diff --git a/TODO.md b/TODO.md index 58b74bb..32dea67 100644 --- a/TODO.md +++ b/TODO.md @@ -1,84 +1,3 @@ # TODO -Faire des fonctions pour faciliter la gestion de configuration par défaut - -La configuration est décrite dans un tableau nommé CONFIG par défaut -~~~ -CONFIG=( - "-*- coding: utf-8 mode: sh -*-" - "# description de la variable NAME" - NAME=default_value - "# description de la variable LONG" - "# sur plusieurs lignes" - LONG="very long value" -) -~~~ - -* si le premier élément commence par `-*-` alors il contient les informations - pour générer la ligne de mode pour le fichier de config s'il faut le créer de - toutes pièces. -* chaque élément qui commence par `#` est une description de la variable qui - suit. plusieurs éléments sont fusionnés le cas échéant. -* les éléments de la forme NAME=DEFAULT_VALUE définissent une variable et sa - valeur par défaut. - -A partir de ce tableau, la fonction upgrade_config() permet de créer un fichier -de config s'il n'existe pas, ou de la mettre à jour avec de nouvelles variables -s'il existe. Soit la commande suivante -~~~ -upgrade_config path/to/config.conf CONFIG -~~~ - -Si le fichier config.conf n'existe pas, il est créé ainsi: -~~~ -# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 - -# description de la variable NAME -#NAME=default_value - -# description de la variable LONG -# sur plusieurs lignes -#LONG="very long value" -~~~ - -Si le fichier config contenait ceci: -~~~ -# -*- coding: utf-8 mode: conf -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 - -# description de la variable LONG -LONG="my value" -~~~ -il est transformé en ceci, c'est à dire que la définition manquante de NAME est -rajoutée: -~~~ -# -*- coding: utf-8 mode: conf -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 - -# description de la variable LONG -LONG="my value" - -# description de la variable NAME -#NAME=default_value -~~~ - -A partir du tableau, la fonction load_config() permet de charger le fichier de -config en ne sélectionnant que les variables qui sont mentionnées dans le -tableau. Soit le fichier de configuration suivant -~~~ -NAME=value -LONG=something -ROGUE=data -~~~ -et les commandes suivantes -~~~ -NAME=x -LONG=y -ROGUE=inchangée -load_config path/to/config.conf CONFIG -echo "NAME=$NAME, LONG=$LONG, ROGUE=$ROGUE" -~~~ -le résultat est le suivant -~~~ -NAME=value, LONG=something, ROGUE=inchangée -~~~ - -*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary \ No newline at end of file diff --git a/lib/ulib/multiconf b/lib/ulib/multiconf index 1059582..f2a2bb6 100644 --- a/lib/ulib/multiconf +++ b/lib/ulib/multiconf @@ -9,7 +9,7 @@ function conf_local() { # par les fonctions conf_* # cela permet d'utiliser ces fonctions à l'intérieur d'autres fonctions sans # polluer l'espace de nom - echo "local -a __CONF_ARRAY_VARS __CONF_PATH_VARS" + echo "local -a __CONF_DESCS __CONF_ARRAY_VARS __CONF_PATH_VARS" } function conf_auto() { @@ -46,7 +46,9 @@ function conf_auto() { function conf_init() { # définir les variables attendues lors du chargement des fichiers de - # configuration par conf_load_files + # configuration par conf_load_files() + # Si cette fonction n'a pas d'argument, le contenu du tableau CONFIG s'il + # est existe est utilisé # par défaut, les variables sont en mode scalaire: la définition d'une # variable écrase la valeur précédente. Avec l'option -a les variables sont # en mode tableau: les nouvelles valeurs sont rajoutées à la fin du tableau. @@ -61,28 +63,70 @@ function conf_init() { # conf_init VAR=value MYPATH=a:b:c # Les variables tableaux sont toujours initialisées à la valeur vide # L'option -s permet de revenir au mode scalaire + + # Note: il est possible d'associer une description à chaque variable ainsi + # qu'un en-tête, ce qui permet de construire le fichier de configuration ou + # de mettre à jour un fichier existant avec conf_upgrade(). Par exemple, les + # commandes suivantes: + # CONFIG=( + # "# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8" + # "# configurer l'application" + # -s + # "NAME=payet//nom de l'administrateur" + # "MAIL=admin@host.tld//mail de contact" + # -a + # "HOSTS//hôtes autorisés à se connecter" + # ) + # conf_init + # permettent de générer automatiquement le fichier de configuration suivant: + # # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 + # # configurer l'application + # + # # nom de l'administrateur + # #NAME=payet + # + # # mail de contact + # #MAIL=admin@host.tld + # + # # hôtes autorisés à se connecter + # #HOSTS=() + __CONF_DESCS=() __CONF_ARRAY_VARS=() __CONF_PATH_VARS=() - local __var __type=scalar + local __type=scalar __initial=1 __prefix __var __desc + [ $# -eq 0 ] && is_array CONFIG && set -- "${CONFIG[@]}" while [ $# -gt 0 ]; do + if [ -n "$__initial" ]; then + if [ "${1:0:1}" == "#" ]; then + [ ${#__prefix} -gt 0 ] && __prefix="$__prefix"$'\n' + __prefix="$__prefix$1" + shift + continue + else + [ -n "$__prefix" ] && array_add __CONF_DESCS "$__prefix" + __initial= + fi + fi case "$1" in -a|--array) __type=array;; -p|--path) __type=path;; -s|--scalar) __type=scalar;; *) + array_add __CONF_DESCS "$1" + splitfsep "$1" // __var __desc case "$__type" in array) - eval "${1%%=*}=()" - array_addu __CONF_ARRAY_VARS "${1%%=*}" - array_del __CONF_PATH_VARS "${1%%=*}" + eval "${__var%%=*}=()" + array_addu __CONF_ARRAY_VARS "${__var%%=*}" + array_del __CONF_PATH_VARS "${__var%%=*}" ;; path) - setv "$1" - array_addu __CONF_PATH_VARS "${1%%=*}" - array_del __CONF_ARRAY_VARS "${1%%=*}" + setv "$__var" + array_addu __CONF_PATH_VARS "${__var%%=*}" + array_del __CONF_ARRAY_VARS "${__var%%=*}" ;; scalar) - setv "$1" + setv "$__var" ;; esac ;; @@ -223,3 +267,35 @@ function conf_install() { done done } + +function conf_upgrade() { + # USAGE: conf_upgrade DEST VARS... + # Si les variables VARS... sont spécifiées, on appelle au préalable conf_init() + local dest="$1"; shift + if [ $# -gt 0 ]; then + eval "$(conf_local)" + conf_init "$@" + fi + local desc namevalue name value + # calculer le préfixe et initialiser le fichier le cas échéant + if [ ! -f "$dest" ]; then + local prefix + for desc in "${__CONF_DESCS[@]}"; do + [ "${desc:0:1}" == "#" ] && echo "$desc" >"$dest" + break + done + >>"$dest" + fi + # vérifier la présence de chaque variable + for desc in "${__CONF_DESCS[@]}"; do + [ "${desc:0:1}" == "#" ] && continue + splitfsep "$desc" // namevalue desc + splitvar "$namevalue" name value + if ! grep -qE "^\s*#*(\s*export)?\s*$name=" "$dest"; then + echo >>"$dest" + [ -n "$desc" ] && echo "# $desc" >>"$dest" + echo -n "#" >>"$dest" + echo_setv "$name" "$value" >>"$dest" + fi + done +}