cgilsxml.py: ajout de l'option -E. bug avec le tri sur des valeurs inexistantes

This commit is contained in:
Jephté Clain 2016-02-09 11:25:33 +04:00
parent f115b98d44
commit 788e1ff0c0
1 changed files with 55 additions and 24 deletions

View File

@ -34,14 +34,19 @@ RE_SORT_FIELD_TYPE = re.compile(r'([_a-zA-Z][-_a-zA-Z0-9]*)(?::([aAdDcCnN]+))?')
class Filter:
re_spec = None
re_allows = None
ex_vars = None
ex_group = None
def __init__(self, re_spec):
self.re_spec = re.compile(re_spec)
self.re_allows = []
self.ex_vars = []
self.ex_group = None
def allow_spec(self, re_allow):
self.re_allows.append(re.compile(re_allow))
def add_var(self, ex_var):
mo = RE_VAR_NAME_EXPR.match(ex_var)
if mo is None: raise ValueError('Invalid VAR_EXPR: %s' % ex_var)
@ -52,7 +57,8 @@ class Filter:
self.ex_group = ex_group
def __repr__(self):
return 'Filter<%s,%s,%s>' % (self.re_spec, repr(self.ex_vars), self.ex_group)
return 'Filter<%s,%s,%s,%s>' % (self.re_spec, repr(self.re_allows),
repr(self.ex_vars), self.ex_group)
def match_fill(self, file):
mo = self.re_spec.match(file.name)
@ -67,17 +73,25 @@ class Filter:
file.group = group
return True
def match_allow(self, file):
for re_allow in self.re_allows:
if re_allow.match(file.name) is not None:
return True
return False
class File:
pf = None
group = None
vars = None
dontlist = None
def __init__(self, dir, name):
def __init__(self, dir, name, dontlist=False):
dir = path.abspath(dir)
pf = path.join(dir, name)
self.__dict__['pf'] = pf
self.__dict__['group'] = None
self.__dict__['vars'] = {}
self.__dict__['dontlist'] = dontlist
stat = os.stat(pf)
mtime = int(stat.st_mtime)
@ -97,12 +111,12 @@ class File:
def __getitem__(self, name): return self.vars[name]
def __setitem__(self, name, value): self.vars[name] = value
def has_key(self, name): return self.vars.has_key(name)
def __getattr__(self, name): return self.vars[name]
def __getattr__(self, name):
try: return self.vars[name]
except KeyError: raise AttributeError(name)
def __setattr__(self, name, value):
if self.__dict__.has_key(name):
self.__dict__[name] = value
else:
self.vars[name] = value
if self.__dict__.has_key(name): self.__dict__[name] = value
else: self.vars[name] = value
def __repr__(self): return 'File<%s>' % (self.pf)
def find_files(basedir, filters):
@ -111,9 +125,13 @@ def find_files(basedir, filters):
file = File(basedir, name)
if not file.isfile(): continue
matched = False
allowed = False
for filter in filters:
matched = filter.match_fill(file) or matched
if not matched: continue
allowed = filter.match_allow(file) or allowed
if matched: pass
elif allowed: file.dontlist = True
else: continue
files.append(file)
return files
@ -134,17 +152,23 @@ def build_sortfunc(sortby):
SORTS.append((field, method, order))
def sortfunc(a, b):
for field, method, order in SORTS:
av = getattr(a, field)
bv = getattr(b, field)
if method == 'C':
av = str(av)
bv = str(bv)
elif method == 'N':
av = int(av)
bv = int(bv)
if av < bv: outcome = -1
elif av > bv: outcome = 1
else: outcome = 0
av = getattr(a, field, None)
bv = getattr(b, field, None)
if av is None:
if bv is None: outcome = 0
else: outcome = 1
elif bv is None:
outcome = -1
else:
if method == 'C':
av = str(av)
bv = str(bv)
elif method == 'N':
av = int(av)
bv = int(bv)
if av < bv: outcome = -1
elif av > bv: outcome = 1
else: outcome = 0
if order == 'A': pass
elif order == 'D': outcome = -outcome
if outcome != 0: return outcome
@ -165,8 +189,9 @@ def build_fgroups(files):
return fgroups
def filter_files(files, group):
if group: return filter(lambda file: file.group == group, files)
else: return filter(lambda file: not file.group, files)
if group: func = lambda file: file.dontlist or file.group == group
else: func = lambda file: file.dontlist or not file.group
return filter(func, files)
def select_file(files, name):
matches = filter(lambda file: file.name == name, files)
@ -241,6 +266,7 @@ def print_files(files, fgroups=None, select_group=None, script_name=None, xslt=N
xfgroup.set('selected', 'selected')
xfiles = ET.SubElement(xresult, "files")
for file in files:
if file.dontlist: continue
xfile = ET.SubElement(xfiles, "file")
if file.group is not None: xfile.set('group', file.group)
for name, value in file.vars.items():
@ -256,6 +282,9 @@ def run_cgilsxml():
def add_spec(option, opt, value, parser, *args, **kw):
if env['filter'] is not None: env['filters'].append(env['filter'])
env['filter'] = Filter(value)
def allow_spec(option, opt, value, parser, *args, **kw):
if env['filter'] is None: env['filter'] = default_filter
env['filter'].allow_spec(value)
def add_var(option, opt_str, value, parser, *args, **kw):
if env['filter'] is None: env['filter'] = default_filter
env['filter'].add_var(value)
@ -265,14 +294,16 @@ def run_cgilsxml():
from optparse import OptionParser
OP = OptionParser(usage=u"\n\t%prog [options] /path/to/dir", description=__doc__)
OP.add_option('-e', '--spec', dest='spec', action='callback', callback=add_spec, type="string",
OP.add_option('-e', '--spec', dest='spec', action='callback', callback=add_spec, type='string',
help=u"Spécifier l'expression régulière permettant de sélectionner les fichiers à lister. L'expression régulière peut définir des groupes qui sont utilisées pour l'extraction des variables."
+ u"\n Il est possible de spécifier cette option plusieurs fois."
+ u"\n Note: TOUTES les expressions régulières sont testées par rapport au nom du fichier, et pour celles qui correspondent, les variables correspondantes sont définies. Il faut donc ordonner les expressions régulières de la plus générale à la plus spécifique, contrairement à ce qui se fait d'habitude.")
OP.add_option('-v', '--var', dest='var', action='callback', callback=add_var, type="string",
OP.add_option('-E', '--allow-spec', dest='spec', action='callback', callback=allow_spec, type='string',
help=u"Ajouter une spécification de fichier qui peut être demandé avec --cgi-path-info. Ces fichiers ne sont pas inclus dans la liste.")
OP.add_option('-v', '--var', dest='var', action='callback', callback=add_var, type='string',
help=u"Définir la variable NAME à la valeur de l'expression VAR_EXPR. Dans cette expression, il est possible d'utiliser des expressions de la forme %%(var)s pour inclure des variables déjà définies, ou \\N et \\g<NAME> pour inclure respective le groupe numéro N et le groupe nommé NAME de l'expression régulière --spec."
+ u"\n Cette option peut être spécifiée plusieurs fois. Elle s'applique à l'expression régulière définie par la dernière option --spec")
OP.add_option('-g', '--group', dest='group', action='callback', callback=set_group, type="string",
OP.add_option('-g', '--group', dest='group', action='callback', callback=set_group, type='string',
help=u"Spécifier l'expression qui permet de construire des ensembles de fichiers sur la base des groupes définis dans l'expression régulière de l'option --spec. Dans cette expression, il est possible d'utiliser des expressions de la forme %%(var)s pour inclure des variables déjà définies, ou \\N ou \\g<NAME> pour inclure respective le groupe numéro N et le groupe nommé NAME de l'expression régulière --spec."
+ u"\n Cette option ne peut être spécifiée qu'une seule fois par option --spec")
OP.add_option('-s', '--sort', dest='sortby',