# -*- coding: utf-8 mode: python -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8

"""Gestion de la version des produits installés.

Pour le moment, seule la version de python est gérée.
"""

__all__ = ('get_version', 'check_version',
           'VersionMismatchError', 'ensure_version',
           )

import sys, re

PYTHON = 'python'
RE_SEP = re.compile(r'\.')

def __unknown_product(product):
    return ValueError("unknown product: %s" % product)

R_MAP = {'alpha': 'a', 'beta': 'b', 'candidate': 'rc', 'final': ''}

def get_version(product=PYTHON):
    if product == PYTHON:
        a, b, c = sys.version_info[:3]
        r = sys.version_info[3]; r = R_MAP.get(r, r)
        s = sys.version_info[4]
        if not r: s = s or ''
        return '%i.%i.%i%s%s' % (a, b, c, r, s)
    else:
        raise __unknown_product(product)

_PYTHON_VERSION_CACHE = {}
def check_version(version, product=PYTHON):
    """Vérifier la version minimum de product.

    Pour le moment, product ne peut valoir que 'python'. version est une chaine
    de la forme "x[.y...]".

    La version majeure doit correspondre. Les versions mineures doivent être
    supérieure ou égales à la version donnée.
    """
    if product == PYTHON:
        check = _PYTHON_VERSION_CACHE.get(version, None)
        if check is None:
            expected = tuple(map(int, RE_SEP.split(version)))
            actual = tuple(sys.version_info[:len(expected)])
            check = actual[0:1] == expected[0:1] and actual[1:] >= expected[1:]
            _PYTHON_VERSION_CACHE[version] = check
        return check
    else:
        raise __unknown_product(product)

class VersionMismatchError(Exception):
    pass

def ensure_version(version, product=PYTHON):
    if not check_version(version, product):
        raise VersionMismatchError("Expected %s %s, got %s" % (product, version, get_version(product)))
