nutools/lib/pyulib/src/uapps/pyurelease.py

812 lines
30 KiB
Python
Executable File

#!/usr/bin/env python
# -*- coding: utf-8 -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
u"""%(name)s - Gérer les releases d'un projet
USAGE
%(name)s [options] [projdir]
"""
import os, sys, string, re, shutil
from os import path
from time import time, localtime
from ulib.all import *
from ulib.vcs import *
from ulib.ext.tarfile import tarfile
from uapps.update_inc import update_inc_params, update_inc
from pyutools.TODO import TODOs
from pyutools.wo import wo_projname_and_projtype
def uappspath(file):
"""Exprimer un fichier par rapport au répertoire de uapps.
XXX il vaut mieux déplacer la logique dans un module, et exprimer le fichier
par rapport à la position du module
"""
uappsdir = path.join(sys.prefix, 'lib', 'python' + sys.version[:3], 'site-packages', 'uapps')
return path.join(uappsdir, file)
##################################################
### Méthodes de gestion des paramètres
# Note: les paramètres peuvent être donnés sur la ligne de commande, dans un
# fichier release.conf, et ont une valeur par défaut
## On construit les structures au fur et à mesure
# Paramètres valides dans release.conf et méthodes associées
params_for_release_conf = {}
# Valeurs par défauts
params_defaults = {}
# Paramètres sur la ligne de commande
argsdesc = [
# Afficher l'aide
('h', 'help', u"Afficher l'aide"),
]
## Gestion des versions
uver = 'release_update_version'
sver = 'force_version'
def set_uver(p, value=False): p[uver] = is_yes(value)
def set_sver(p, value): p[sver] = value
params_for_release_conf.update({uver: set_uver})
params_defaults.update({uver: False, sver: None})
argsdesc.extend([
('n', 'keep-version', u"Ne pas changer la version (par défaut)"),
('u', 'update-version', u"Mettre à jour la version"),
('v:', 'set-version=', u"Spécifier une nouvelle version"),
])
## suivi des changements
log = 'release_log_changes'
todorc = 'release_todorc'
def set_log(p, value=False): p[log] = is_yes(value)
def set_todorc(p, value): p[todorc] = path.abspath(value)
params_for_release_conf.update({log: set_log, todorc: set_todorc})
params_defaults.update({log: True, todorc: None})
argsdesc.extend([
(None, 'log-changes', u"Saisir les changements pour une nouvelle version (par défaut)"),
(None, 'no-log-changes', u"Ne pas saisir les changements"),
(None, 'todorc=', u"Spécifier le fichier de configuration pour la gestion des TODOs"),
])
## gestion des tags (avec CVS)
tag = 'release_tag_in_vcs'
stag = 'force_tag'
def set_tag(p, value=False): p[tag] = is_yes(value)
def set_stag(p, value): p[stag] = value
params_for_release_conf.update({tag: set_tag})
params_defaults.update({tag: True, stag: None})
argsdesc.extend([
(None, 'tag', u"tagger les sources avec le nom du projet et la version (par défaut)"),
(None, 'no-tag', u"Ne pas tagger les sources"),
(None, 'set-tag', u"Spécifier le tag à utiliser"),
])
## gestion des fichiers de licence
lic = 'release_include_license'
slic = 'force_license'
def set_lic(p, value=False): p[lic] = is_yes(value)
def set_slic(p, value): p[slic] = value
params_for_release_conf.update({lic: set_lic})
params_defaults.update({lic: True, slic: None})
argsdesc.extend([
(None, 'include-license', u"Inclure un fichier de licence"),
(None, 'no-include-license', u"Ne pas inclure le fichier de licence"),
(None, 'set-license', u"Choisir le fichier de licence à utiliser"),
(None, 'ur', u"Spécifier la licence pour les produits de l'université de la Réunion"),
(None, 'jclain', u"Spécifier la licence pour les produits de Jephté CLAIN"),
])
## création de l'archive
bp = 'release_base_path'
exn = 'release_exclude_names'
exp = 'release_exclude_paths'
an = 'archive_name'
asrc = 'archive_source'
sas = 'source_archive_suffix'
ab = 'archive_binary'
bas = 'binary_archive_suffix'
aj = 'archive_javadoc'
jdas = 'archive_suffix'
def set_bp(p, value): p[bp] = value
def set_exn(p, value):
if not p.has_key(exn): p[exn] = []
if ':' in value:
values = string.split(value, ':')
else:
values = [value]
for value in values:
list_set(p[exn], value)
def set_exp(p, value):
if not p.has_key(exp): p[exp] = []
if ':' in value:
values = string.split(value, ':')
else:
values = [value]
for value in values:
list_set(p[exp], value)
def set_an(p, value): p[an] = value
def set_asrc(p, value=False): p[asrc] = is_yes(value)
def set_sas(p, value): p[sas] = value
def set_ab(p, value=False): p[ab] = is_yes(value)
def set_bas(p, value): p[bas] = value
def set_aj(p, value=False): p[aj] = is_yes(value)
def set_jdas(p, value): p[jdas] = value
params_for_release_conf.update({bp: set_bp, exn: set_exn, exp: set_exp})
params_defaults.update({bp: '@@projname@@', #'@@projname@@-@@projver@@',
exn: [], exp: [], an: None,
asrc: False, sas: '',
ab: False, bas: '',
aj: False, jdas: '-api'
})
argsdesc.extend([
('c', 'archive-source', u"Créer l'archive du source"),
('B', 'archive-binary', u"Créer l'archive du produit binaire"),
('J', 'archive-javadoc', u"Créer l'archive de la javadoc"),
('b:', 'base-path=', u"Dans l'archive générée, répertoire de base"),
('x:', 'exclude-names=', u"Noms de fichiers à exclure de l'archive"),
('X:', 'exclude-paths=', u"Répertoires à exclure de l'archive"),
])
# ensembles nommés d'options
pyp = 'release_use_python_defaults'
zop = 'release_use_zope_defaults'
jawop = 'release_use_jawo_defaults'
def set_pyp(p, value=False):
if is_yes(value):
p[pyp] = True
p[zop] = p[jawop] = False
set_tag(p, True)
set_log(p, True)
set_lic(p, True)
set_exn(p, 'CVS/')
set_exn(p, '.svn/')
set_exn(p, '*.pyc')
set_exn(p, '*~')
set_exn(p, '.DS_Store')
def set_zop(p, value=False):
if is_yes(value):
set_pyp(True)
p[zop] = True
p[pyp] = p[jawop] = False
p[bp] = 'lib/python/Products/@@projname@@' #'lib/python/Products/@@projname@@-@@projver@@'
def set_jawop(p, value=False):
if is_yes(value):
p[jawop] = True
p[pyp] = p[zop] = False
set_tag(p, True)
set_log(p, True)
set_lic(p, True)
set_sas(p, '-src')
set_exn(p, 'CVS/')
set_exn(p, '.svn/')
set_exn(p, '*~')
set_exn(p, '.DS_Store')
set_exp(p, 'build/')
set_exp(p, '*.pbproj/*.pbxuser')
params_for_release_conf.update({pyp: set_pyp, zop: set_zop, jawop: set_jawop})
params_defaults.update({pyp: False, zop: False, jawop: False})
argsdesc.extend([
(None, 'auto', u"Autodétecter le type de projet (par défaut)"),
(None, 'no-auto', u"Ne pas autodétecter le type de projet"),
('P', 'python-product', u"Choisir les options par défaut pour un projet Python"),
('Z', 'zope-product', u"Choisir les options par défaut pour un projet Zope"),
('W', 'jawo-product', u"Choisir les options par défaut pour un projet jabuild/wobuild"),
])
def is_auto(opt): return opt in ('--auto', )
def isnot_auto(opt): return opt in ('--no-auto', '-P', '--python-product',
'-Z', '--zope-product',
'-W', '--jawo-product',
)
# support de update_inc
ui = 'update_inc'
def set_ui(p, value=False, basedir=None):
p[ui] = None
if is_yes(value):
if basedir is None: basedir = os.getcwd()
cf = ShConfigFile(path.join(basedir, '.uinst.conf'), raise_exception=False)
if cf.is_valid():
# on force le mode quiet avec -q en attendant que update_inc supporte set_verbosity()
options = split_args(cf.get('update_inc_options', '') + ' -q') + split_args(cf.get('update_inc_args', ''))
p_ui, args_ui = update_inc_params(options, basedir=basedir)
p[ui] = (p_ui, args_ui)
def fold_maybe(p, vcsdir=None):
if p[ui]:
pr, args = p[ui]
if vcsdir is None:
update_inc(pr, args, 'fold')
return True
else: return vcsdir.fold(pr, args, 'fold')
def unfold_maybe(p, vcsdir=None):
if p[ui]:
pr, args = p[ui]
if vcsdir is None: update_inc(pr, args, 'unfold')
else: vcsdir.unfold(pr, args, 'unfold')
params_for_release_conf.update({ui: set_ui})
params_defaults.update({ui: False})
argsdesc.extend([
(None, 'update_inc', u"Activer le support de update_inc"),
])
# autres paramètres qui sont utilisés par release()
cver = 'version_txt_created?'
clog = 'changes_txt_created?'
clic = 'license_txt_created?'
cd = 'curdir'
pn = 'projname'
pt = 'projtype'
def set_cver(p, value=False): p[cver] = is_yes(value)
def set_clog(p, value=False): p[clog] = is_yes(value)
def set_clic(p, value=False): p[clic] = is_yes(value)
def set_cd(p, value): p[cd] = value
def set_pn(p, value): p[pn] = value
def set_pt(p, value): p[pt] = value
params_for_release_conf.update({})
params_defaults.update({cver: False,clog: False, clic: False, cd: None,
pn: None, pt: None,
})
argsdesc.extend([])
##################################################
# Méthodes utilitaires
def list_set(list, value):
"""insérer une valeur dans une liste si elle n'y est pas déjà
"""
if value not in list:
list.append(value)
def strip_release_from_version(v):
"""Supprimer la date de release dd/mm/yyyy d'un numéro de version
"""
v = string.strip(v)
mo = re.match(r'(.*)-r[0-9]+/[0-9]+/[0-9]+$', v)
if mo is not None:
v = mo.group(1)
return v
def _inc_last(v):
v0, v1 = re.match(r'^(.*?)([0-9]*)$', v).groups()
v1 = str(int(v1 or 0) + 1)
return v0 + v1
def increment_version(v):
"""Incrémenter le dernier élément d'un numéro de version, et retourner les
différentes propositions possibles.
"""
vs = []
# [0]: ajouter un chiffre
vs.append(v + '.1')
# [1]: incrémenter le dernier
vs.append(_inc_last(v))
# [2]: incrémenter l'avant dernier
if v.count('.') > 1:
pos = v.rfind('.')
vs.append(_inc_last(v[:pos]))
return vs
def expand_projname_and_version(s, p):
s = string.replace(s, "@@projname@@", p[pn])
s = string.replace(s, "@@projver@@", p[sver])
return s
##################################################
# Méthodes pour la création d'une archive
def tarpath(p):
"""normaliser un chemin pour utilisation dans un fichier tar: il ne doit pas
se terminer par /, les séparateurs doivent être / et non \ et le répertoire
courant '.' est remplacé par ''
"""
p = path.normpath(p)
p = string.replace(p, '\\', '/')
while p[-1:] == '/': p = p[:-1]
if p == '.': p = ''
return p
def normalize_paths(paths):
"""Normaliser tous les chemins de la liste paths.
Retourner une liste de tuples (tpath, apath), où tpath est le chemin
normalisé pour le fichier tar (séparateurs '/'), et apath est le chemin
absolu sur le système de fichier.
"""
return map(lambda p: (tarpath(p), path.abspath(p)), paths)
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
on ne suit pas les liens symboliques.
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):
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:
files.append(pf)
if path.isdir(pf) and not path.islink(pf):
files.extend(select_files(pf, exclude_names, exclude_paths, basepath))
return files
def create_archive(p, paths, altbp=None):
"""Créer l'archive p[an].tgz dans le répertoire courant avec les
répertoires énumérés dans paths
"""
archive = tarfile.open(p[an] + '.tgz', 'w:gz')
archive.posix = 0
if altbp is None: altbp = p[bp]
basepath = altbp and altbp + '/' or ''
for tp, ap in paths:
tp = tp and tp + '/' or ''
files = select_files(ap, p[exn], p[exp])
for file in files:
tfile = basepath + tp + string.replace(file[len(ap) + 1:], '\\', '/')
archive.add(file, tfile, False)
archive.close()
##################################################
# L'application release
def print_help(name=None):
if name is None:
name = path.split(sys.argv[0])[1]
print __doc__ % vars()
print "OPTIONS"
for argdesc in argsdesc:
so = argdesc[0:1] and argdesc[0] or None
if so is not None: so = '-' + so[:1]
lo = argdesc[1:2] and argdesc[1] or None
if lo is not None: lo = (so is not None and ', ' or '') + '--' + lo
desc = argdesc[2:3] and argdesc[2] or None
if so is not None or lo is not None:
print " %s%s" % (so or '', lo or '')
if desc is not None: print " %s" % desc
def release(p, *paths):
release_date = time()
# Obtenir, vérifier et/ou normaliser les chemins
paths = list(paths)
curdir = p[cd]
if curdir is None: die(u"curdir doit être spécifié")
projname = p[pn]
if projname is None: die(u"Il faut donner le nom du projet")
projtype = p[pt]
tp0, ap0 = paths[0]
### obtenir le numéro de version courant et incrémenter le numéro de version
maj_version = False # True si la version a été changée
# calculer le nom du fichier qui contient la version
version_txt = 'VERSION.txt'
if not path.isfile(path.join(ap0, version_txt)):
if path.isfile(path.join(ap0, 'version.txt')):
version_txt = 'version.txt'
aversion_txt = path.join(ap0, version_txt)
# lire la version qui se trouve dans le fichier
if not path.isfile(aversion_txt):
if not ask_yesquit(u"Le fichier %s n'existe pas. Faut-il le créer?" % version_txt, True, minlevel=I_INTER):
raise Exit, 1
set_cver(p, True)
vf = TextFile(aversion_txt, raise_exception=False)
if vf.lines:
v = strip_release_from_version(vf.lines[0])
einfo(u"La version actuelle est %s" % v)
else:
v = ''
if p[uver]:
v = '0.0'
einfo(u"Pas d'information de version. on commence à 0.1")
elif p[sver] is not None:
einfo(u"Pas d'information de version. On commence à %s (forcé)" % p[sver])
else:
einfo(u"Pas d'information de version.")
vs = None
if p[sver] is None:
if p[uver]:
vs = increment_version(v)
v = vs[1]
maj_version = True
p[sver] = v
else:
maj_version = p[sver] != v
if maj_version:
if vs is None:
if not ask_yesquit(u"Mettre à jour la version vers %s?" % p[sver], True):
raise Exit, 1
else:
if check_verbosity(I_NORMAL):
for i in range(len(vs)):
einfo(u"%i - Passer à la version %s" % (i, vs[i]))
r = read_value(u"Mettre à jour la version vers %s? [Oq]" % p[sver], default="O", refuse_empty=False)
v = None
if re.match(r'\d+$', r) is not None:
i = int(r)
if i >= 0 and i < len(vs):
v = vs[i]
elif is_yes(r):
v = vs[1]
if v is None: raise Exit, 1
else: p[sver] = v
vf.lines[0:1] = [p[sver] + '-r' + datef(FR_DATEF, release_date)]
vf.writelines()
# mettre à jour p[bp] qui peut contenir des tags @@projname@@ et @@projver@@
p[bp] = expand_projname_and_version(tarpath(p[bp]), p)
### enregistrer les changements, seulement si on met à jour la version
if p[log] and maj_version:
if not ask_yesquit(u"Saisir le changelog pour la version %s?" % p[sver], True, minlevel=I_INTER):
raise Exit, 1
template = u"""
-EDIT-: ----------------------------------------------------------------------
-EDIT-: Saisissez une description de la distribution %(projname)s-%(version)s
-EDIT-:
-EDIT-: Les lignes commencant par '-EDIT-:' sont automatiquement supprimees
-EDIT-: dans le fichier de sortie (%(filename)s)
-EDIT-:
-EDIT-: ----------------------------------------------------------------------
"""
project = path.split(ap0)[1]
# Calculer automatiquement les tâches qui doivent être incluses dans le log
ts = TODOs(p[todorc])
ts.purge(project)
released = ts.list_releaseable(project)
mark_released = False
if released:
mark_released = True
template = template + u"""\
-EDIT-: Pour information, les informations suivantes seront automatiquement
-EDIT-: ajoutées à la description de la distribution:
-EDIT-:
"""
lines = []
for ds in map(lambda d: d.to_string(), released):
ds = ds.replace("%", "%%")
lines.append("\n".join(map(lambda l: "-EDIT-: " + l, string.split(ds, "\n"))))
template = template + "\n-EDIT-: ----\n".join(lines)
todofile = ts.get_todofile(project)
if todofile is not None and todofile.can_release():
# éditer le fichier
change_lines = edit_template(template % {'projname': projname,
'version': p[sver],
'filename': todofile.get_file()},
'-EDIT-:')
todofile.release(released, release_date, p[sver], change_lines.join())
todofile.save()
else:
# calculer le nom du fichier qui contient les changements
changes_txt = 'CHANGES.txt'
if not path.exists(path.join(ap0, changes_txt)):
if path.exists(path.join(ap0, 'changes.txt')):
changes_txt = changes.txt
achanges_txt = path.join(ap0, changes_txt)
if not path.exists(achanges_txt):
set_clog(p, True)
# éditer le fichier
change_lines = edit_template(template % {'projname': projname,
'version': p[sver],
'filename': changes_txt},
'-EDIT-:')
if released:
first = False
if change_lines: change_lines.append("")
else: first = True
for todo in released:
if first: first = False
else: change_lines.append("----")
change_lines.extend(string.split(todo.to_string(), "\n"))
# ajouter le changelog
cf = TextFile(achanges_txt, raise_exception=False)
if cf.lines and string.strip(cf.lines[-1]):
cf.lines.append("")
title = u"%s %s-%s" % (datef(FRHM_DATEF, release_date), projname, p[sver])
cf.lines[0:0] = [title, "=" * len(title), ""] + change_lines + (cf.lines and [""] or [])
cf.writelines()
ts.mark_released(project)
### ajouter le fichier de licence
alicense_txt = None
if p[lic] and maj_version:
# calculer le nom du fichier qui contient la licence
license_txt = 'LICENSE.txt'
if not path.exists(path.join(ap0, license_txt)):
if path.exists(path.join(ap0, 'license.txt')):
license_txt = 'license.txt'
alicense_txt = path.join(ap0, license_txt)
if not path.exists(alicense_txt):
set_clic(p, True)
# si on a spécifié un fichier de license, forcer l'écrasement. Sinon, on
# ne copie la license que si elle n'existe pas déjà
copy_license = False
if p[slic] is None:
if p[clic]:
copy_license = True
p[slic] = uappspath('ur_license.txt') # par défaut
if p[slic] is not None:
copy_license = True
if dirname(p[slic]) == '':
# si on donne juste le nom du fichier, et qu'il n'existe pas
# dans le répertoire courant, l'exprimer par rapport à au
# répertoire du module uapps. XXX cf la documentation de
# uappspath() pour voir ce qu'il faut corriger
if not path.isfile(path.join(curdir, p[slic])):
p[slic] = tmp = uappspath(p[slic])
if not path.isfile(tmp):
tmp = tmp + '_license.txt'
if path.exists(tmp): p[slic] = tmp
## si on donne juste le nom du fichier, et qu'il n'existe pas
## dans le répertoire courant, l'exprimer par rapport à
## au répertoire de ce module
#if not path.isfile(path.join(curdir, p[slic])):
# p[slic] = path.join(dirname(__file__), p[slic])
# if not path.isfile(p[slic]):
# tmp = p[slic] + '_license.txt'
# if path.exists(tmp):
# p[slic] = tmp
if not path.isfile(p[slic]):
die(u"Fichier de licence inexistant: %s" % p[slic])
if copy_license:
if not ask_yesquit(u"Copier le fichier de licence %s?" % basename(p[slic]), True, minlevel=I_INTER):
raise Exit, 1
if not path.exists(alicense_txt) or not path.samefile(p[slic], alicense_txt):
shutil.copy(p[slic], alicense_txt)
p[slic] = alicense_txt
lf = TextFile(p[slic])
if lf.grep(r'.*(@@projname@@|@@year@@)'):
lf.replace('@@projname@@', projname)
lf.replace('@@year@@', datef(YEAR_DATEF))
lf.writelines()
### tag des fichiers si VCS est activé et si la version a été modifiée
if p[tag] and maj_version and is_vcsdir(ap0):
vcsdir = get_vcsdir(ap0)
vcsdir.set_tag_rootdir(False)
options = dict(trace=True, quiet=True, auto_update=False)
# déterminer le nom du tag
if p[stag] is None:
p[stag] = '%s-%s' % (projname, string.replace(p[sver], '.', '-'))
if ask_yesno(u"Taguer avec %s?" % p[stag], True, minlevel=I_INTER):
os.chdir(ap0)
# avant vcs, il faut faire un fold si on supporte update_inc
estep(u"Suppression des inclusions")
folded = fold_maybe(p, vcsdir)
estep(u"Marquage des fichiers avec le tag %s" % p[stag])
if p[cver]: vcsdir.add(version_txt, **options)
if p[clog]: vcsdir.add(changes_txt, **options)
if p[clic]: vcsdir.add(license_txt, **options)
message = u"Création de la distribution pour le tag %s" % p[stag]
vcsdir.commit(message, **options)
vcsdir.tag(p[stag], message, **options)
# après vcs, il faut faire un unfold si on supporte update_inc
if folded:
estep(u"Mise à jour des inclusions")
unfold_maybe(p, vcsdir)
### Créer la distribution si cela a été demandé
# vérifier la cohérence de certains paramètres
if p[asrc] or p[ab] or p[aj]:
if (p[ab] or p[aj]) and not p[jawop]:
ewarn(u"La création d'une archive binaire/javadoc n'est supportée que pour les projets WebObjects")
# avant de créer l'archive, unfold si on supporte update_inc
unfold_maybe(p)
# contruire l'archive du source
p[an] = '%s-%s%s' % (projname, p[sver], p[sas])
if ask_yesno(u"Créer l'archive %s.tgz?" % p[an], True, minlevel=I_INTER):
if p[bp] != '':
# si on a spécifié un chemin de base, inclure la racine de façon relative
paths[0] = ('', paths[0][1])
estep(u"Création de l'archive %s.tgz" % p[an])
create_archive(p, paths)
# construire l'archive du binaire
if p[ab] and p[jawop]:
archive_created = False
for suffix in ('', '.woa', '.framework'):
projdir = projname + suffix
p[an] = '%s-%s%s' % (projdir, p[sver], p[bas])
aprojdir = path.join(ap0, 'build', projdir)
if path.isdir(aprojdir):
if ask_yesno(u"Créer l'archive des binaires %s.tgz?" % p[an], True, minlevel=I_INTER):
estep(u"Création de l'archive %s.tgz" % p[an])
create_archive(p, [(projdir, aprojdir)], '')
archive_created = True
if not archive_created:
eerror(u"Imposssible de créer l'archive binaire: il faut construire le projet d'abord")
# construire l'archive de la documentation
if p[aj] and p[jawop]:
p[an] = '%s-%s%s' % (projname, p[sver], p[jdas])
aprojdir = path.join(ap0, 'build', 'api')
if path.isdir(aprojdir):
if ask_yesno(u"Créer l'archive de la documentation %s.tgz?" % p[an], True, minlevel=I_INTER):
estep(u"Création de l'archive %s.tgz" % p[an])
create_archive(p, [(projdir, aprojdir)])
else:
eerror(u"Répertoire de la javadoc introuvable. L'archive n'a pas été générée")
def run_release():
### Lire les arguments
options, longoptions = build_options(argsdesc)
opts, paths = get_args(None, options, longoptions)
p = {}
# todorc est traité à part, parce qu'il peut s'agir d'un répertoire relatif
index = 0
for opt, value in opts:
if opt in ('--todorc', ):
set_todorc(p, value)
del opts[index]
break
index = index + 1
### Vérifier et normaliser les chemins
if not paths: paths = ['.']
paths = normalize_paths(paths)
tp0, ap0 = paths[0]
curdir = os.getcwd()
if curdir[:len(ap0)] == ap0:
# nous sommes dans le répertoire de la distribution, se placer au-dessus
os.chdir(path.split(ap0)[0])
p[cd] = curdir
### Lecture des paramètres
# Si nécessaire, auto-détecter le type de projet
# ne pas autodétecter s'il existe un fichier .uinst.conf
rcf = ShConfigFile(path.join(ap0, '.uinst.conf'), raise_exception=False)
projname = projtype = None
projecttype_autodetected = False
autodetect_projecttype = not rcf.is_valid()
for opt, value in opts:
if is_auto(opt): autodetect_projecttype = True
elif isnot_auto(opt): autodetect_projecttype = False
if autodetect_projecttype:
projname, projtype = wo_projname_and_projtype(ap0)
if projtype in ('woapplication', 'woframework'):
projecttype_autodetected = True
set_jawop(p, True)
if projname is None:
# sinon, le nom de base de l'archive est le nom du répertoire
projname = path.split(ap0)[1]
p[pn] = projname
p[pt] = projtype
# Tout d'abord, essayer de lire les paramètres dans un fichier .uinst.conf
if rcf.is_valid():
for key, set_func in params_for_release_conf.items():
if not rcf.has_key(key): continue
value = rcf[key]
if key == ui:
# cas particulier: ui demande le répertoire de base
set_func(p, value, ap0)
else:
set_func(p, value)
# puis lire les paramètres en ligne de commande
for opt, value in opts:
if opt in ('-h', '--help'):
print_help()
sys.exit(0)
elif opt in ('-n', '--keep-version'): set_uver(p, False)
elif opt in ('-u', '--update-version'): set_uver(p, True)
elif opt in ('-v', '--set-version'): set_sver(p, value)
elif opt in ('--log-changes', ): set_log(p, True)
elif opt in ('--no-log-changes', ): set_log(p, False)
elif opt in ('--tag', ): set_tag(p, True)
elif opt in ('--no-tag', ): set_tag(p, False)
elif opt in ('--set-tag', ): set_stag(p, value)
elif opt in ('--include-license', ): set_lic(p, True)
elif opt in ('--no-include-license', ): set_lic(p, False)
elif opt in ('--set-license', ): set_slic(p, value)
elif opt in ('--ur', ): set_slic(p, 'ur_license.txt')
elif opt in ('--jclain', ): set_slic(p, 'jclain_license.txt')
elif opt in ('-c', '--archive-source'): set_asrc(p, True)
elif opt in ('-B', '--archive-binary'): set_ab(p, True)
elif opt in ('-J', '--archive-javadoc'): set_aj(p, True)
elif opt in ('-b', '--base-path'): set_bp(p, value)
elif opt in ('-x', '--exclude-names'): set_exn(p, value)
elif opt in ('-X', '--exclude-paths'): set_exp(p, value)
elif opt in ('-P', '--python-product'): set_pyp(p, True)
elif opt in ('-Z', '--zope-product'): set_zop(p, True)
elif opt in ('-W', '--jawo-product'): set_jawop(p, True)
elif opt in ('--update_inc', ): set_ui(p, True, ap0)
# compléter avec les valeurs par défaut des paramètres
for key, value in params_defaults.items():
if not p.has_key(key):
p[key] = value
# lancer l'application
try:
exitcode = apply(release, tuple([p] + paths))
except Exit, exitcode:
pass
sys.exit(exitcode)
if __name__ == '__main__':
run_release()