#!/usr/bin/env python
# -*- coding: utf-8 -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8

u"""%(scriptname)s: Afficher la dernière version d'un ensemble de fichiers
USAGE
    %(scriptname)s [/path/to/]basename
OPTIONS
    -r  Inverser le rôle de cet utilitaire: afficher toutes les versions des
        fichiers plutôt que la dernière
    -s suffix
        Ajouter suffix à la liste des suffixes qui doivent être enlevés au nom
        de fichier avant de trouver la version.
    -n  Ne pas utiliser une liste de suffixes par défaut qui convient pour les
        fichiers d'archives et d'export:
        (war, jar, ear, zip, tar[.gz|.bz2], t[gz|bz2], sql, ldif)
    -f INPUT-FILE
        Au lieu de lister les fichiers, prendre la liste dans INPUT-FILE. -f -
        signifie lire sur stdin."""

import os, sys, re
from os import path
from glob import glob

from ulib.all import *

SUFFIXES = (".war", ".jar", ".ear", ".zip", ".gz", ".bz2", ".tar", ".tgz", ".tbz2",
            ".sql", ".ldif",
            )
def strip_suffixes(p, suffixes=SUFFIXES):
    suffix_striped = True
    while suffix_striped:
        suffix_striped = False
        for suffix in suffixes:
            if p.endswith(suffix):
                p = p[:len(p) - len(suffix)]
                suffix_striped = True
    return p

RE_ARCHIVE = re.compile(r'(?i)\.(war|jar|ear|zip|tar|tar\.gz|tgz|tar\.bz2|tbz2)$')
def is_archive(p):
    return RE_ARCHIVE.search(p) is not None
def strip_archive_ext(p):
    mo = RE_ARCHIVE.search(p)
    if mo is not None:
        p = p[:mo.start(0)]
    return p

RE_PATH_VERSION = re.compile(r'(?i)(?:-|_|\.)' # préfixe: - ou .
                             r'(\d+(?:(-|_|\.)\d+(?:\2\d+)*)?)' # version
                             r'(?:(a|alpha|b|beta|rc)(\d*))?' # type
                             r'$' #
                             )
RE_NUMBERS = re.compile(r'\d+')
TYPE_MAPPINGS = {'a': 'alpha', 'b': 'beta'}
TYPES = ['alpha', 'beta', None, 'rc']
def has_version(p):
    return RE_PATH_VERSION.search(p) is not None
def get_version(p):
    mo = RE_PATH_VERSION.search(p)
    if mo is None: return None, None, None
    else:
        vns = map(int, RE_NUMBERS.findall(mo.group(1)))
        type = mo.group(3)
        if type is not None: type = type.lower()
        type = TYPE_MAPPINGS.get(type, type)
        n = mo.group(4)
        if n is not None: n = int(n)
        return vns, type, n
def strip_version(p):
    mo = RE_PATH_VERSION.search(p)
    if mo is not None:
        p = p[:mo.start(0)]
    return p

class PathVersion:
    def __init__(self, suffixes=SUFFIXES):
        self.suffixes = suffixes

    def cmp(self, p0, p1):
        p0 = strip_suffixes(p0, self.suffixes)
        p1 = strip_suffixes(p1, self.suffixes)

        vns0, type0, n0 = get_version(p0)
        vns1, type1, n1 = get_version(p1)

        c = cmp(vns0, vns1)
        if c == 0: c = cmp(TYPES.index(type0), TYPES.index(type1))
        if c == 0: c = cmp(n0, n1)
        return c

def display_help():
    uprint(__doc__ % globals())

def run_plver():
    all = False
    reverse = False
    suffixes = list(SUFFIXES)
    inf = None

    opts, argv = get_args(None, 'arns:f:',
                          ['help', 'all', 'reverse', 'no-suffixes', 'suffix=', 'file='])
    for opt, value in opts:
        if opt in ('--help', ):
            display_help()
            sys.exit(0)
        elif opt in ('-a', '--all'):
            all = True
        elif opt in ('-r', '--reverse'):
            reverse = True
        elif opt in ('-n', '--no-suffixes'):
            suffixes = []
        elif opt in ('-s', '--suffix'):
            suffixes.append(value)
        elif opt in ('-f', '--file'):
            inf = value
            if inf == '-': inf = sys.stdin

    basenames = {}
    if inf is None:
        # Generer une liste de fichiers en ne gardant que les fichiers archive qui
        # ont un numero de version. Classer ces fichiers par noms de base
        if not argv: argv = ['*']
        for arg in argv:
            if path.isdir(arg): arg += '/'
            if not arg.endswith('*'): arg += '*'

            for p in glob(arg):
                n = strip_suffixes(p, suffixes)
                s = p[len(n):]

                if has_version(n):
                    b = strip_version(n) + s
                    if b not in basenames:
                        basenames[b] = []
                    basenames[b].append(p)
    else:
        lines = Lines()
        for p in lines.readlines(inf):
            n = strip_suffixes(p, suffixes)
            s = p[len(n):]

            if has_version(n):
                b = strip_version(n) + s
                if b not in basenames:
                    basenames[b] = []
                basenames[b].append(p)

    # Pour chacun des noms de base, classer la liste et retourner la(les)
    # version(s) demandée(s)
    pv = PathVersion(suffixes)
    for basename, paths in basenames.items():
        if all:
            paths.sort(pv.cmp, reverse=reverse)
            for p in paths:
                print p
        else:
            paths.sort(pv.cmp, reverse=True)
            if reverse:
                for p in paths[1:]:
                    print p
            else:
                print paths[0]

if __name__ == '__main__':
    run_plver()
