2013-08-27 15:14:44 +04:00
|
|
|
#!/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)
|
2015-08-20 07:58:17 +04:00
|
|
|
|
2013-08-27 15:14:44 +04:00
|
|
|
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
|
2015-08-20 07:58:17 +04:00
|
|
|
|
2013-08-27 15:14:44 +04:00
|
|
|
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()
|