Intégration de la branche release-2.21.0

This commit is contained in:
Jephté Clain 2015-12-07 15:12:53 +04:00
commit 2831e43a54
9 changed files with 523 additions and 47 deletions

View File

@ -1,3 +1,13 @@
## Version 2.21.0 du 07/12/2015-15:12
d7b468d cgilsxml: ajouter les variables dlname, size, Y, m, d, H, M, S. maj doc
eac94a7 cgiupload: possibilité de filtrer sur le nom du fichier ou son type de contenu
fae2111 ajout de cgilsxml
26fe709 apacheconfig: -S peut aussi être utilisé avec --localhosts
7c6ad6a apacheconfig: nouvelles options pour le développement
c2d5eab pxs fait aussi git pull avec un dépôt sans annexe
dca7bee pxs fonctionne pour les dépôt normaux comme pci -A
## Version 2.20.0 du 12/11/2015-15:41
16d95d2 apache_autoconf(): déploiement des certificats autorité

View File

@ -1 +1 @@
2.20.0
2.21.0

View File

@ -47,7 +47,22 @@ OPTIONS
Les arguments qui restent sont passés tels quels à apache_autoconf
-r, --certsdir CERTSDIR
Spécifier le cas échéant le répertoire contenant les certificats à
déployer. Cet argument est requis si le répertoire certsconf/ existe."
déployer. Cet argument est requis si le répertoire certsconf/ existe.
--localhosts
Créer dans le fichier /etc/hosts tous les noms d'hôte ayant un suffixe
.local mentionnés dans les fichiers de site. Cette option est utile pour
le développement et les tests.
-C, --one-conf CONF
Ne déployer que le fichier de configuration spécifié. Cette option est
utilisée avec --deploy et est utile pour le développement et les tests.
-M, --one-module MODULE
Ne déployer que le fichier de module spécifié. Cette option est utilisée
avec --deploy et est utile pour le développement et les tests.
-S, --one-site SITE
Ne déployer que le fichier de site spécifié. Cette option est utilisée
avec --deploy ou --localhosts et est utile pour le développement et les
tests."
}
# toujours placer une variable dépendante AVANT la variable maitre
@ -139,6 +154,9 @@ destdir=
nohideconfig=
templateopt=
aac_certsdir=
oneconf=
onemodule=
onesite=
args=(
--help '$exit_with display_help'
-c,--create action=create
@ -160,6 +178,10 @@ args=(
-8,--jessie '$array_add TEMPLATECTL_VARS sysver=jessie'
-u,--update,--deploy action=deploy
-r:,--certsdir: aac_certsdir=
--localhosts action=localhosts
-C:,--one-conf: oneconf=
-M:,--one-module: onemodule=
-S:,--one-site: onesite=
)
parse_args "$@"; set -- "${args[@]}"
@ -218,21 +240,39 @@ $__TEMPLATECTL_HELP"
templatectl -d "$destdir" --config "$config" --no-load-vars ${templateopt:+-$templateopt} "$@"
################################################################################
elif [ "$action" == deploy ]; then
elif [ "$action" == deploy -o "$action" == localhosts ]; then
[ -d "$destdir" ] || die "$destdir: répertoire introuvable"
args=(-d "$destdir" --deploy ${aac_certsdir:+-r "$aac_certsdir"})
args=(
-d "$destdir" --$action ${aac_certsdir:+-r "$aac_certsdir"}
${oneconf:+--one-conf "$oneconf"}
${onemodule:+--one-module "$onemodule"}
${onesite:+--one-site "$onesite"}
)
for __name in "${TEMPLATE_DYNAMIC_VARS[@]}"; do
array_add args -v "$__name=${!__name}"
done
array_add args -- "$@"
run_as_root "${args[@]}"
etitle "Mise à jour du système"
args=("$destdir" "$aac_certsdir")
if [ "$action" == deploy ]; then
etitle "Mise à jour du système"
args=(apache_autoconf
--ignore "$(basename -- "$config")"
${oneconf:+--one-conf "$(basename -- "$oneconf")"}
${onemodule:+--one-module "$(basename -- "$onemodule")"}
)
elif [ "$action" == localhosts ]; then
etitle "Mise à jour de /etc/hosts"
args=(apache_autoconf_localhosts)
fi
args=("${args[@]}"
"$destdir" "$aac_certsdir"
${onesite:+--one-site "$(basename -- "$onesite")"}
)
for __name in "${TEMPLATE_DYNAMIC_VARS[@]}"; do
array_add args "$__name=${!__name}"
done
apache_autoconf --ignore "$(basename -- "$config")" "${args[@]}" "$@" || die
"${args[@]}" "$@" || die
eend
fi

View File

@ -1 +1 @@
009007000
009008000

View File

@ -155,6 +155,27 @@ OPTIONS
return 0
}
function __apache_autoconf_setup() {
if ! check_sysinfos -s linux -d debian; then
eerror "apache_autoconf n'est supporté que sur Debian linux"
return 1
fi
urequire install
compute_apache_prefixes
return 0
}
function __apache_autoconf_fillxxx() {
local var name value first=1
for var in "$@"; do
splitvar "$var" name value
array_addu FILLVARS "$name"
[ -n "$first" ] || FILLSCRIPT="$FILLSCRIPT"$'\n'
FILLSCRIPT="${FILLSCRIPT}s/@@${name}@@/$(qseds "${value}")/g"
first=
done
# Il faut un fichier temporaire pour les remplacement de fichiers
ac_set_tmpfile FILLTEMP
}
function __apache_autoconf_fillcopy() {
# copier le fichier $1 vers le fichier $2. Si le fichier $1 contient l'une
# des variables du tableau $FILLVARS, corriger d'abord le fichier avec le
@ -186,14 +207,14 @@ __APACHE_AUTOCONF_HELP="\
fichiers 'confs.conf', 'modules.conf' et 'sites.conf'. Par défaut, prendre
le répertoire local DESTDIR.
--confsdir CONFSDIR
Spécifier l'emplacement des fichiers de configuration des configuration. Par
défaut, utiliser DESTDIR/confs si ce répertoire existe.
Spécifier l'emplacement des fichiers des configuration. Par défaut, utiliser
DESTDIR/confs si ce répertoire existe.
--modulesdir MODULESDIR
Spécifier l'emplacement des fichiers de configuration des modules. Par
défaut, utiliser DESTDIR/modules si ce répertoire existe.
Spécifier l'emplacement des fichiers des modules. Par défaut, utiliser
DESTDIR/modules si ce répertoire existe.
--sitesdir SITESDIR
Spécifier l'emplacement des fichiers de configuration des sites. Par défaut,
utiliser DESTDIR/sites si ce répertoire existe.
Spécifier l'emplacement des fichiers des sites. Par défaut, utiliser
DESTDIR/sites si ce répertoire existe.
--cgibindir CGIBINDIR
Spécifier l'emplacement des scripts cgi à installer. Par défaut, utiliser
DESTDIR/cgi-bin si ce répertoire existe.
@ -213,15 +234,19 @@ function __display_apache_autoconf_help() { eecho "$__APACHE_AUTOCONF_HELP"; }
function apache_autoconf() {
eval "$(utools_local)"
local -a ignores
local autoconfdir certsdir confdir confsdir modulesdir sitesdir cgibindir wwwdir certsconfdir rrdir
local autoconfdir certsdir confdir confsdir oneconf modulesdir onemodule
local sitesdir onesite cgibindir wwwdir certsconfdir rrdir onecms
local restart=1
parse_opts "${PRETTYOPTS[@]}" \
--help '$exit_with __display_apache_autoconf_help' \
--ignore: ignores \
--confdir: confdir= \
--confsdir: confsdir= \
--one-conf: oneconf= \
--modulesdir: modulesdir= \
--one-module: onemodule= \
--sitesdir: sitesdir= \
--one-site: onesite= \
--cgibindir: cgibindir= \
--wwwdir: wwwdir= \
--certsconfdir: certsconfdir= \
@ -229,12 +254,7 @@ function apache_autoconf() {
--no-restart restart= \
@ args -- "$@" && set -- "${args[@]}" || die "$args"
if ! check_sysinfos -s linux -d debian; then
eerror "apache_autoconf n'est supporté que sur Debian linux"
return 1
fi
urequire install
compute_apache_prefixes
__apache_autoconf_setup || return 1
# Configuration
autoconfdir="$1"; shift
@ -259,20 +279,12 @@ function apache_autoconf() {
[ -n "$wwwdir" ] || wwwdir="$autoconfdir/www"
[ -n "$certsconfdir" ] || certsconfdir="$autoconfdir/certsconf"
[ -n "$rrdir" ] || rrdir="$autoconfdir/RewriteRules"
[ -n "$oneconf" -o -n "$onemodule" -o -n "$onesite" ] && onecms=1
# Faire un script sed pour remplacer les variables spécifiées par leur
# valeur dans les fichiers
local -a FILLVARS; local FILLSCRIPT FILLTEMP
local var name value first=1
for var in "$@"; do
splitvar "$var" name value
array_addu FILLVARS "$name"
[ -n "$first" ] || FILLSCRIPT="$FILLSCRIPT"$'\n'
FILLSCRIPT="${FILLSCRIPT}s/@@${name}@@/$(qseds "${value}")/g"
first=
done
# Il faut un fichier temporaire pour les remplacement de fichiers
ac_set_tmpfile FILLTEMP
__apache_autoconf_fillxxx
# Copie des certificats
local modified rehash conf
@ -308,12 +320,14 @@ function apache_autoconf() {
fi
# Gestion des configurations
if [ -d "$confsdir" ]; then
if [ -d "$confsdir" -a \( -z "$onecms" -o "$oneconf" \) ]; then
local -a confs
local conf
etitle "Installation des configurations"
array_from_lines confs "$(list_files "$confsdir" "*.conf")"
for conf in "${confs[@]}"; do
[ -z "$oneconf" -o "$conf" == "$oneconf" ] || continue
estep "$conf"
__apache_autoconf_fillcopy \
"$confsdir/$conf" \
@ -323,12 +337,14 @@ function apache_autoconf() {
fi
# Gestion des modules
if [ -d "$modulesdir" ]; then
if [ -d "$modulesdir" -a \( -z "$onecms" -o "$onemodule" \) ]; then
local -a confs
local conf
etitle "Installation des configurations des modules"
array_from_lines confs "$(list_files "$modulesdir" "*.conf")"
for conf in "${confs[@]}"; do
[ -z "$onemodule" -o "$conf" == "$onemodule" ] || continue
estep "$conf"
__apache_autoconf_fillcopy \
"$modulesdir/$conf" \
@ -338,7 +354,7 @@ function apache_autoconf() {
fi
# Règles de réécriture
if [ -d "$rrdir" ]; then
if [ -d "$rrdir" -a -z "$onecms" ]; then
local -a confs
local conf
etitle "Installation des règles de réécriture"
@ -354,18 +370,19 @@ function apache_autoconf() {
# Sites
local -a enablesites disablesites
if [ -d "$sitesdir" ]; then
if [ -d "$sitesdir" -a \( -z "$onecms" -o "$onesite" \) ]; then
local -a confs
local conf confname destconf certsconf
etitle "Installation des sites"
array_lsfiles confs "$sitesdir" "*.conf"
for conf in "${confs[@]}"; do
confname="$(basename "$conf")"
destconf="$confname"
[ -z "$onesite" -o "$confname" == "$onesite" ] || continue
certsconf=
if [ "${destconf%.ssl.conf}" != "$destconf" ]; then
if [ "${confname%.ssl.conf}" != "$confname" ]; then
if [ -d "$certsconfdir" ]; then
certsconf="${destconf%.ssl.conf}-certs.conf"
certsconf="${confname%.ssl.conf}-certs.conf"
else
ewarn "$conf: fichier ignoré parce que --certsconfdir n'a pas été spécifié"
fi
@ -373,6 +390,7 @@ function apache_autoconf() {
case "$destconf" in
default.conf) destconf=default;;
default.ssl.conf) destconf=default-ssl;;
*) destconf="$confname";;
esac
if [ -n "$certsconf" ]; then
@ -401,7 +419,7 @@ s#@@ca@@#$APACHESSLCERTSDIR/$(basename "$ca")#g
fi
# Fichiers de configuration
if [ -d "$confdir" ]; then
if [ -d "$confdir" -a -z "$onecms" ]; then
local -a confs
local conf
etitle "Configuration de base"
@ -474,14 +492,14 @@ s#@@ca@@#$APACHESSLCERTSDIR/$(basename "$ca")#g
fi
# Scripts CGI
if [ -d "$cgibindir" ]; then
if [ -d "$cgibindir" -a -z "$onecms" ]; then
etitle "Installation des scripts CGI"
cpdirnovcs "$cgibindir" "$CGIBINDIR"
eend
fi
# Contenu web
if [ -d "$wwwdir" ]; then
if [ -d "$wwwdir" -a -z "$onecms" ]; then
etitle "Installation des fichiers du serveur web"
cpdirnovcs "$wwwdir" "$HTDOCSDIR"
eend
@ -512,3 +530,62 @@ s#@@ca@@#$APACHESSLCERTSDIR/$(basename "$ca")#g
fi
fi
}
function apache_autoconf_localhosts() {
eval "$(utools_local)"
local autoconfdir sitesdir onesite
parse_opts "${PRETTYOPTS[@]}" \
--sitesdir: sitesdir= \
--one-site: onesite= \
@ args -- "$@" && set -- "${args[@]}" || die "$args"
__apache_autoconf_setup || return 1
# Configuration
autoconfdir="$1"; shift
[ -n "$autoconfdir" ] || {
eerror "Vous devez spécifier le répertoire de base de la configuration apache"
return 1
}
[ -n "$sitesdir" ] || sitesdir="$autoconfdir/sites"
# Faire un script sed pour remplacer les variables spécifiées par leur
# valeur dans les fichiers
local -a FILLVARS; local FILLSCRIPT FILLTEMP ULIB_INSTALL_VERBOSE
__apache_autoconf_fillxxx
local -a newhosts
if [ -d "$sitesdir" ]; then
local -a localips localhosts confs candidates newhosts
local conf tmpconf candidate
array_from_lines localips "$(</etc/hosts awk '$1 ~ /127\./ { print $1 }' | sort -u)"
array_from_lines localhosts "$(</etc/hosts awk '$1 ~ /127\./ { for (i = 2; i <= NF; i++) { if ($i ~ /\.local$/) print $i } }' | sort -u)"
ac_set_tmpfile tmpconf
array_lsfiles confs "$sitesdir" "*.conf"
for conf in "${confs[@]}"; do
confname="$(basename "$conf")"
[ -z "$onesite" -o "$confname" == "$onesite" ] || continue
__apache_autoconf_fillcopy "$conf" "$tmpconf"
array_from_lines candidates "$(<"$tmpconf" awk '
$1 == "ServerName" && $2 ~ /\.local$/ { print $2 }
$1 == "ServerAlias" { for (i = 2; i <= NF; i++) { if ($i ~ /\.local$/) print $i } }
')"
for candidate in "${candidates[@]}"; do
array_contains localhosts "$candidate" || array_addu newhosts "$candidate"
done
done
fi
local ip host i=0
for host in "${newhosts[@]}"; do
i=$(($i + 1)); ip="127.0.1.$i"
while array_contains localips "$ip"; do
i=$(($i + 1)); ip="127.0.1.$i"
done
estep "Ajout de $ip $host"
echo "$ip $host" >>/etc/hosts
done
}

8
lib/ulib/cgilsxml Normal file
View File

@ -0,0 +1,8 @@
##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
## Fonction de support pour cgilsxml
##@cooked nocomments
##@require ulib
uprovide cgilsxml
urequire ulib
function cgilsxml() { "$ULIBDIR/support/cgilsxml.py" "$@"; }

305
lib/ulib/support/cgilsxml.py Executable file
View File

@ -0,0 +1,305 @@
#!/usr/bin/env python
# -*- coding: utf-8 mode: python -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
u"""Ce script est prévu pour être utilisé dans un script CGI.
Il permet de lister le contenu d'un répertoire au format XML, et de télécharger les fichiers trouvés.
"""
import os, sys, re, shutil, mimetypes
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):
if type(u) not in StringTypes: u = unicode(str(u), 'utf-8', 'strict')
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
ex_vars = None
ex_group = None
def __init__(self, re_spec):
self.re_spec = re.compile(re_spec)
self.ex_vars = []
self.ex_group = None
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
def __repr__(self):
return 'Filter<%s,%s,%s>' % (self.re_spec, repr(self.ex_vars), self.ex_group)
def match_fill(self, file):
mo = self.re_spec.match(file.name)
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
file.group = group
return True
class File:
pf = None
group = None
vars = None
def __init__(self, dir, name):
dir = path.abspath(dir)
pf = path.join(dir, name)
self.__dict__['pf'] = pf
self.__dict__['group'] = None
self.__dict__['vars'] = {}
stat = os.stat(pf)
mtime = int(stat.st_mtime)
self.dir = dir
self.name = name
self.dlname = name
self.size = stat.st_size
self.mtime = mtime
self.date = datef(DATE_DATEF, mtime)
self.time = datef(TIME_DATEF, mtime)
self.Y, self.m, self.d, self.H, self.M, self.S = datef('%Y %m %d %H %M %S', mtime).split(' ')
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
def has_key(self, name): return self.vars.has_key(name)
def __getattr__(self, name): return self.vars[name]
def __setattr__(self, 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):
files = []
for name in os.listdir(basedir):
file = File(basedir, name)
if not file.isfile(): continue
matched = False
for filter in filters:
matched = filter.match_fill(file) or matched
if not matched: continue
files.append(file)
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:
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
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):
if group: return filter(lambda file: file.group == group, files)
else: return filter(lambda file: not file.group, files)
def select_file(files, name):
matches = filter(lambda file: file.name == name, files)
if matches: return matches[0]
else: return None
def print_files(files, fgroups=None, select_group=None, script_name=None, query_string=None, xslt=None):
xresult = ET.Element("result")
xenv = ET.SubElement(xresult, "env")
if script_name is not None:
ET.SubElement(xenv, "script_name").text = _u(script_name)
if query_string is not None:
ET.SubElement(xenv, "query_string").text = _u(query_string)
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')
xfiles = ET.SubElement(xresult, "files")
for file in files:
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)
sys.stdout.write('<?xml version="1.0" encoding="UTF-8"?>\n')
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():
default_filter = Filter(r'(.*)')
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 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)
from optparse import OptionParser
OP = OptionParser(usage=u"\n\t%prog [options] /path/to/dir", description=__doc__)
OP.add_option('-t', '--xslt', dest='xslt',
help=u"Ajouter le chemin vers la feuille de style XSLT dans le flux XML généré")
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.\nIl est possible de spécifier cette option plusieurs fois.\nNote: 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",
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.\nCette 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",
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.\nCette option ne peut être spécifiée qu'une seule fois par option --spec")
OP.add_option('-s', '--sort', dest='sortby',
help=u"Spécifier le champ sur lequel trier ainsi que le type de tri à utiliser. 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. Si un champ est spécifié mais que le type de tri ne l'est pas, la valeur par défaut est AC. Si cette option n'est pas spécifiée, le tri par défaut est 'mtime:DN'.\nIl est possible de spécifier plusieurs champs pour le tri en les séparant par des virgules.")
OP.add_option('--cgi', dest='cgi_mode', action='store_true',
help=u"Activer le mode CGI. Ce mode est automatiquement activé si la variable d'environnement REQUEST_METHOD existe.")
OP.add_option('--cgi-path-info', dest='path_info',
help=u"Spécifier un chemin d'un fichier à télécharger. En mode CGI, cette valeur est prise dans la variable d'environnement PATH_INFO")
OP.add_option('--cgi-script-name', dest='script_name',
help=u"Spécifier la valeur de SCRIPT_NAME pour provisionner l'environnement du fichier résultat. En mode CGI, cette valeur est prise dans la variable d'environnement du même nom.")
OP.add_option('--cgi-query-string', dest='query_string',
help=u"Spécifier la valeur de QUERY_STRING pour provisionner l'environnement du fichier résultat. En mode CGI, cette valeur est prise dans la variable d'environnement du même nom.")
OP.add_option('--cgi-param-group', dest='select_group',
help=u"Sélectionner le groupe spécifié. Seuls les fichiers du groupe sont affichés. En mode CGI, cette option est automatiquement activée si QUERY_STRING contient le paramètre group=GROUP.\nNote: pour le calcul de cette valeur, l'API cgi.FieldStorage() est utilisé, ce qui fait que la valeur éventuellement fournie par l'option --cgi-query-string est ignorée.")
env = dict(filters=[], filter=None)
o, args = OP.parse_args()
filters = env['filters']
filter = env['filter']
xslt, sortby, cgi_mode = o.xslt, o.sortby, o.cgi_mode
cgi_path_info = o.path_info
cgi_script_name = o.script_name
cgi_query_string = o.query_string
cgi_select_group = o.select_group
environ = os.environ
if cgi_mode is None: cgi_mode = 'REQUEST_METHOD' in environ
if cgi_mode:
import cgi
form = cgi.FieldStorage()
if 'group' in form and cgi_select_group is None:
cgi_select_group = form.getfirst("group")
if cgi_path_info is None and 'PATH_INFO' in environ :
cgi_path_info = environ.get('PATH_INFO')
if cgi_script_name is None and 'SCRIPT_NAME' in environ :
cgi_script_name = environ.get('SCRIPT_NAME')
if cgi_query_string is None and 'QUERY_STRING' in environ :
cgi_query_string = environ.get('QUERY_STRING')
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
# complète, mais requérir la sélection d'un groupe
cgi_select_group = ''
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:
print "Content-Type: text/plain; charset=UTF-8"
print
print "Impossible de trouver le fichier %s" % cgi_path_info
else:
if cgi_mode:
dlname = file.dlname or file.name
ctype = file.has_key('type') and file.type or None
if ctype is None: ctype, encoding = mimetypes.guess_type(dlname, False)
if ctype is None: ctype = "application/octet-stream"
print "Content-Type: %s; charset=utf-8" % ctype
print "Content-Disposition: attachment; filename=\"%s\"" % dlname
print
inf = open(file.pf, 'rb')
try: shutil.copyfileobj(inf, sys.stdout)
finally: inf.close()
sys.exit()
if cgi_mode:
print "Content-Type: text/xml; charset=UTF-8"
print
print_files(files, fgroups, cgi_select_group, cgi_script_name, cgi_query_string, xslt)
if __name__ == '__main__':
run_cgilsxml()

View File

@ -3,30 +3,49 @@
u"""Ce script est prévu pour être utilisé dans un script CGI.
Il enregistre les fichiers uploadés dans le répertoire spécifié, et éventuellement lance une commande avec comme argument les fichiers enregistrés.
Retourner 0 si tous les fichiers ont été traités, 1 si au moins un fichier a été rejeté, 2 si aucun fichier ne correspondait (ou si aucun fichier n'a été fourni)
"""
import sys, os, types, cgi, tempfile
import sys, os, re, types, cgi, tempfile
from os import path
cgitb = None # marqueur pour savoir si le module cgitb a été importé
#import cgitb; cgitb.enable()
class FileManager(object):
def __init__(self, destdir=None, parse_env=True):
fileinfos = None
tries = None
count = None
destdir = None
spec = None
type = None
exitcode = None
def __init__(self, destdir=None, spec=None, type=None, parse_env=True):
if destdir is None: destdir = '/tmp'
self.fileinfos = []
self.tries = 0
self.count = 0
self.destdir = destdir
if spec is not None: spec = re.compile(spec)
self.spec = spec
self.type = type
if parse_env: self.parse_env()
def parse_env(self):
class FieldStorage(cgi.FieldStorage):
def make_file(self, binary=None):
return self.fm._new_file(self)
outf = self.fm._new_file(self)
if outf is not None: return outf
return cgi.FieldStorage.make_file(self, binary)
FieldStorage.fm = self
self.form = FieldStorage()
def _new_file(self, form):
self.tries += 1
if self.spec is not None and self.spec.match(form.filename) is None: return None
if self.type is not None and self.type != form.type: return None
fp = path.join(self.destdir, 'upload%i' % self.count)
outf = open(fp, 'w+b')
self.count += 1
@ -45,11 +64,20 @@ class FileManager(object):
finally:
if close: outf.close()
def exitcode(self):
if self.count == 0: return 2
elif self.count != self.tries: return 1
else: return 0
# Analyser les options
from optparse import OptionParser
parser = OptionParser(usage=u"\n\t%prog [options]\n\t%prog [options] -c command [args]", description=__doc__)
parser.add_option('-d', '--destdir', dest='destdir',
help=u"Spécifier le répertoire de destination des fichiers uploadés. Ce répertoire est créé si nécessaire.")
parser.add_option('-e', '--spec', dest='spec',
help=u"N'accepter que des fichiers dont le nom correspond à l'expression régulière spécifiée")
parser.add_option('-t', '--type', dest='type',
help=u"N'accepter que des fichiers dont le type mime correspond à la valeur spécifiée")
parser.add_option('-p', '--printcsv', action='store_true', dest='printcsv',
help=u"Afficher la liste des fichiers uploadés au format CSV. Chaque ligne est de la forme 'name,value,file,type' où name est le nom du champ dans le formulaire http, value le nom du fichier tel qu'il a été fourni par le client, file le chemin complet vers le fichier uploadé, et type le type mime du contenu.")
parser.add_option('-c', '--cmd', action='store_true', dest='cmd',
@ -84,7 +112,7 @@ if o.printcsv is None and o.cmd is None:
if o.cmd and o.clear is None:
o.clear = True
fm = FileManager(o.destdir)
fm = FileManager(o.destdir, o.spec, o.type)
if o.printcsv:
fm.write_csv(sys.stdout)
@ -112,3 +140,5 @@ if o.clear:
for fi in fm.fileinfos:
try: os.remove(fi[0])
except: pass
sys.exit(fm.exitcode())

View File

@ -78,11 +78,15 @@ COMMANDS
xadd
xunlock
xdrop
xsync
xwhereis
xwebapp
Chacune de ces commandes est un raccourci vers la commande
correspondante de git annex, sans le préfixe 'x'
xsync
Sur un dépot où git-annex est activé, lancer 'git annex sync' si on est
en mode indirect ou 'git annex sync --content' si on est en mode direct.
Sur un dépôt où git-annex n'est pas activé, faire l'équivalent des
commandes 'git add -A && git commit && git pull && git push'
xcopy
xmove
xget
@ -237,7 +241,9 @@ elif array_contains VCS_CMDS "$CMD"; then
elif array_contains GITANNEX_CMDS "$CMD"; then
function xsync() {
if is_yes "$(git config --get annex.direct)"; then
if ! git_have_annex; then
git_commit -Al "Maj des fichiers" && git pull && git_push
elif is_yes "$(git config --get annex.direct)"; then
git annex add &&
git annex sync &&
git annex sync --content &&