716 lines
26 KiB
Python
716 lines
26 KiB
Python
|
#!/usr/bin/env python
|
||
|
# -*- coding: utf-8 -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
||
|
|
||
|
import os, sys, re, string
|
||
|
from os import path
|
||
|
|
||
|
from ulib.all import *
|
||
|
|
||
|
##################################################
|
||
|
# fonctions diverses
|
||
|
|
||
|
verbosity = 1
|
||
|
verbose = 2
|
||
|
normal = 1
|
||
|
quiet = 0
|
||
|
|
||
|
def _print(level, text, min_verbosity=normal):
|
||
|
"""afficher un texte avec un niveau d'indentation, si le niveau de verbosité
|
||
|
est correct.
|
||
|
|
||
|
Retourner 1 si le texte a été affiché, 0 sinon
|
||
|
"""
|
||
|
global verbosity
|
||
|
if verbosity < min_verbosity: return 0
|
||
|
|
||
|
if level < 0: level = 0
|
||
|
print "%s%s" % (" " * level, text)
|
||
|
return 1
|
||
|
|
||
|
debug = 0
|
||
|
|
||
|
def _debug(text):
|
||
|
if debug: print text
|
||
|
|
||
|
def select_files(p, exclude_names=(), exclude_paths=(), basepath=None):
|
||
|
"""Construire récursivement la liste de tous les fichiers à partir du
|
||
|
répertoire p, en excluant les répertoires dont le nom est donné dans
|
||
|
excludes_names, ou dont le chemin relativement à p est donné dans
|
||
|
exclude_paths
|
||
|
|
||
|
Note: on exclue automatiquement les fichiers qui sont 'binaires'
|
||
|
"""
|
||
|
if basepath is None:
|
||
|
return select_files(p, exclude_names, exclude_paths, p)
|
||
|
else:
|
||
|
files = []
|
||
|
for file in os.listdir(p):
|
||
|
if fileext_is_binary(file): continue
|
||
|
|
||
|
pf = path.join(p, file) # chemin absolu
|
||
|
relpf = pf[len(basepath) + 1:] # chemin relativement à basepath. +1 pour le '/'
|
||
|
|
||
|
ignore = 0
|
||
|
for pattern in exclude_names:
|
||
|
if matches_name(pattern, file, p):
|
||
|
ignore = 1
|
||
|
else:
|
||
|
for pattern in exclude_paths:
|
||
|
if matches_name(pattern, relpf, basepath):
|
||
|
ignore = 1
|
||
|
if not ignore:
|
||
|
if path.isdir(pf):
|
||
|
files.extend(select_files(pf, exclude_names, exclude_paths, basepath))
|
||
|
else:
|
||
|
files.append(pf)
|
||
|
return files
|
||
|
|
||
|
##################################################
|
||
|
# Gestion des répertoires d'inclusion
|
||
|
|
||
|
incpaths = None
|
||
|
|
||
|
def init_incpaths(ignore_env=0):
|
||
|
"""Initialiser incpaths, la liste globale des répertoires dans lesquels on
|
||
|
cherche les fichiers d'inclusions.
|
||
|
|
||
|
Lire la valeur de la variable d'environnement UPDATEINCPATH, sauf si on est
|
||
|
dans un répertoire non déployé.
|
||
|
|
||
|
Si on est dans un répertoire non déployé, s'assurer que le répertoire qui
|
||
|
contient ce script est dans incpaths.
|
||
|
"""
|
||
|
global incpaths
|
||
|
if incpaths is None: incpaths = []
|
||
|
|
||
|
if path.isdir(path.join(scriptdir, "test")):
|
||
|
# ignorer UPDATEINCPATH si on est dans le répertoire de test
|
||
|
ignore_env = 1
|
||
|
|
||
|
if not ignore_env:
|
||
|
incpaths = filter(None, string.split(os.environ.get('UPDATEINCPATH', ''), ':'))
|
||
|
else:
|
||
|
if scriptdir not in incpaths:
|
||
|
incpaths.insert(0, scriptdir)
|
||
|
_debug("init_incpaths()\n incpaths=\n %s" % string.join(incpaths, "\n "))
|
||
|
|
||
|
def set_incpaths(p):
|
||
|
"""Soit un répertoire ou une liste de répertoires séparés par ':'
|
||
|
|
||
|
Si p est un répertoire, l'ajouter à la liste des répertoires de recherche.
|
||
|
Si p est une liste de répertoires, remplacer la liste actuelle par cette
|
||
|
nouvelle liste.
|
||
|
"""
|
||
|
global incpaths
|
||
|
if incpaths is None: init_incpaths()
|
||
|
|
||
|
if ':' in p:
|
||
|
incpaths[:] = map(path.abspath, filter(None, string.split(p, ':')))
|
||
|
else:
|
||
|
p = path.abspath(p)
|
||
|
if p not in incpaths:
|
||
|
incpaths.append(p)
|
||
|
_debug("set_incpaths()\n incpaths=\n %s" % string.join(incpaths, "\n "))
|
||
|
|
||
|
def inc_abspath(file, local_incpaths=()):
|
||
|
"""Retourner le chemin absolu vers un fichier.
|
||
|
|
||
|
Si file est un chemin relatif, il est recherché dans incpaths et dans
|
||
|
local_incpaths
|
||
|
"""
|
||
|
file = path.expanduser(path.expandvars(file))
|
||
|
|
||
|
if path.isabs(file): return file
|
||
|
if path.exists(file): return path.abspath(file)
|
||
|
for incpath in incpaths:
|
||
|
pf = path.join(incpath, file)
|
||
|
if path.exists(pf): return pf
|
||
|
else:
|
||
|
for incpath in local_incpaths:
|
||
|
pf = path.join(incpath, file)
|
||
|
if path.exists(pf): return pf
|
||
|
return path.abspath(file)
|
||
|
|
||
|
##################################################
|
||
|
# Gestion des lignes d'inclusion
|
||
|
|
||
|
class InterestingLine:
|
||
|
def __init__(self, c=None):
|
||
|
"""Initialiser l'objet
|
||
|
|
||
|
re_inc matche une ligne d'inclusion repliée
|
||
|
|
||
|
re_start_inc matche une ligne d'inclusion dépliée de type 'start'
|
||
|
|
||
|
re_end_inc match une ligne d'inclusion dépliée de type 'end'
|
||
|
|
||
|
re_require match une ligne d'inclusion de type 'require'
|
||
|
"""
|
||
|
self.re_comments = [
|
||
|
re.compile(r'[ \t]*(?:r|R)(?:e|E)(?:m|M)'),
|
||
|
re.compile(r'[ \t]*##'),
|
||
|
re.compile(r'[ \t]*;;'),
|
||
|
re.compile(r'[ \t]*//'),
|
||
|
re.compile(r"[ \t]*''"),
|
||
|
]
|
||
|
if c is None:
|
||
|
self.re_inc = re.compile(r'(.*)@include[ \t]+(.+)')
|
||
|
self.re_start_inc = re.compile(r'(.*)@inc\[(.+)')
|
||
|
self.re_end_inc = re.compile(r'(.*)@inc\](.+)')
|
||
|
self.re_require = re.compile(r'(.*)@require[ \t]+(.+)')
|
||
|
self.re_provide = re.compile(r'(.*)@provide[ \t]+(.+)')
|
||
|
self.c = '@'
|
||
|
elif c in ('*', '@'):
|
||
|
self.re_inc = re.compile(r'(.*)(?:@|\*)include[ \t]+(.+)')
|
||
|
self.re_start_inc = re.compile(r'(.*)(?:@|\*)inc\[(.+)')
|
||
|
self.re_end_inc = re.compile(r'(.*)(?:@|\*)inc\](.+)')
|
||
|
self.re_require = re.compile(r'(.*)(?:@|\*)require[ \t]+(.+)')
|
||
|
self.re_provide = re.compile(r'(.*)(?:@|\*)provide[ \t]+(.+)')
|
||
|
self.c = c
|
||
|
|
||
|
self.inc_templ = "%s%sinclude %s"
|
||
|
self.start_inc_templ = "%s%sinc[%s"
|
||
|
self.end_inc_templ = "%s%sinc]%s"
|
||
|
self.require_templ = "%s%srequire %s"
|
||
|
self.provide_templ = "%s%sprovide %s"
|
||
|
|
||
|
self.top_level = True
|
||
|
|
||
|
def copy(self):
|
||
|
"""faire une copie de cet objet
|
||
|
"""
|
||
|
il = self.__class__(self.c)
|
||
|
il.top_level = False
|
||
|
return il
|
||
|
|
||
|
def is_comment(self, s):
|
||
|
"""retourner vrai si s est un commentaire (matche l'une des expressions
|
||
|
régulières de re_comment)
|
||
|
"""
|
||
|
for re_comment in self.re_comments:
|
||
|
if re_comment.match(s):
|
||
|
return True
|
||
|
return False
|
||
|
|
||
|
def matches(self, line):
|
||
|
"""retourner vrai si line est une ligne 'intéressante': ligne
|
||
|
d'inclusion repliée, dépliée de type 'start', dépliée de type 'end', de
|
||
|
type 'require', ou de type 'provide'
|
||
|
|
||
|
initialiser les informations sur cette ligne: mo, spaces, file
|
||
|
"""
|
||
|
self.__is_inc = 0
|
||
|
self.__is_start_inc = 0
|
||
|
self.__is_end_inc = 0
|
||
|
self.__is_require = 0
|
||
|
self.__is_provide = 0
|
||
|
|
||
|
mo = self.re_inc.match(line)
|
||
|
if mo is not None:
|
||
|
self.__is_inc = 1
|
||
|
else:
|
||
|
mo = self.re_start_inc.match(line)
|
||
|
if mo is not None:
|
||
|
self.__is_start_inc = 1
|
||
|
else:
|
||
|
mo = self.re_end_inc.match(line)
|
||
|
if mo is not None:
|
||
|
self.__is_end_inc = 1
|
||
|
else:
|
||
|
mo = self.re_require.match(line)
|
||
|
if mo is not None:
|
||
|
self.__is_require = 1
|
||
|
else:
|
||
|
mo = self.re_provide.match(line)
|
||
|
if mo is not None:
|
||
|
self.__is_provide = 1
|
||
|
if mo is not None:
|
||
|
before = mo.group(1)
|
||
|
if self.is_comment(before):
|
||
|
self.before = before
|
||
|
self.file = mo.group(2)
|
||
|
self.pf = inc_abspath(self.file)
|
||
|
else:
|
||
|
self.__is_inc = 0
|
||
|
self.__is_start_inc = 0
|
||
|
self.__is_end_inc = 0
|
||
|
self.__is_require = 0
|
||
|
self.__is_provide = 0
|
||
|
mo = None
|
||
|
self.mo = mo
|
||
|
|
||
|
return mo is not None
|
||
|
|
||
|
def is_inc(self, line=None):
|
||
|
"""Si line==None, retourner vrai si la ligne matchée par matches() est
|
||
|
une ligne d'inclusion repliée.
|
||
|
|
||
|
si line!=None, retourner vrai si la ligne est une ligne d'inclusion
|
||
|
repliée dont le nom de fichier correspond à la ligne matchée par
|
||
|
matches()
|
||
|
"""
|
||
|
if line is None:
|
||
|
return self.__is_inc
|
||
|
else:
|
||
|
mo = self.re_inc.match(line)
|
||
|
if mo is not None:
|
||
|
if mo.group(2) == self.file:
|
||
|
return 1
|
||
|
return 0
|
||
|
|
||
|
def inc(self):
|
||
|
"""retourner une ligne d'inclusion repliée construite avec self.before
|
||
|
et self.file
|
||
|
"""
|
||
|
return self.inc_templ % (self.before, self.c, self.file)
|
||
|
|
||
|
def is_start_inc(self, line=None):
|
||
|
"""Si line==None, retourner vrai si la ligne matchée par matches() est
|
||
|
une ligne d'inclusion dépliée de type 'start'.
|
||
|
|
||
|
si line!=None, retourner vrai si la ligne est une ligne d'inclusion
|
||
|
dépliée de type 'start' dont le nom de fichier correspond à la ligne
|
||
|
matchée par matches()
|
||
|
"""
|
||
|
if line is None:
|
||
|
return self.__is_start_inc
|
||
|
else:
|
||
|
mo = self.re_start_inc.match(line)
|
||
|
if mo is not None:
|
||
|
if mo.group(2) == self.file:
|
||
|
return 1
|
||
|
return 0
|
||
|
|
||
|
def start_inc(self):
|
||
|
"""retourner une ligne d'inclusion dépliée de type 'start' construite
|
||
|
avec self.before et self.file
|
||
|
"""
|
||
|
return self.start_inc_templ % (self.before, self.c, self.file)
|
||
|
|
||
|
def is_end_inc(self, line=None):
|
||
|
"""Si line==None, retourner vrai si la ligne matchée par matches() est
|
||
|
une ligne d'inclusion dépliée de type 'end'.
|
||
|
|
||
|
si line!=None, retourner vrai si la ligne est une ligne d'inclusion
|
||
|
dépliée de type 'end' dont le nom de fichier correspond à la ligne
|
||
|
matchée par matches()
|
||
|
"""
|
||
|
if line is None:
|
||
|
return self.__is_end_inc
|
||
|
else:
|
||
|
mo = self.re_end_inc.match(line)
|
||
|
if mo is not None:
|
||
|
if mo.group(2) == self.file:
|
||
|
return 1
|
||
|
return 0
|
||
|
|
||
|
def end_inc(self):
|
||
|
"""retourner une ligne d'inclusion dépliée de type 'end' construite
|
||
|
avec self.before et self.file
|
||
|
"""
|
||
|
return self.end_inc_templ % (self.before, self.c, self.file)
|
||
|
|
||
|
def is_require(self, line=None):
|
||
|
"""Si line==None, retourner vrai si la ligne matchée par matches() est
|
||
|
une ligne d'inclusion de type 'require'.
|
||
|
|
||
|
si line!=None, retourner vrai si la ligne est une ligne d'inclusion de
|
||
|
type 'require' dont le nom de fichier correspond à la ligne matchée par
|
||
|
matches()
|
||
|
"""
|
||
|
if line is None:
|
||
|
return self.__is_require
|
||
|
else:
|
||
|
mo = self.re_require.match(line)
|
||
|
if mo is not None:
|
||
|
if mo.group(2) == self.file:
|
||
|
return 1
|
||
|
return 0
|
||
|
|
||
|
def require(self):
|
||
|
"""retourner une ligne d'inclusion de type 'require' construite avec
|
||
|
self.before et self.file
|
||
|
"""
|
||
|
return self.require_templ % (self.before, self.c, self.file)
|
||
|
|
||
|
def is_provide(self, line=None):
|
||
|
"""Si line==None, retourner vrai si la ligne matchée par matches() est
|
||
|
une ligne d'inclusion de type 'provide'.
|
||
|
|
||
|
si line!=None, retourner vrai si la ligne est une ligne d'inclusion de
|
||
|
type 'provide' dont le nom de fichier correspond à la ligne matchée par
|
||
|
matches()
|
||
|
"""
|
||
|
if line is None:
|
||
|
return self.__is_provide
|
||
|
else:
|
||
|
mo = self.re_provide.match(line)
|
||
|
if mo is not None:
|
||
|
if mo.group(2) == self.file:
|
||
|
return 1
|
||
|
return 0
|
||
|
|
||
|
def provide(self):
|
||
|
"""retourner une ligne d'inclusion de type 'provide' construite avec
|
||
|
self.before et self.file
|
||
|
"""
|
||
|
return self.provide_templ % (self.before, self.c, self.file)
|
||
|
|
||
|
##################################################
|
||
|
# replier un fichier
|
||
|
|
||
|
def fold(file, level=0, il=None, recursive_update=0, parent_print_processing_maybe=None, **ignored):
|
||
|
"""Replier un fichier: c'est l'opération inverse de unfold_or_update
|
||
|
"""
|
||
|
if il is None: il = InterestingLine()
|
||
|
|
||
|
pf = inc_abspath(file)
|
||
|
|
||
|
# vérifier la présence du fichier
|
||
|
if not path.exists(pf):
|
||
|
_print(level, "not found: %s" % pf)
|
||
|
return
|
||
|
|
||
|
# Il ne faut pas changer le répertoire courant en sortant de cette
|
||
|
# fonction. Faire une copie d'abord
|
||
|
cwd = os.getcwd()
|
||
|
|
||
|
# Se placer dans le répertoire du fichier
|
||
|
p, f = path.split(pf)
|
||
|
os.chdir(p)
|
||
|
|
||
|
try:
|
||
|
tf = TextFile(pf, lines=BLines())
|
||
|
try:
|
||
|
old = tf.readlines()
|
||
|
except:
|
||
|
# impossible de lire le fichier
|
||
|
_print(level, "unable to read: %s" % pf)
|
||
|
return
|
||
|
new = []
|
||
|
|
||
|
printed = [0]
|
||
|
def print_processing_maybe(level=level, file=file, printed=printed, parent_print_processing_maybe=parent_print_processing_maybe):
|
||
|
if parent_print_processing_maybe is not None:
|
||
|
parent_print_processing_maybe()
|
||
|
if not printed[0]:
|
||
|
_print(level, "processing: %s" % file)
|
||
|
printed[0] = 1
|
||
|
|
||
|
folding = 0 # est-on en train de replier?
|
||
|
was_modified = 0
|
||
|
for line in old:
|
||
|
if not folding:
|
||
|
if il.matches(line):
|
||
|
if il.is_require():
|
||
|
if recursive_update:
|
||
|
fold(il.file, level=level + 1,
|
||
|
il=il.copy(), recursive_update=recursive_update,
|
||
|
parent_print_processing_maybe=print_processing_maybe)
|
||
|
new.append(il.require())
|
||
|
if il.require() != line: was_modified = 1
|
||
|
elif il.is_provide():
|
||
|
if recursive_update:
|
||
|
fold(il.file, level=level + 1,
|
||
|
il=il.copy(), recursive_update=recursive_update,
|
||
|
parent_print_processing_maybe=print_processing_maybe)
|
||
|
new.append(il.provide())
|
||
|
if il.provide() != line: was_modified = 1
|
||
|
elif il.is_inc():
|
||
|
if recursive_update:
|
||
|
fold(il.file, level=level + 1,
|
||
|
il=il.copy(), recursive_update=recursive_update,
|
||
|
parent_print_processing_maybe=print_processing_maybe)
|
||
|
new.append(il.inc())
|
||
|
if il.inc() != line: was_modified = 1
|
||
|
elif il.is_start_inc():
|
||
|
if il.start_inc() != line: was_modified = 1
|
||
|
folding = 1
|
||
|
|
||
|
if was_modified: print_processing_maybe()
|
||
|
else:
|
||
|
new.append(line)
|
||
|
else:
|
||
|
if il.is_end_inc(line):
|
||
|
if recursive_update:
|
||
|
fold(il.file, level=level + 1,
|
||
|
il=il.copy(), recursive_update=recursive_update,
|
||
|
parent_print_processing_maybe=print_processing_maybe)
|
||
|
print_processing_maybe()
|
||
|
_print(level, "f %s" % il.file, verbose)
|
||
|
new.append(il.inc())
|
||
|
was_modified = 1
|
||
|
folding = 0
|
||
|
|
||
|
if folding:
|
||
|
# on a trouvé une inclusion non terminée. ne pas modifier le fichier
|
||
|
_print(level, "warning: %s include not properly ended, ignored" % il.file)
|
||
|
was_modified = 0
|
||
|
|
||
|
if was_modified:
|
||
|
tf.writelines(new)
|
||
|
finally:
|
||
|
os.chdir(cwd)
|
||
|
|
||
|
|
||
|
##################################################
|
||
|
# déplier un fichier
|
||
|
|
||
|
MODIFIED = 2
|
||
|
UNMODIFIED = 1
|
||
|
ERROR = 0
|
||
|
|
||
|
def unfold_or_update(file, level=0, il=None, recursive_update=0, files=None, provided=None, parent_print_processing_maybe=None, **ignored):
|
||
|
"""déplier un fichier. Seul le fichier file est modifié le cas échéant si
|
||
|
files!=None
|
||
|
|
||
|
retourner MODIFIED si le fichier a été lu depuis le disque ou s'il a été
|
||
|
modifié, UNMODIFIED s'il faut utiliser le cache de lecture files, ERROR si
|
||
|
erreur (aucune modification effectuée)
|
||
|
"""
|
||
|
if il is None: il = InterestingLine()
|
||
|
|
||
|
pf = inc_abspath(file)
|
||
|
|
||
|
# Si le fichier a déja été traité, nous pouvons retourner
|
||
|
if files is not None and files.has_key(pf):
|
||
|
return UNMODIFIED
|
||
|
|
||
|
# liste des fichiers déjà traités.
|
||
|
can_write = recursive_update # doit-on mettre à jour le fichier sur disque?
|
||
|
if files is None:
|
||
|
can_write = 1
|
||
|
files = {}
|
||
|
# liste des fichiers déjà inclus
|
||
|
if provided is None:
|
||
|
provided = {}
|
||
|
|
||
|
printed = [0]
|
||
|
def print_processing_maybe(level=level, file=file, printed=printed, parent_print_processing_maybe=parent_print_processing_maybe):
|
||
|
if parent_print_processing_maybe is not None:
|
||
|
parent_print_processing_maybe()
|
||
|
if not printed[0]:
|
||
|
_print(level, "processing: %s" % file)
|
||
|
printed[0] = 1
|
||
|
|
||
|
# vérifier la présence du fichier
|
||
|
if not path.exists(pf):
|
||
|
if level == 0:
|
||
|
_print(level, "not found: %s" % pf)
|
||
|
else:
|
||
|
print_processing_maybe()
|
||
|
_print(level - 1, "X %s (not found)" % file)
|
||
|
return ERROR
|
||
|
|
||
|
# Il ne faut pas changer le répertoire courant en sortant de cette
|
||
|
# fonction. Faire une copie d'abord
|
||
|
cwd = os.getcwd()
|
||
|
|
||
|
# Se placer dans le répertoire du fichier
|
||
|
p, f = path.split(pf)
|
||
|
os.chdir(p)
|
||
|
|
||
|
try:
|
||
|
tf = TextFile(pf, lines=BLines())
|
||
|
try:
|
||
|
old = tf.readlines()
|
||
|
except:
|
||
|
# impossible de lire le fichier
|
||
|
if level == 0:
|
||
|
_print(level, "unable to read: %s" % pf)
|
||
|
else:
|
||
|
_print(level - 1, "X %s (unable to read)" % file)
|
||
|
return ERROR
|
||
|
new = []
|
||
|
files[pf] = tf
|
||
|
provided[pf] = 1
|
||
|
|
||
|
unfolding = None # est-on en train de déplier?
|
||
|
was_modified = 0
|
||
|
for line in old:
|
||
|
if unfolding is None:
|
||
|
if il.matches(line):
|
||
|
if il.is_require():
|
||
|
# traiter le cas @require
|
||
|
_debug("require\n file=%s\n provided=\n %s" % (il.file, string.join(provided.keys(), '\n ')))
|
||
|
if not il.top_level and not provided.has_key(il.pf):
|
||
|
print_processing_maybe()
|
||
|
_print(level, "R %s (is required)" % il.file)
|
||
|
new.append(il.require())
|
||
|
if il.require() != line: was_modified = 1
|
||
|
elif il.is_provide():
|
||
|
# traiter le cas @provide
|
||
|
_debug("provide\n file=%s\n provided=\n %s" % (il.file, string.join(provided.keys(), '\n ')))
|
||
|
provided[il.pf] = 1
|
||
|
new.append(il.provide())
|
||
|
if il.provide() != line: was_modified = 1
|
||
|
elif il.is_inc():
|
||
|
# traiter le cas @include
|
||
|
if unfold_or_update(il.file, level=level + 1,
|
||
|
il=il.copy(), recursive_update=recursive_update,
|
||
|
files=files, provided=provided,
|
||
|
parent_print_processing_maybe=print_processing_maybe):
|
||
|
print_processing_maybe()
|
||
|
_print(level, "U %s" % il.file, verbose)
|
||
|
new.append(il.start_inc())
|
||
|
new.extend(files[il.pf].lines)
|
||
|
new.append(il.end_inc())
|
||
|
was_modified = 1
|
||
|
else:
|
||
|
new.append(il.inc())
|
||
|
if il.inc() != line: was_modified = 1
|
||
|
elif il.is_start_inc():
|
||
|
unfolding = []
|
||
|
if il.start_inc() != line: was_modified = 1
|
||
|
else:
|
||
|
new.append(line)
|
||
|
else:
|
||
|
if il.is_end_inc(line):
|
||
|
status = unfold_or_update(il.file, level=level + 1,
|
||
|
il=il.copy(), recursive_update=recursive_update,
|
||
|
files=files, provided=provided,
|
||
|
parent_print_processing_maybe=print_processing_maybe)
|
||
|
if status == MODIFIED:
|
||
|
if unfolding != files[il.pf].lines:
|
||
|
print_processing_maybe()
|
||
|
_print(level, "u %s" % il.file, verbose)
|
||
|
was_modified = 1
|
||
|
new.append(il.start_inc())
|
||
|
new.extend(files[il.pf].lines)
|
||
|
new.append(il.end_inc())
|
||
|
if il.end_inc() != line: was_modified = 1
|
||
|
elif status == UNMODIFIED:
|
||
|
new.append(il.start_inc())
|
||
|
new.extend(files[il.pf].lines)
|
||
|
new.append(il.end_inc())
|
||
|
if il.end_inc() != line: was_modified = 1
|
||
|
elif status == ERROR:
|
||
|
print_processing_maybe()
|
||
|
_print(level, "X %s (not found)" % il.file)
|
||
|
new.append(il.start_inc())
|
||
|
new.extend(unfolding)
|
||
|
new.append(il.end_inc())
|
||
|
if il.end_inc() != line: was_modified = 1
|
||
|
unfolding = None
|
||
|
else:
|
||
|
unfolding.append(line)
|
||
|
|
||
|
if unfolding is not None:
|
||
|
# on a trouvé une inclusion non terminée. ne pas modifier le fichier
|
||
|
print_processing_maybe()
|
||
|
_print(level, "warning: %s include not properly ended, ignored" % il.file)
|
||
|
was_modified = 0
|
||
|
|
||
|
if was_modified:
|
||
|
if new == tf.lines:
|
||
|
return UNMODIFIED
|
||
|
print_processing_maybe()
|
||
|
tf.lines[:] = new
|
||
|
if can_write:
|
||
|
tf.writelines()
|
||
|
|
||
|
return MODIFIED
|
||
|
finally:
|
||
|
os.chdir(cwd)
|
||
|
|
||
|
##################################################
|
||
|
# lecture des paramètres
|
||
|
|
||
|
def update_inc_params(args=None, basedir=None):
|
||
|
if args is None: args = sys.argv[1:]
|
||
|
|
||
|
global verbosity, debug, incpaths
|
||
|
pr = {'action': unfold_or_update,
|
||
|
'exclude_names': ['CVS/', '.svn/'],
|
||
|
'exclude_paths': [],
|
||
|
'il': None,
|
||
|
'recursive_update': 0,
|
||
|
}
|
||
|
|
||
|
args_read = False
|
||
|
while not args_read:
|
||
|
config_file = None
|
||
|
|
||
|
opts, args = get_args(args, 'qvDuRfx:X:I:*@C:',
|
||
|
['quiet', 'verbose', 'debug',
|
||
|
'update', 'unfold', 'recursive-update',
|
||
|
'fold',
|
||
|
'exclude-names=', 'exclude-paths', 'include-paths',
|
||
|
'config-file=', 'basedir=',
|
||
|
])
|
||
|
|
||
|
for opt, value in opts:
|
||
|
if opt in ('-q', '--quiet'):
|
||
|
verbosity = quiet
|
||
|
elif opt in ('-v', '--verbose'):
|
||
|
verbosity = verbose
|
||
|
elif opt in ('-D', '--debug'):
|
||
|
debug = 1
|
||
|
elif opt in ('-u', '--update', '--unfold'):
|
||
|
pr['action'] = unfold_or_update
|
||
|
elif opt in ('-R', '--recursive-update'):
|
||
|
pr['recursive_update'] = 1
|
||
|
elif opt in ('-f', '--fold'):
|
||
|
pr['action'] = fold
|
||
|
elif opt in ('-x', '--exclude-names'):
|
||
|
if ':' in value:
|
||
|
pr['exclude_names'] = filter(None, string.split(value, ':'))
|
||
|
else:
|
||
|
pr['exclude_names'].append(value)
|
||
|
elif opt in ('-X', '--exclude-paths'):
|
||
|
if ':' in value:
|
||
|
pr['exclude_paths'] = filter(None, string.split(value, ':'))
|
||
|
else:
|
||
|
pr['exclude_paths'].append(value)
|
||
|
elif opt in ('-I', '--include-paths'):
|
||
|
if incpaths is None: init_incpaths()
|
||
|
set_incpaths(value)
|
||
|
elif opt in ('-*',):
|
||
|
pr['il'] = InterestingLine('*')
|
||
|
elif opt in ('-@',):
|
||
|
pr['il'] = InterestingLine('@')
|
||
|
elif opt in ('-C', '--config-file'):
|
||
|
config_file = value
|
||
|
elif opt in ('--basedir',):
|
||
|
basedir = path.abspath(value)
|
||
|
|
||
|
if config_file is not None:
|
||
|
cf = ShConfigFile(config_file, raise_exception=False)
|
||
|
if cf.is_valid():
|
||
|
args = split_args(cf.get('update_inc_options', '')) + split_args(cf.get('update_inc_args', '')) + args
|
||
|
else:
|
||
|
ewarn("Impossible de lire le fichier de configuration: %s" % config_file)
|
||
|
|
||
|
args_read = config_file is None
|
||
|
|
||
|
# transformer tous les chemins de args en chemins absolus.
|
||
|
if basedir is None: basedir = os.getcwd()
|
||
|
for i in range(len(args)):
|
||
|
args[i] = path.abspath(path.join(basedir, args[i]))
|
||
|
|
||
|
return pr, args
|
||
|
|
||
|
def update_inc(pr, args=None, action=None):
|
||
|
global incpaths
|
||
|
if incpaths is None: init_incpaths()
|
||
|
|
||
|
if action is not None:
|
||
|
action = {'fold': fold,
|
||
|
'unfold': unfold_or_update,
|
||
|
'update': unfold_or_update,
|
||
|
'unfold_or_update': unfold_or_update,
|
||
|
}.get(action, None)
|
||
|
if action is None: action = pr['action']
|
||
|
|
||
|
if args is None: args = []
|
||
|
for arg in args:
|
||
|
if path.isdir(arg):
|
||
|
for file in select_files(arg, pr['exclude_names'], pr['exclude_paths']):
|
||
|
action(file, il=pr['il'], recursive_update=pr['recursive_update'])
|
||
|
else:
|
||
|
action(arg, il=pr['il'], recursive_update=pr['recursive_update'])
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
pr, args = update_inc_params()
|
||
|
update_inc(pr, args)
|