2015-12-07 12:26:37 +04:00
#!/usr/bin/env python
# -*- coding: utf-8 mode: python -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
2015-12-07 14:59:20 +04:00
u """ Ce script est prévu pour être utilisé dans un script CGI.
2015-12-07 12:26:37 +04:00
Il permet de lister le contenu d ' un répertoire au format XML, et de télécharger les fichiers trouvés.
"""
2016-06-10 03:57:07 +04:00
import os , sys , re , shutil , mimetypes , urlparse , urllib , fnmatch , glob
2015-12-07 12:26:37 +04:00
from os import path
from time import time , localtime
from types import UnicodeType , StringTypes
import xml . etree . ElementTree as ET
# _u() et datef() sont des fonctions de pyulib, recopiées ici pour ne pas devoir
# dépendre d'une librairie extérieure
def _u ( u ) :
2016-06-10 01:34:38 +04:00
if u is None : return None
elif type ( u ) not in StringTypes : u = unicode ( str ( u ) , ' utf-8 ' , ' strict ' )
2015-12-07 12:26:37 +04:00
elif type ( u ) is not UnicodeType : u = unicode ( u , ' utf-8 ' , ' strict ' )
return u
DATEF_MAP = { ' % Y ' : ' %(y)04i ' , ' % m ' : ' %(m)02i ' , ' %d ' : ' %(d)02i ' , ' % H ' : ' %(H)02i ' , ' % M ' : ' %(M)02i ' , ' % S ' : ' %(S)02i ' }
DATE_DATEF = ' %d / % m/ % Y '
TIME_DATEF = ' % H: % M: % S '
def datef ( format = None , t = None ) :
if format is None : format = DATE_DATEF
if t is None : t = time ( )
y , m , d , H , M , S , W , J , dst = localtime ( t )
for fr , to in DATEF_MAP . items ( ) : format = format . replace ( fr , to )
return format % locals ( )
RE_COMMA = re . compile ( r ' \ s*, \ s* ' )
RE_VAR_NAME_EXPR = re . compile ( r ' ([_a-zA-Z][-_a-zA-Z0-9]*)=(.*) ' )
RE_SORT_FIELD_TYPE = re . compile ( r ' ([_a-zA-Z][-_a-zA-Z0-9]*)(?::([aAdDcCnN]+))? ' )
class Filter :
re_spec = None
2016-06-10 03:57:07 +04:00
glob = None
caret_anchor = None
deep_scan = None
2016-02-09 11:25:33 +04:00
re_allows = None
2015-12-07 12:26:37 +04:00
ex_vars = None
ex_group = None
2016-06-08 16:06:23 +04:00
ex_break_on = None
2016-06-10 04:28:01 +04:00
force_disposition = None
force_type = None
force_charset = None
2015-12-07 12:26:37 +04:00
2016-06-10 03:57:07 +04:00
def __init__ ( self , spec = None , glob = None ) :
if spec is not None :
self . re_spec = re . compile ( spec )
self . caret_anchor = spec . startswith ( ' ^ ' )
self . deep_scan = ' / ' in spec
elif glob is not None :
self . glob = glob
self . deep_scan = ' / ' in glob
else : raise ValueError ( " either spec or glob must be specified " )
2016-02-09 11:25:33 +04:00
self . re_allows = [ ]
2015-12-07 12:26:37 +04:00
self . ex_vars = [ ]
self . ex_group = None
2016-06-08 16:06:23 +04:00
self . ex_break_on = None
2015-12-07 12:26:37 +04:00
2016-02-09 11:25:33 +04:00
def allow_spec ( self , re_allow ) :
self . re_allows . append ( re . compile ( re_allow ) )
2015-12-07 12:26:37 +04:00
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 )
name , expr = mo . groups ( )
self . ex_vars . append ( ( name , expr ) )
def set_group ( self , ex_group ) :
self . ex_group = ex_group
2016-06-08 16:06:23 +04:00
def set_break_on ( self , ex_break_on ) :
self . ex_break_on = ex_break_on
2015-12-07 12:26:37 +04:00
def __repr__ ( self ) :
2016-06-10 03:57:07 +04:00
return ' Filter< %s || %s , %s , %s , %s , %s > ' % \
( self . re_spec , self . glob , repr ( self . re_allows ) ,
2016-06-08 16:06:23 +04:00
repr ( self . ex_vars ) ,
self . ex_group , self . ex_break_on ,
)
2015-12-07 12:26:37 +04:00
2016-06-10 03:57:07 +04:00
def match_fill ( self , file , basedir = None ) :
if self . glob :
if self . deep_scan :
# la correspondance a déjà été faite avant avec glob.glob(). on
# se contente d'initialiser l'objet
pass
elif not fnmatch . fnmatch ( file . name , self . glob ) :
return None
file . group = None
file . break_on = None
2016-06-10 04:28:01 +04:00
if self . force_disposition : file . content_disposition = self . force_disposition
if self . force_type : file . content_type = self . force_type
if self . force_charset : file . content_charset = self . force_charset
2016-06-10 03:57:07 +04:00
return True
if self . deep_scan :
pf = file . pf
if not self . caret_anchor :
blen = len ( basedir )
if pf [ : blen ] != basedir : return None
pf = pf [ blen : ]
if not pf . startswith ( ' / ' ) : return None
pf = pf [ 1 : ]
mo = self . re_spec . match ( pf )
else : mo = self . re_spec . match ( file . name )
2015-12-07 12:26:37 +04:00
if mo is None : return None
for name , expr in self . ex_vars :
value = mo . expand ( expr )
if ' % ' in value : value = value % file . vars
file [ name ] = value
if self . ex_group is not None :
group = mo . expand ( self . ex_group )
if ' % ' in group : group = group % file . vars
2016-06-08 16:06:23 +04:00
else :
group = None
file . group = group
if self . ex_break_on is not None :
break_on = mo . expand ( self . ex_break_on )
if ' % ' in break_on : break_on = break_on % file . vars
else :
break_on = None
file . break_on = break_on
2016-06-10 04:28:01 +04:00
if self . force_disposition : file . content_disposition = self . force_disposition
if self . force_type : file . content_type = self . force_type
if self . force_charset : file . content_charset = self . force_charset
2015-12-07 12:26:37 +04:00
return True
2016-02-09 11:25:33 +04:00
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
2015-12-07 12:26:37 +04:00
class File :
pf = None
group = None
vars = None
2016-02-09 11:25:33 +04:00
dontlist = None
2015-12-07 12:26:37 +04:00
2016-06-10 03:57:07 +04:00
def __init__ ( self , dir = None , name = None , pf = None , dontlist = False ) :
if pf is None :
2016-08-09 09:42:00 +04:00
if dir is None or name is None : raise ValueError ( " either (dir,name) or pf must be specified " )
2016-06-10 03:57:07 +04:00
pf = path . join ( dir , name )
dir , name = path . split ( pf ) # il est possible que name soit de la forme subdir/name
2015-12-07 12:26:37 +04:00
dir = path . abspath ( dir )
pf = path . join ( dir , name )
self . __dict__ [ ' pf ' ] = pf
self . __dict__ [ ' group ' ] = None
self . __dict__ [ ' vars ' ] = { }
2016-02-09 11:25:33 +04:00
self . __dict__ [ ' dontlist ' ] = dontlist
2015-12-07 12:26:37 +04:00
stat = os . stat ( pf )
mtime = int ( stat . st_mtime )
self . dir = dir
self . name = name
2015-12-07 14:59:20 +04:00
self . dlname = name
self . size = stat . st_size
2015-12-07 12:26:37 +04:00
self . mtime = mtime
self . date = datef ( DATE_DATEF , mtime )
self . time = datef ( TIME_DATEF , mtime )
2015-12-07 14:59:20 +04:00
self . Y , self . m , self . d , self . H , self . M , self . S = datef ( ' % Y % m %d % H % M % S ' , mtime ) . split ( ' ' )
2015-12-07 12:26:37 +04:00
def isfile ( self ) :
return path . isfile ( self . pf )
def __getitem__ ( self , name ) : return self . vars [ name ]
def __setitem__ ( self , name , value ) : self . vars [ name ] = value
2015-12-07 14:59:20 +04:00
def has_key ( self , name ) : return self . vars . has_key ( name )
2016-02-09 11:25:33 +04:00
def __getattr__ ( self , name ) :
try : return self . vars [ name ]
except KeyError : raise AttributeError ( name )
2015-12-07 12:26:37 +04:00
def __setattr__ ( self , name , value ) :
2016-02-09 11:25:33 +04:00
if self . __dict__ . has_key ( name ) : self . __dict__ [ name ] = value
else : self . vars [ name ] = value
2015-12-07 12:26:37 +04:00
def __repr__ ( self ) : return ' File< %s > ' % ( self . pf )
def find_files ( basedir , filters ) :
2016-06-10 03:57:07 +04:00
basedir = path . abspath ( basedir )
2015-12-07 12:26:37 +04:00
files = [ ]
2016-06-10 03:57:07 +04:00
deep_filters = [ filter for filter in filters if filter . re_spec is not None and filter . deep_scan ]
if deep_filters :
for dirpath , dirnames , filenames in os . walk ( basedir ) :
for filename in filenames :
2016-08-09 09:42:00 +04:00
# race condition: si le fichier disparait entre-temps, une
# exception se produit
try : file = File ( dirpath , filename )
except : continue
2016-06-10 03:57:07 +04:00
matched = False
allowed = False
for filter in deep_filters :
matched = filter . match_fill ( file , basedir ) or matched
allowed = filter . match_allow ( file ) or allowed
if matched : pass
elif allowed : file . dontlist = True
else : continue
files . append ( file )
simple_filters = [ filter for filter in filters if filter . re_spec is not None and not filter . deep_scan ]
if simple_filters :
for name in os . listdir ( basedir ) :
2016-08-09 09:42:00 +04:00
# race condition: si le fichier disparait entre-temps, une
# exception se produit
try : file = File ( basedir , name )
except : continue
2016-06-10 03:57:07 +04:00
if not file . isfile ( ) : continue
matched = False
allowed = False
for filter in simple_filters :
matched = filter . match_fill ( file ) or matched
allowed = filter . match_allow ( file ) or allowed
if matched : pass
elif allowed : file . dontlist = True
else : continue
files . append ( file )
glob_filters = [ filter for filter in filters if filter . glob is not None ]
if glob_filters :
for filter in glob_filters :
2016-08-09 09:42:00 +04:00
candidates = [ ]
2016-06-10 03:57:07 +04:00
if filter . deep_scan :
2016-08-09 09:42:00 +04:00
for pf in glob . glob ( path . join ( basedir , filter . glob ) ) :
# race condition: si le fichier disparait entre-temps, une
# exception se produit
try : file = File ( pf = pf )
except : continue
candidates . append ( file )
2016-06-10 03:57:07 +04:00
else :
2016-08-09 09:42:00 +04:00
for name in os . listdir ( basedir ) :
# race condition: si le fichier disparait entre-temps, une
# exception se produit
try : file = File ( basedir , name )
except : continue
candidates . append ( file )
2016-06-10 03:57:07 +04:00
for file in candidates :
if not file . isfile ( ) : continue
elif filter . match_fill ( file ) : pass
elif filter . match_allow ( file ) : file . dontlist = True
else : continue
files . append ( file )
2015-12-07 12:26:37 +04:00
return files
def build_sortfunc ( sortby ) :
SORTS = [ ]
for term in RE_COMMA . split ( sortby . strip ( ) ) :
mo = RE_SORT_FIELD_TYPE . match ( term )
if mo is None : raise ValueError ( ' Invalid SORT_EXPR: %s ' % term )
field , type = mo . groups ( )
if type is None : type = ' '
type = type . upper ( )
if ' A ' in type : order = ' A '
elif ' D ' in type : order = ' D '
else : order = ' A '
if ' C ' in type : method = ' C '
elif ' N ' in type : method = ' N '
else : method = ' C '
SORTS . append ( ( field , method , order ) )
def sortfunc ( a , b ) :
for field , method , order in SORTS :
2016-02-09 11:25:33 +04:00
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
2015-12-07 12:26:37 +04:00
if order == ' A ' : pass
elif order == ' D ' : outcome = - outcome
if outcome != 0 : return outcome
return 0
return sortfunc
def sort_files ( files , sortfunc ) :
files . sort ( sortfunc )
return files
def build_fgroups ( files ) :
fgroups = set ( )
for file in files :
if file . group is not None :
fgroups . add ( file . group )
fgroups = list ( fgroups )
fgroups . sort ( )
return fgroups
def filter_files ( files , group ) :
2016-02-09 11:25:33 +04:00
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 )
2015-12-07 12:26:37 +04:00
def select_file ( files , name ) :
matches = filter ( lambda file : file . name == name , files )
if matches : return matches [ 0 ]
else : return None
2015-12-24 11:14:57 +04:00
def cgi_nocache ( ) :
print " Cache-Control: private, no-cache, no-store, must-revalidate, max-age=0 "
print " Pragma: no-cache "
print " Expires: Thu, 01 Jan 1970 00:00:00 GMT "
2016-02-07 23:03:38 +04:00
RE_COMMA = re . compile ( ' , ' )
def lfix ( values ) :
if values is None : return None
fvalues = [ ]
for parts in values :
parts = RE_COMMA . split ( parts )
fvalues . extend ( parts )
return fvalues
def filter_query_string ( query_string , includes = None , excludes = None , prefix = None ) :
params = urlparse . parse_qsl ( query_string , keep_blank_values = True )
includes = lfix ( includes )
if includes is None : names = dict ( params ) . keys ( )
else : names = includes [ : ]
excludes = lfix ( excludes )
if excludes is not None :
for name in excludes :
if name in names : names . remove ( name )
params = [ ( name , value ) for ( name , value ) in params if name in names ]
query_string = urllib . urlencode ( params )
if prefix :
if query_string != " " : query_string = " %s & %s " % ( prefix , query_string )
elif prefix != " " : query_string = prefix
return query_string
def print_files ( files , fgroups = None , select_group = None , script_name = None , xslt = None ,
query_string = None , includes = None , excludes = None , prefix = None ) :
2015-12-07 12:26:37 +04:00
xresult = ET . Element ( " result " )
xenv = ET . SubElement ( xresult , " env " )
if script_name is not None :
ET . SubElement ( xenv , " script_name " ) . text = _u ( script_name )
2016-02-04 13:52:09 +04:00
ET . SubElement ( xenv , " script_base " ) . text = _u ( re . sub ( r ' [^/]+$ ' , ' ' , script_name ) )
2016-06-09 16:29:24 +04:00
orig_query_string = query_string
if orig_query_string is not None :
query_string = orig_query_string
2016-06-10 01:34:38 +04:00
params = [ ]
if query_string is not None :
params = urlparse . parse_qsl ( query_string , keep_blank_values = True )
query_string = _u ( query_string )
fquery_string = orig_query_string
fparams = [ ]
if fquery_string is not None :
fquery_string = filter_query_string ( fquery_string , includes , excludes , prefix )
fparams = urlparse . parse_qsl ( fquery_string , keep_blank_values = True )
fquery_string = _u ( fquery_string )
2016-06-09 16:29:24 +04:00
2016-02-07 23:03:38 +04:00
if includes or excludes or prefix :
xorig = ET . SubElement ( xenv , " orig " )
2016-02-08 09:34:02 +04:00
if query_string :
ET . SubElement ( xorig , " query_string " ) . text = u ' ? %s ' % query_string
ET . SubElement ( xorig , " squery_string " ) . text = u ' & %s ' % query_string
2016-02-07 23:03:38 +04:00
xvars = ET . SubElement ( xorig , " query_vars " )
for name , value in params :
ET . SubElement ( xvars , name ) . text = value
query_string = fquery_string
params = fparams
2016-06-09 16:29:24 +04:00
2016-02-08 09:34:02 +04:00
if query_string :
ET . SubElement ( xenv , " query_string " ) . text = u ' ? %s ' % query_string
ET . SubElement ( xenv , " squery_string " ) . text = u ' & %s ' % query_string
2016-06-09 16:29:24 +04:00
2015-12-24 12:16:57 +04:00
xvars = ET . SubElement ( xenv , " query_vars " )
2016-02-07 23:03:38 +04:00
for name , value in params :
ET . SubElement ( xvars , name ) . text = value
2016-06-09 16:29:24 +04:00
2015-12-07 12:26:37 +04:00
xfgroups = ET . SubElement ( xresult , " fgroups " )
if fgroups is not None :
for fgroup in fgroups :
xfgroup = ET . SubElement ( xfgroups , ' fgroup ' )
xfgroup . text = _u ( fgroup )
if fgroup == select_group :
xfgroup . set ( ' selected ' , ' selected ' )
2016-06-09 16:29:24 +04:00
2015-12-07 12:26:37 +04:00
xfiles = ET . SubElement ( xresult , " files " )
2016-06-08 16:06:23 +04:00
first = True
last_classifier = ( None , None )
2015-12-07 12:26:37 +04:00
for file in files :
2016-02-09 11:25:33 +04:00
if file . dontlist : continue
2016-06-08 16:06:23 +04:00
current_classifier = ( file . group , file . break_on )
2016-06-10 01:34:38 +04:00
if first or current_classifier != last_classifier :
file . break_here = None
2016-06-08 16:06:23 +04:00
last_classifier = current_classifier
first = False
2015-12-07 12:26:37 +04:00
xfile = ET . SubElement ( xfiles , " file " )
if file . group is not None : xfile . set ( ' group ' , file . group )
for name , value in file . vars . items ( ) :
ET . SubElement ( xfile , name ) . text = _u ( value )
2016-06-08 15:05:41 +04:00
sys . stdout . write ( ' <?xml version= " 1.0 " encoding= " utf-8 " ?> \n ' )
2015-12-07 12:26:37 +04:00
if xslt is not None :
sys . stdout . write ( ' <?xml-stylesheet version= " 1.0 " type= " text/xsl " href= " %s " ?> \n ' % xslt )
ET . ElementTree ( xresult ) . write ( sys . stdout , " utf-8 " )
def run_cgilsxml ( ) :
2016-06-10 04:28:01 +04:00
class ContentInfos :
disposition = ' attachment '
type = None
charset = ' utf-8 '
default_content = ContentInfos ( )
2015-12-07 12:26:37 +04:00
default_filter = Filter ( r ' (.*) ' )
def add_spec ( option , opt , value , parser , * args , * * kw ) :
if env [ ' filter ' ] is not None : env [ ' filters ' ] . append ( env [ ' filter ' ] )
2016-06-10 03:57:07 +04:00
env [ ' filter ' ] = Filter ( spec = value )
def add_glob ( option , opt , value , parser , * args , * * kw ) :
if env [ ' filter ' ] is not None : env [ ' filters ' ] . append ( env [ ' filter ' ] )
env [ ' filter ' ] = Filter ( glob = value )
2016-02-09 11:25:33 +04:00
def allow_spec ( option , opt , value , parser , * args , * * kw ) :
if env [ ' filter ' ] is None : env [ ' filter ' ] = default_filter
env [ ' filter ' ] . allow_spec ( value )
2015-12-07 12:26:37 +04:00
def add_var ( option , opt_str , value , parser , * args , * * kw ) :
if env [ ' filter ' ] is None : env [ ' filter ' ] = default_filter
env [ ' filter ' ] . add_var ( value )
def set_group ( option , opt_str , value , parser , * args , * * kw ) :
if env [ ' filter ' ] is None : env [ ' filter ' ] = default_filter
env [ ' filter ' ] . set_group ( value )
2016-06-08 16:06:23 +04:00
def set_break_on ( option , opt_str , value , parser , * args , * * kw ) :
if env [ ' filter ' ] is None : env [ ' filter ' ] = default_filter
env [ ' filter ' ] . set_break_on ( value )
2016-06-10 04:28:01 +04:00
def set_content_disposition ( option , opt_str , value , parser , * args , * * kw ) :
if value in ( ' attachment ' , ' inline ' ) : pass
elif value == ' none ' : value = None
else :
if cgi_mode :
if not cgi_cache : cgi_nocache ( )
print " Content-Type: text/plain; charset=utf-8 "
print
print " %s : Disposition de contenu invalide. Ce soit être attachment, inline ou none " % cgi_content_disposition
sys . exit ( 1 )
if env [ ' filter ' ] is None : default_content . disposition = value
else : env [ ' filter ' ] . force_disposition = value
def set_content_type ( option , opt_str , value , parser , * args , * * kw ) :
if env [ ' filter ' ] is None : default_content . type = value
else : env [ ' filter ' ] . force_type = value
def set_content_charset ( option , opt_str , value , parser , * args , * * kw ) :
if env [ ' filter ' ] is None : default_content . charset = value
else : env [ ' filter ' ] . force_charset = value
2015-12-07 12:26:37 +04:00
from optparse import OptionParser
OP = OptionParser ( usage = u " \n \t % prog [options] /path/to/dir " , description = __doc__ )
2016-02-09 11:25:33 +04:00
OP . add_option ( ' -e ' , ' --spec ' , dest = ' spec ' , action = ' callback ' , callback = add_spec , type = ' string ' ,
2016-06-10 03:57:07 +04:00
help = u " Spécifier l ' expression régulière permettant de sélectionner les fichiers à lister. "
+ u " La correspondance est tentée sur le nom du fichier avec la fonction match(). "
+ u " Penser à inclure l ' ancre $ pour matcher le nom entier du fichier. "
+ u " Si l ' expression régulière contient un caractère ' / ' , la correspondance peut se faire sur le chemin complet du fichier. "
+ u " Pour simplifier, par défaut seule la partie située après le chemin de base est matchée, sauf si l ' expression commence par ' ^ ' , auquel cas la correspondance se fait sur le chemin complet du fichier. "
+ u " L ' expression régulière peut définir des groupes qui sont utilisées pour l ' extraction des variables. "
2015-12-15 10:05:45 +04:00
+ u " \n Il est possible de spécifier cette option plusieurs fois. "
2016-06-10 03:57:07 +04:00
+ 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. "
+ u " 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 ( ' --glob ' , dest = ' pattern ' , action = ' callback ' , callback = add_glob , type = ' string ' ,
help = u " Comme --spec, mais en utilisant les patterns du shell *, ?, [seq], [!seq]. "
+ u " Si l ' expression contient un caractère ' / ' , la correspondance se fait sur le chemin complet du fichier avec le module glob. "
+ u " Cette précision est importante notamment pour la recherche de fichiers dont le nom commence par un point. "
+ u " Si l ' expression ne contient pas le caractère ' / ' , la correspondance est faite uniquement sur le nom de fichier avec le module fnmatch, et le point n ' a plus de signification particulière. "
+ u " Cette méthode de correspondance ne permet pas de définir des groupes et ne permet donc pas d ' extraire des variables. " )
2016-02-09 11:25:33 +04:00
OP . add_option ( ' -E ' , ' --allow-spec ' , dest = ' spec ' , action = ' callback ' , callback = allow_spec , type = ' string ' ,
2016-06-10 04:28:01 +04:00
help = u " Ajouter une spécification de fichier qui peut être demandé avec --cgi-path-info. "
+ u " Ces fichiers ne sont pas inclus dans la liste. " )
2016-02-09 11:25:33 +04:00
OP . add_option ( ' -v ' , ' --var ' , dest = ' var ' , action = ' callback ' , callback = add_var , type = ' string ' ,
2016-06-10 04:28:01 +04:00
help = u " Définir la variable NAME à la valeur de l ' expression VAR_EXPR. "
+ u " 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 respectivement 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. "
+ u " Elle s ' applique à l ' expression régulière définie par la dernière option --spec " )
2016-02-09 11:25:33 +04:00
OP . add_option ( ' -g ' , ' --group ' , dest = ' group ' , action = ' callback ' , callback = set_group , type = ' string ' ,
2016-06-10 04:28:01 +04:00
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. "
+ u " 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 respectivement le groupe numéro N et le groupe nommé NAME de l ' expression régulière --spec. "
2016-06-08 16:06:23 +04:00
+ u " \n Cette option ne peut être spécifiée qu ' une seule fois par option --spec " )
OP . add_option ( ' -b ' , ' --break-on ' , dest = ' break_on ' , action = ' callback ' , callback = set_break_on , type = ' string ' ,
2016-06-10 04:28:01 +04:00
help = u " Spécifier une expression qui permet de partitionner la list des fichiers au sein d ' un même groupe. "
+ u " 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 respectivement le groupe numéro N et le groupe nommé NAME de l ' expression régulière --spec. "
2016-06-08 16:06:23 +04:00
+ u " \n Bien que ce ne soit pas une obligation, il est logique de trier la liste sur cette expression pour que les groupes de fichiers soient ensembles dans la liste. "
2015-12-15 10:05:45 +04:00
+ u " \n Cette option ne peut être spécifiée qu ' une seule fois par option --spec " )
2015-12-07 12:26:37 +04:00
OP . add_option ( ' -s ' , ' --sort ' , dest = ' sortby ' ,
2016-06-10 04:28:01 +04:00
help = u " Spécifier le champ sur lequel trier ainsi que le type de tri à utiliser. "
+ u " SORT_EXPR est de la forme FIELD:TYPE où FIELD est le nom du champ et TYPE est le type de tri: A, D, C et/ou N pour (A)scendant, (D)escendant, (C)haine, (N)numérique. "
+ u " Si un champ est spécifié mais que le type de tri ne l ' est pas, la valeur par défaut est AC. "
+ u " Si cette option n ' est pas spécifiée, le tri par défaut est ' mtime:DN ' . "
2015-12-15 10:05:45 +04:00
+ u " \n Il est possible de spécifier plusieurs champs pour le tri en les séparant par des virgules. " )
2015-12-07 12:26:37 +04:00
OP . add_option ( ' --cgi ' , dest = ' cgi_mode ' , action = ' store_true ' ,
2016-06-10 04:28:01 +04:00
help = u " Activer le mode CGI. "
+ u " Ce mode est automatiquement activé si la variable d ' environnement REQUEST_METHOD existe. " )
2015-12-24 11:14:57 +04:00
OP . add_option ( ' --cgi-allow-cache ' , dest = ' cgi_allow_cache ' , action = ' store_true ' ,
help = u " En mode CGI, ne pas rajouter les en-tête désactivant la mise en cache du résultat. " )
2016-06-10 04:28:01 +04:00
OP . add_option ( ' --cgi-content-disposition ' , ' --cgicd ' , dest = ' content-disposition ' , action = ' callback ' , callback = set_content_disposition , type = ' string ' ,
help = u " En mode CGI, forcer la disposition de contenu avec lequel servir le fichier. "
+ u " Les valeurs valides sont attachment (par défaut), inline, none. "
+ u " Si cette option est spécifiée après une option --spec ou --glob, elle ne s ' applique qu ' aux fichiers qui correspondent à ce modèle " )
OP . add_option ( ' --cgi-content-type ' , ' --cgict ' , dest = ' content-type ' , action = ' callback ' , callback = set_content_type , type = ' string ' ,
help = u " En mode CGI, forcer le type de contenu avec lequel servir le fichier. "
+ u " Si cette option est spécifiée après une option --spec ou --glob, elle ne s ' applique qu ' aux fichiers qui correspondent à ce modèle " )
OP . add_option ( ' --cgi-content-charset ' , ' --cgicc ' , dest = ' content-charset ' , action = ' callback ' , callback = set_content_charset , type = ' string ' ,
help = u " En mode CGI, forcer l ' encoding de contenu avec lequel servir le fichier. "
+ u " Si cette option est spécifiée après une option --spec ou --glob, elle ne s ' applique qu ' aux fichiers qui correspondent à ce modèle " )
2015-12-15 10:05:45 +04:00
OP . add_option ( ' -P ' , ' --cgi-path-info ' , dest = ' path_info ' ,
2016-06-10 04:28:01 +04:00
help = u " Spécifier un chemin d ' un fichier à télécharger. "
+ u " En mode CGI, cette valeur est prise dans la variable d ' environnement PATH_INFO " )
2015-12-15 10:05:45 +04:00
OP . add_option ( ' -Q ' , ' --cgi-query-string ' , dest = ' query_string ' ,
2016-06-10 04:28:01 +04:00
help = u " Spécifier la valeur de QUERY_STRING pour provisionner l ' environnement du fichier résultat. "
+ u " En mode CGI, cette valeur est prise dans la variable d ' environnement QUERY_STRING. " )
2015-12-15 10:05:45 +04:00
OP . add_option ( ' -N ' , ' --cgi-script-name ' , dest = ' script_name ' ,
2016-06-10 04:28:01 +04:00
help = u " Spécifier la valeur de SCRIPT_NAME pour provisionner l ' environnement du fichier résultat. "
+ u " En mode CGI, cette option est automatiquement activée si QUERY_STRING contient le paramètre script_name=SCRIPT_NAME, la valeur par défaut étant la valeur de la variable d ' environnement SCRIPT_NAME. "
2015-12-15 10:05:45 +04:00
+ u " \n L ' ordre de priorité pour le calcul de cette valeur est: d ' abord le paramètre script_name dans QUERY_STRING, puis l ' option de la ligne de commande, enfin la valeur de la variable d ' environnement " )
OP . add_option ( ' -G ' , ' --cgi-param-group ' , dest = ' select_group ' ,
2016-06-10 04:28:01 +04:00
help = u " Sélectionner le groupe spécifié. "
+ u " Seuls les fichiers du groupe sont affichés. "
+ u " En mode CGI, cette option est automatiquement activée si QUERY_STRING contient le paramètre group=GROUP. "
2015-12-15 11:01:27 +04:00
+ u " \n S ' il n ' y a qu ' un seul groupe, il est automatiquement sélectionné. "
2015-12-15 10:05:45 +04:00
+ u " \n L ' ordre de priorité pour le calcul de cette valeur est: d ' abord le paramètre group dans QUERY_STRING, puis l ' option de la ligne de commande " )
OP . add_option ( ' -t ' , ' --cgi-param-xslt ' , dest = ' xslt ' ,
2016-06-10 04:28:01 +04:00
help = u " Ajouter le chemin vers la feuille de style XSLT dans le flux XML généré. "
+ u " En mode CGI, cette option est automatiquement activée si QUERY_STRING contient le paramètre xslt=XSLT. "
2015-12-15 10:05:45 +04:00
+ u " \n L ' ordre de priorité pour le calcul de cette valeur est: d ' abord le paramètre xslt dans QUERY_STRING, puis l ' option de la ligne de commande " )
2016-02-07 23:03:38 +04:00
OP . add_option ( ' -i ' , ' --include ' , dest = ' includes ' , action = ' append ' ,
2016-06-10 04:28:01 +04:00
help = u " Spécifier un paramètre à inclure pour construire la valeur du chemin xpath /result/env/query_string dans le résultat. "
+ u " Il est possible de spécifier plusieurs paramètres en les séparant par des virgules. "
+ u " Par défaut, prendre tous les paramètres de la requête. " )
2016-02-07 23:03:38 +04:00
OP . add_option ( ' -x ' , ' --exclude ' , dest = ' excludes ' , action = ' append ' ,
2016-06-10 04:28:01 +04:00
help = u " Spécifier un paramètre à exclure pour construire la valeur du chemin xpath /result/env/query_string dans le résultat. "
+ u " Il est possible de spécifier plusieurs paramètres en les séparant par des virgules. " )
2016-02-07 23:03:38 +04:00
OP . add_option ( ' -p ' , ' --prefix ' , dest = " prefix " ,
help = u " Ajouter les paramètres supplémentaires spécifiés à /result/env/query_string. " )
2015-12-07 12:26:37 +04:00
env = dict ( filters = [ ] , filter = None )
o , args = OP . parse_args ( )
filters = env [ ' filters ' ]
filter = env [ ' filter ' ]
2015-12-15 10:05:45 +04:00
sortby = o . sortby
2015-12-07 12:26:37 +04:00
environ = os . environ
2015-12-15 10:05:45 +04:00
cgi_mode = o . cgi_mode
2016-06-08 15:05:41 +04:00
cgi_cache = o . cgi_allow_cache and True or False
2016-02-07 23:03:38 +04:00
cgi_query_string = o . query_string
if cgi_query_string is not None : environ [ ' QUERY_STRING ' ] = cgi_query_string
2015-12-15 10:05:45 +04:00
if cgi_mode is None :
cgi_mode = ' REQUEST_METHOD ' in environ
2015-12-07 12:26:37 +04:00
if cgi_mode :
2015-12-15 10:05:45 +04:00
import cgi ; form = cgi . FieldStorage ( )
cgi_path_info = o . path_info
if cgi_path_info is None and ' PATH_INFO ' in environ : cgi_path_info = environ . get ( ' PATH_INFO ' )
2016-02-07 23:03:38 +04:00
if cgi_query_string is None and ' QUERY_STRING ' in environ : cgi_query_string = environ . get ( ' QUERY_STRING ' )
2015-12-15 10:05:45 +04:00
cgi_script_name = None
if ' script_name ' in form and cgi_script_name is None : cgi_script_name = form . getfirst ( " script_name " )
if cgi_script_name is None : cgi_script_name = o . script_name
if cgi_script_name is None and ' SCRIPT_NAME ' in environ : cgi_script_name = environ . get ( ' SCRIPT_NAME ' )
cgi_select_group = None
if ' group ' in form and cgi_select_group is None : cgi_select_group = form . getfirst ( " group " )
if cgi_select_group is None : cgi_select_group = o . select_group
cgi_xslt = None
if ' xslt ' in form and cgi_xslt is None : cgi_xslt = form . getfirst ( " xslt " )
if cgi_xslt is None : cgi_xslt = o . xslt
else :
cgi_path_info = o . path_info
cgi_query_string = o . query_string
cgi_script_name = o . script_name
cgi_select_group = o . select_group
cgi_xslt = o . xslt
2015-12-07 12:26:37 +04:00
if cgi_path_info is not None : cgi_path_info = path . split ( cgi_path_info ) [ 1 ]
if filter is not None : filters . append ( filter )
if filter is None and not filters : filters . append ( default_filter )
if len ( args ) == 0 : args = [ ' . ' ]
if sortby is None : sortby = ' mtime:DN '
files = [ ]
for basedir in args :
files . extend ( find_files ( basedir , filters ) )
sortfunc = build_sortfunc ( sortby )
files = sort_files ( files , sortfunc )
fgroups = build_fgroups ( files )
if cgi_mode and fgroups and cgi_select_group is None :
# En mode CGI, s'il y a plusieurs groupes, ne pas afficher la liste
2015-12-15 11:01:27 +04:00
# complète, mais requérir la sélection d'un groupe, sauf s'il n'y a
# qu'une seul groupe défini
if len ( fgroups ) == 1 : cgi_select_group = fgroups [ 0 ]
else : cgi_select_group = ' '
2015-12-07 12:26:37 +04:00
if cgi_select_group is not None :
files = filter_files ( files , cgi_select_group )
if cgi_path_info :
file = select_file ( files , cgi_path_info )
if file is None :
if cgi_mode :
2015-12-24 11:14:57 +04:00
if not cgi_cache : cgi_nocache ( )
2016-06-08 15:05:41 +04:00
print " Content-Type: text/plain; charset=utf-8 "
2015-12-07 12:26:37 +04:00
print
print " Impossible de trouver le fichier %s " % cgi_path_info
2016-06-08 15:05:41 +04:00
sys . exit ( 1 )
2015-12-07 12:26:37 +04:00
else :
if cgi_mode :
2015-12-24 11:14:57 +04:00
if not cgi_cache : cgi_nocache ( )
2015-12-07 14:59:20 +04:00
dlname = file . dlname or file . name
2016-06-10 04:28:01 +04:00
if file . has_key ( ' content_disposition ' ) : content_disposition = file . content_disposition
else : content_disposition = default_content . disposition
if file . has_key ( ' content_type ' ) : content_type = file . content_type
else : content_type = default_content . type
if content_type is None : content_type , encoding = mimetypes . guess_type ( dlname , False )
if content_type is None : content_type = " application/octet-stream "
if file . has_key ( ' content_charset ' ) : content_charset = file . content_charset
else : content_charset = default_content . charset
print " Content-Type: %s ; charset= %s " % ( content_type , content_charset )
if content_disposition is not None :
print " Content-Disposition: %s ; filename= \" %s \" " % ( content_disposition , dlname )
2015-12-07 12:26:37 +04:00
print
inf = open ( file . pf , ' rb ' )
try : shutil . copyfileobj ( inf , sys . stdout )
finally : inf . close ( )
2016-06-08 15:05:41 +04:00
sys . exit ( 0 )
2015-12-07 12:26:37 +04:00
if cgi_mode :
2015-12-24 11:14:57 +04:00
if not cgi_cache : cgi_nocache ( )
2016-06-08 15:05:41 +04:00
print " Content-Type: text/xml; charset=utf-8 "
2015-12-07 12:26:37 +04:00
print
2016-02-07 23:03:38 +04:00
print_files ( files , fgroups , cgi_select_group , cgi_script_name , cgi_xslt ,
cgi_query_string , o . includes , o . excludes , o . prefix )
2015-12-07 12:26:37 +04:00
if __name__ == ' __main__ ' :
run_cgilsxml ( )