From b6ff411b8f2e9c681af06ae7a1afd38f4f71a7d6 Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Wed, 27 Sep 2017 21:58:29 +0400 Subject: [PATCH 01/14] maj doc uscrontab --- uscrontab | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/uscrontab b/uscrontab index b4f60f6..c963b67 100755 --- a/uscrontab +++ b/uscrontab @@ -197,6 +197,19 @@ Les lignes commençant par # sont des commentaires et sont ignorées La fonction elogto() permet de spécifier un fichier vers lequel toutes les sorties sont redirigées. + La fonction osvar() permet d'utiliser une variable de type oneshot définie + via l'option --osvar. Dans l'exemple suivant: + + 0 1 * * * + osvar FIRST=default SECOND + echo \"first is $FIRST and second is $SECOND\" + + En temps normal, FIRST vaut la valeur par défaut 'default' et SECOND vaut la + chaine vide ''. Si on appelle '$scriptname -v FIRST=1 -v SECOND=2' alors ces + variables auront la valeur spécifiée *une seule fois* à la prochaine + invocation avant de retrouver leur valeur par défaut à l'invocation + suivante. + OPTIONS -A, --install Installer une planification toutes les minutes du script dans la crontab From 5bf55e599951b8a9180881ac6d023a05b6f74137 Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Thu, 28 Sep 2017 10:43:04 +0400 Subject: [PATCH 02/14] bug --- uwatch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uwatch b/uwatch index 43e08ac..e91d8aa 100755 --- a/uwatch +++ b/uwatch @@ -81,7 +81,7 @@ rcount) duration="${1:-$DEFAULT_DURATION}" [ -n "$offset" ] && duration=$(($duration - $offset)) end=$(($start + $duration)) - TZ= setx until=date -d "@$end" +%H:%M:%S + setx until=date -d "@$end" +%H:%M:%S ;; esac From 312c7dcc1b00d19879a78bf12df0c9b444d96dfb Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Thu, 12 Oct 2017 19:47:53 +0400 Subject: [PATCH 03/14] ajouter des fonctions pour simplifier le check de la version de l'os et l'installation de paquets --- lib/ulib/debian | 11 +++++++++++ lib/ulib/sysinfos | 25 +++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/lib/ulib/debian b/lib/ulib/debian index c53d020..32a7ad7 100644 --- a/lib/ulib/debian +++ b/lib/ulib/debian @@ -60,6 +60,17 @@ function pkg_check_install() { pkg_installm "$@" } +function require_pkgs() { + # installer les packages spécifiés silencieusement et sans confirmation. + # si les packages n'existent pas ou ne peuvent pas être installé, c'est une + # erreur fatale. + if ! pkg_check "$@"; then + # essayer d'installer les packages + enote "Installation de packages $*" + pkg_install "$@" || die + fi +} + ################################################################################ # Gestion des services diff --git a/lib/ulib/sysinfos b/lib/ulib/sysinfos index 1b7c707..fd6f519 100644 --- a/lib/ulib/sysinfos +++ b/lib/ulib/sysinfos @@ -611,3 +611,28 @@ function on_default() { #XXX ici, on peut ajouter le code de support pour d'autres systèmes return 1 } + +################################################################################ +# Support uinst + +function require_debian() { + set -- -d debian "$@" + if check_sysinfos "$@"; then + urequire debian + return 0 + fi + local -a infos; local info + for info in "$@"; do + if ! [[ "$info" == -* ]]; then + infos=("${infos[@]}" "$info") + fi + done + local msg="Ce script n'est pas supporté sur $(get_sysinfos_desc)" + [ -n "$*" ] && msg="$msg +Il faut au moins l'un des systèmes suivants: ${infos[*]}" + [ -n "$UINST" -a -n "$ABORT" ] && touch "$ABORT" + die "$msg" +} +function require_stretch() { + require_debian -v stretch+ +} From ab8ede8c287824364c7b1db342a672e7e2c7cfe8 Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Thu, 12 Oct 2017 21:03:59 +0400 Subject: [PATCH 04/14] awk: support du format dd/mm/yy --- lib/ulib/base | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/ulib/base b/lib/ulib/base index 92db175..63e97d1 100644 --- a/lib/ulib/base +++ b/lib/ulib/base @@ -1883,6 +1883,12 @@ function __parse_date_fr(date, parts, y, m, d) { m = int(parts[2]) d = int(parts[1]) return mktime(sprintf("%04i %02i %02i 00 00 00 +0400", y, m, d)) + } else if (match(date, /([0-9][0-9]?)\/([0-9][0-9]?)\/([0-9][0-9])/, parts)) { + basey = int(strftime("%Y")); basey = basey - basey % 100 + y = basey + int(parts[3]) + m = int(parts[2]) + d = int(parts[1]) + return mktime(sprintf("%04i %02i %02i 00 00 00 +0400", y, m, d)) } return -1 } From f31f5f72ad0c3ce66e4975c21dca6cfa05746bb0 Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Fri, 13 Oct 2017 12:02:19 +0400 Subject: [PATCH 05/14] =?UTF-8?q?corriger=20un=20probl=C3=A8me=20de=20comp?= =?UTF-8?q?ilation=20sur=20OL6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/reptyr/ptrace.h | 2 +- reptyr.cgo | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/reptyr/ptrace.h b/lib/reptyr/ptrace.h index d981369..d4f09c4 100644 --- a/lib/reptyr/ptrace.h +++ b/lib/reptyr/ptrace.h @@ -19,9 +19,9 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include #include #include -#include enum child_state { ptrace_detached = 0, diff --git a/reptyr.cgo b/reptyr.cgo index bed81f0..18167d6 100755 --- a/reptyr.cgo +++ b/reptyr.cgo @@ -28,9 +28,9 @@ compilerArgs=-O2 -D_GNU_SOURCE -o $cacheDir/$executableFilename $cacheDir/$sourc * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ +#include #include #include -#include enum child_state { ptrace_detached = 0, From 9c5b46b372584edfbf854a78cb87d50bbcb59349 Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Mon, 16 Oct 2017 04:37:26 +0400 Subject: [PATCH 06/14] pyulib: ajouter ShConfig --- lib/pyulib/src/ulib/base/config.py | 72 ++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/lib/pyulib/src/ulib/base/config.py b/lib/pyulib/src/ulib/base/config.py index 3c63f2b..5d04774 100644 --- a/lib/pyulib/src/ulib/base/config.py +++ b/lib/pyulib/src/ulib/base/config.py @@ -11,14 +11,18 @@ value peut être placé entre double quotes ou simple quotes. Elle peut s'étend plusieurs lignes si elle est mise entre quotes, ou si elle se termine par \ """ -__all__ = ('ConfigFile', 'ShConfigFile', 'PListFile') +__all__ = ( + 'ConfigFile', 'ShConfigFile', 'PListFile', + 'ShConfig', +) -import os, string, re, types +import os, string, re, types, shlex from os import path -from base import make_prop, isseq, seqof, firstof +from base import odict, make_prop, isseq, seqof, firstof from uio import _s, _u from files import TextFile +from ulib.formats import unicodeF #################### # gestion des commentaires @@ -806,6 +810,68 @@ class PListFile(TextFile): _print_debug("XXX string=%s" % string) return string +################################################################################ +# classes utilisant shlex et l'interface odict + +class ShConfig(odict): + _formats = None + def __init__(self, config, formats=None): + super(ShConfig, self).__init__() + if formats is None: formats = {} + else: formats = dict(formats) + self.__dict__['_formats'] = formats + for name in self._formats.keys(): + self[name] = None + + inf = open(config, 'rb') + try: s = inf.read() + finally: inf.close() + parts = shlex.split(s, True) + self.parse(parts) + + def get_format(self, name): + format = None + if format is None: format = self._formats.get(name, None) + if format is None: format = self._formats.get(None, None) + if format is None: format = unicodeF + return format + + RE_ARRAY = re.compile(r'([^=]+)=\((.*)') + RE_ARRAY_LAST = re.compile(r'(.*)\)$') + RE_SCALAR = re.compile(r'([^=]+)=(.*)') + def parse(self, parts): + i = 0 + while i < len(parts): + part = parts[i] + i += 1 + amo = self.RE_ARRAY.match(part) + smo = self.RE_SCALAR.match(part) + if amo is not None: + array = [] + name, value = amo.groups() + format = self.get_format(name) + if value != '': array.append(format.parse(value)) + while i < len(parts): + value = parts[i] + i += 1 + mo = self.RE_ARRAY_LAST.match(value) + if mo is not None: + value = mo.group(1) + if value != '': array.append(format.parse(value)) + break + else: + array.append(format.parse(value)) + self[name] = array + elif smo is not None: + name, value = smo.groups() + format = self.get_format(name) + self[name] = format.parse(value) + else: + continue # ignorer l'erreur pour le moment + raise ValueError("%s: not a variable" % part) + +################################################################################ + if __name__ == '__main__': import doctest doctest.testmod() From 6130c2ff7ff18c589727d8f6bc6cf230fcbd8118 Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Tue, 17 Oct 2017 21:46:01 +0400 Subject: [PATCH 07/14] =?UTF-8?q?chrono.py:=200=20est=20=C3=A9quivalent=20?= =?UTF-8?q?=C3=A0=20la=20chaine=20vide?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- chrono.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/chrono.py b/chrono.py index fde9efe..03d1d88 100755 --- a/chrono.py +++ b/chrono.py @@ -32,6 +32,12 @@ def playSound(name=None): def isnum(i): return type(i) in (IntType, LongType) +RE_NUM = re.compile(r'\d+$') +def numof(s): + if isnum(s): return s + elif s is None: return None + elif RE_NUM.match(str(s)) is not None: return int(str(s)) + else: return s DEFAULT_TIMEOUT = '5' @@ -99,11 +105,13 @@ class Chrono: return Timedelta(seconds=timeout) def set_timeout(self, timeout=None): + if timeout == '': timeout = None if timeout is not None and not isnum(timeout): tmp = parse_desthour(str(timeout)) if tmp is None: tmp = parse_timeout(timeout) if tmp is None: tmp = int(timeout) * 60 timeout = tmp + if timeout == 0: timeout = None self.timeout = timeout if timeout is None: self.initial = '00:00' else: self.initial = self.__format(self.__delta(timeout)) @@ -334,7 +342,6 @@ d'arrivée, et que la durée est calculée automatiquement""") timeout = o.timeout if timeout is None: timeout = DEFAULT_TIMEOUT - elif timeout == '': timeout = None o.timeout = timeout run_chronometre(o.timeout, o.autostart) From 7bd0a95b3e83404613076e036939aba278e9b168 Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Tue, 17 Oct 2017 22:45:47 +0400 Subject: [PATCH 08/14] ufile: support des pattern regex --- ufile | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/ufile b/ufile index e45641b..22f9dda 100755 --- a/ufile +++ b/ufile @@ -12,7 +12,11 @@ Dans ce fichier, le tableau RULES contient des règles qui sont chacune de la forme pattern:destdir[:renamef] - pattern est au format glob et identifie les fichiers auxquels s'applique la - règle + règle, sauf si la chaine commence par / auquel cas il s'agit d'une expression + régulière reconnue par awk. Par exemple, les deux patterns suivants sont + équivalents: + [ab]cd*.pdf + /[ab]cd.*\\\\.pdf\$ - destdir est le répertoire de destination dans lequel classer le fichier - renamef est une fonction qui permet de supporter le renommage d'un fichier lors de son classement. Sa signature est 'renamef filename pf destdir' où @@ -107,7 +111,7 @@ function __set_dest() { setx dest=abspath "$dest" else __check_destdir "$destdir" "$rule" || return 1 - setx dest=joinp "$destdir" "$filename" + setx dest=joinp "$destdir" "$dest" fi upvar dest "$dest" return 0 @@ -223,7 +227,11 @@ for file in "${files[@]}"; do odestdir="$HOME" fi - eval "[[ \"\$filename\" == $(qwc "$pattern") ]]" || continue + if [ "${pattern#/}" != "$pattern" ]; then + awk -v filename="$filename" -v pattern="${pattern#/}" 'BEGIN { exit(filename ~ pattern? 0: 1) }' || continue + else + eval "[[ \"\$filename\" == $(qwc "$pattern") ]]" || continue + fi unset dest interaction=--DEFAULT-- From 489b31ded99c8353b17c8f08f218fec3ccf1baa9 Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Wed, 18 Oct 2017 06:37:44 +0400 Subject: [PATCH 09/14] =?UTF-8?q?moiso:=20am=C3=A9liorer=20l'ergonomie=20p?= =?UTF-8?q?our=20le=20d=C3=A9montage?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- moiso | 1 + 1 file changed, 1 insertion(+) diff --git a/moiso b/moiso index ae5347f..1039839 100755 --- a/moiso +++ b/moiso @@ -29,6 +29,7 @@ parse_opts "${PRETTYOPTS[@]}" \ image="$1" [ -n "$image" ] || die "Vous devez spécifier l'image iso à monter" +[ -d "$image" -a -f "$image.iso" ] && image="$image.iso" [ -f "$image" ] || die "$image: fichier introuvable" image="$(abspath "$image")" From 528a281e307572c6d80ece237f1646f367e40919 Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Wed, 18 Oct 2017 06:55:51 +0400 Subject: [PATCH 10/14] =?UTF-8?q?em:=20supprimer=20la=20sortie=20d'erreur?= =?UTF-8?q?=20par=20d=C3=A9faut.=20rendre=20configurable=20la=20g=C3=A9om?= =?UTF-8?q?=C3=A9trie?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- em | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/em b/em index f1e40e4..027106d 100755 --- a/em +++ b/em @@ -1,13 +1,19 @@ #!/bin/bash # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 -EMACS_GEOMETRY=150x50+0+67 +: "${EM_GEOMETRY:=150x50+0+67}" "${EM_STDERR:=}" # Essayer avec emacs emacs="$(which emacs 2>/dev/null)" if [ -x "$emacs" ]; then if [ -n "$DISPLAY" ]; then - exec "$emacs" -g "$EMACS_GEOMETRY" "$@" & + if [ -n "$EM_STDERR" ]; then + # ne pas supprimer la sortie erreur + exec "$emacs" -g "$EM_GEOMETRY" "$@" & + else + # supprimer la sortie d'erreur. les warnings de GTK sont horripilants + exec "$emacs" -g "$EM_GEOMETRY" "$@" 2>/dev/null & + fi exit 0 else exec "$emacs" -nw "$@" From 6c3ae24a6733aad55cd00fdd74ad70dee3bbf8d3 Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Thu, 19 Oct 2017 09:12:08 +0400 Subject: [PATCH 11/14] openurl: supprimer la sortie erreur pour cacher les warnings GTK --- openurl | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/openurl b/openurl index 3e8a4e0..b3fb3c9 100755 --- a/openurl +++ b/openurl @@ -3,6 +3,9 @@ source "$(dirname "$0")/lib/ulib/ulib" || exit 1 urequire DEFAULTS +# faut-il supprimer la sortie erreur? les warnings de GTK sont horripilants. +: "${OPENURL_STDERR:=}" + function display_help() { uecho "$scriptname: Ouvrir une URL dans un navigateur @@ -22,15 +25,20 @@ esac setx url="$scriptdir/caturl" "$1" || die if progexists xdg-open; then - exec xdg-open "$url" -elif progexists gnome-open; then - exec gnome-open "$url" -else - # si on est sur un MacOSX, essayer utiliser open - urequire sysinfos - if check_sysinfos -s macosx; then - exec open "$url" + if [ -n "$OPENURL_STDERR" ]; then + exec xdg-open "$url" + else + exec xdg-open "$url" 2>/dev/null fi +elif progexists gnome-open; then + if [ -n "$OPENURL_STDERR" ]; then + exec gnome-open "$url" + else + exec gnome-open "$url" 2>/dev/null + fi +elif check_sysinfos -s macosx; then + # si on est sur un MacOSX, utiliser open + exec open "$url" fi die "Impossible de trouver une méthode pour ouvrir l'url $url" From 9fb19b4cef314438a7310342a7c3ddb2f704a8a0 Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Thu, 19 Oct 2017 12:11:03 +0400 Subject: [PATCH 12/14] =?UTF-8?q?ulib/multiconf:=20am=C3=A9liorer=20conf?= =?UTF-8?q?=5Finstall()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/ulib/multiconf | 42 +++++++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/lib/ulib/multiconf b/lib/ulib/multiconf index 21b381a..eda18c9 100644 --- a/lib/ulib/multiconf +++ b/lib/ulib/multiconf @@ -24,8 +24,8 @@ function conf_auto() { # conf_auto NAME # est équivalent à: # conf_init VARS... - # conf_find_files __CONF_FILES ~/etc/default/NAME.conf ~/etc/NAME.d/*.conf - # conf_upgrade ~/etc/default/NAME.conf + # conf_find_files __CONF_FILES ~/etc/default/NAME ~/etc/NAME.d/*.conf + # conf_upgrade ~/etc/default/NAME # conf_load_files "${__CONF_FILES[@]}" # Pour supporter les scénarii où les fichiers de configuration sont ailleurs # que dans ~/etc/default, l'argument NAME peut être un chemin: @@ -43,8 +43,8 @@ function conf_auto() { conf_find_files __CONFS_FILES "$__name.conf" "$__name.d/*.conf" [ $# -gt 0 ] && conf_upgrade "$__name.conf" else - conf_find_files __CONFS_FILES "$HOME/etc/default/$__name.conf" "$HOME/etc/$__name.d/*.conf" - [ $# -gt 0 ] && conf_upgrade "$HOME/etc/default/$__name.conf" + conf_find_files __CONFS_FILES "$HOME/etc/default/$__name" "$HOME/etc/$__name.d/*.conf" + [ $# -gt 0 ] && conf_upgrade "$HOME/etc/default/$__name" fi conf_load_files "${__CONFS_FILES[@]}" } @@ -240,8 +240,9 @@ function conf_load_files() { } function conf_install() { - # USAGE: conf_install DEST SRCS... - # installer les fichiers de SRCS dans le répertoire standardisé DEST + # USAGE: conf_install DEST PREFIX SRCS... + # installer les fichiers de SRCS dans le répertoire standardisé DEST avec le + # préfixe PREFIX # ## destination # - si DEST est un nom sans chemin, e.g NAME, alors la destination est # ~/etc/NAME.d @@ -253,24 +254,43 @@ function conf_install() { # - si SRC est un fichier, le prendre tel quel # - si SRC est un répertoire, prendre tous les fichiers SRC/*.conf # - si SRC est un pattern, prendre tous les fichiers correspondant - local -a srcs + # s'il n'y a qu'une seule source, la destination sera DEST/PREFIX.conf + # sinon, la destination sera DEST/PREFIX-SRCNAME où SRCNAME est le nom du + # fichier source + # si PREFIX est vide, alors les fichiers sont copiés avec leur nom sans + # modification. + local -a tmpsrcs srcs local src dir wc local dest="$1"; shift + local prefix="$1"; shift [[ "$dest" == */* ]] || dest="$HOME/etc/$dest.d" mkdir -p "$dest" || return 1 for src in "$@"; do if [ -f "$src" ]; then - srcs=("$src") + array_add srcs "$src" elif [ -d "$src" ]; then - array_lsfiles srcs "$src" "*.conf" + array_lsfiles tmpsrcs "$src" "*.conf" + array_extend srcs tmpsrcs else splitwcs "$src" dir wc - array_lsfiles srcs "$dir" "$wc" + array_lsfiles tmpsrcs "$dir" "$wc" + array_extend srcs tmpsrcs fi + done + [ ${#srcs[*]} -gt 0 ] || return 0 + if [ -n "$prefix" ]; then + if [ ${#srcs[*]} -eq 1 ]; then + copy_update_ask -y "$src" "$dest/$prefix.conf" + else + for src in "${srcs[@]}"; do + copy_update_ask -y "$src" "$dest/$prefix-$(basename -- "$srcname")" + done + fi + else for src in "${srcs[@]}"; do copy_update_ask -y "$src" "$dest" done - done + fi } function conf_upgrade() { From 72d7d15cca3380cb10cfbac896407795c12a75f6 Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Thu, 19 Oct 2017 12:11:41 +0400 Subject: [PATCH 13/14] maj version ulib --- lib/ulib/.ulibver | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ulib/.ulibver b/lib/ulib/.ulibver index 651b787..4cf4c7d 100644 --- a/lib/ulib/.ulibver +++ b/lib/ulib/.ulibver @@ -1 +1 @@ -015000000 +015001000 From b07b894e018a8e56b3bee030c3fb96a5d86168d3 Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Thu, 19 Oct 2017 12:12:34 +0400 Subject: [PATCH 14/14] Init changelog & version 7.3.0 --- CHANGES.md | 16 ++++++++++++++++ VERSION.txt | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 2073d81..dc9a708 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,19 @@ +## Version 7.3.0 du 19/10/2017-12:12 + +* `72d7d15` maj version ulib +* `9fb19b4` ulib/multiconf: améliorer conf_install() +* `6c3ae24` openurl: supprimer la sortie erreur pour cacher les warnings GTK +* `528a281` em: supprimer la sortie d'erreur par défaut. rendre configurable la géométrie +* `489b31d` moiso: améliorer l'ergonomie pour le démontage +* `7bd0a95` ufile: support des pattern regex +* `6130c2f` chrono.py: 0 est équivalent à la chaine vide +* `9c5b46b` pyulib: ajouter ShConfig +* `f31f5f7` corriger un problème de compilation sur OL6 +* `ab8ede8` awk: support du format dd/mm/yy +* `312c7dc` ajouter des fonctions pour simplifier le check de la version de l'os et l'installation de paquets +* `5bf55e5` bug +* `b6ff411` maj doc uscrontab + ## Version 7.2.0 du 26/09/2017-17:01 * `1e576da` multiconf: rajouter conf_upgrade() dans conf_auto() diff --git a/VERSION.txt b/VERSION.txt index 0ee843c..1502020 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -7.2.0 +7.3.0