#!/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()