diff --git a/lib/ulib/multiconf b/lib/ulib/multiconf index 0efc083..e7b81ed 100644 --- a/lib/ulib/multiconf +++ b/lib/ulib/multiconf @@ -66,7 +66,16 @@ function conf_init() { # Les variables scalaires et chemin sont initialisées à la valeur vide ou à # la valeur spécifiée e.g.: # conf_init VAR=value MYPATH=a:b:c - # Les variables tableaux sont toujours initialisées à la valeur vide + # Les variables tableaux sont initialisées à la valeur vide sauf si le nom + # est suivi de '=' auquel cas la valeur actuelle est gardée, e.g. + # VS=(a b c); WS=(x y z) + # conf_init -a VS WS= + # echo_seta2 VS # VS=() + # echo_seta2 WS # WS=(x y z) + # Dans le cas des variables tableaux, la valeur après '=' est toujours + # ignorée. Pour simplifier la lecture, on peut rajouter une valeur marqueur + # comme 'current' ou 'actual', e.g + # conf_init -a VS=CurrentValues # L'option -s permet de revenir au mode scalaire # Note: il est possible d'associer une description à chaque variable ainsi @@ -121,7 +130,7 @@ function conf_init() { splitfsep "$1" // __var __desc case "$__type" in array) - eval "${__var%%=*}=()" + [ "${__var%%=*}" == "$__var" ] && eval "${__var%%=*}=()" array_addu __CONF_ARRAY_VARS "${__var%%=*}" array_del __CONF_PATH_VARS "${__var%%=*}" ;; @@ -160,81 +169,81 @@ function conf_find_files() { # - si on spécifie un pattern e.g path/to/*.conf alors tous les fichiers # correspondant au pattern sont pris # - sinon l'argument est ignoré - local __conf_dest="$1"; shift - local -a __conf_files - local __conf_spec __conf_dir __conf_wc - array_new "$__conf_dest" - for __conf_spec in "$@"; do - if [ -f "$__conf_spec" ]; then - array_add "$__conf_dest" "$__conf_spec" + local __dest="$1"; shift + local -a __files + local __spec __dir __wc + array_new "$__dest" + for __spec in "$@"; do + if [ -f "$__spec" ]; then + array_add "$__dest" "$__spec" continue - elif [ -d "$__conf_spec" ]; then - __conf_spec="$__conf_spec/*.conf" + elif [ -d "$__spec" ]; then + __spec="$__spec/*.conf" fi - splitwcs "$__conf_spec" __conf_dir __conf_wc - array_lsfiles __conf_files "${__conf_dir:-.}" "$__conf_wc" - array_extend "$__conf_dest" __conf_files + splitwcs "$__spec" __dir __wc + array_lsfiles __files "${__dir:-.}" "$__wc" + array_extend "$__dest" __files done } function conf_load_files() { # sourcer les fichiers spécifiés en faisant ce qui est nécessaire pour que # les variables de __CONF_ARRAY_VARS soient correctement traitées. - local -a __conf_backups __conf_values - local __conf_file __conf_name __conf_i __conf_backup __conf_bn __conf_bv - for __conf_file in "$@"; do + local -a __backups __values + local __file __name __i __backup __bn __bv + for __file in "$@"; do # faire une copie de sauvegarde puis supprimer les variables tableaux - __conf_backups=() - for __conf_name in "${__CONF_ARRAY_VARS[@]}" "${__CONF_PATH_VARS[@]}"; do - __conf_backup="$(declare -p "$__conf_name" 2>/dev/null)" - if [ -z "$__conf_backup" ]; then - __conf_backup="$__conf_name=" + __backups=() + for __name in "${__CONF_ARRAY_VARS[@]}" "${__CONF_PATH_VARS[@]}"; do + __backup="$(declare -p "$__name" 2>/dev/null)" + if [ -z "$__backup" ]; then + __backup="$__name=" else # faire une correction de l'expression parce que la commande # affichée par declare -p est différente entre bash 4.3 et bash # 4.4 pour les tableaux. soit le tableau array=(a b) # - bash 4.3 affiche declare -a array='([0]="a" [1]="b")' # - bash 4.4 affiche declare -a array=([0]="a" [1]="b") - __conf_backup="${__conf_backup#declare }" - __conf_bn="${__conf_backup%% *}" - __conf_bv="${__conf_backup#* }" - if [[ "$__conf_bn" == -*a* ]]; then - __conf_bn="${__conf_bv%%=*}" - __conf_bv="${__conf_bv#*=}" - if [ "${__conf_bv:0:2}" == "'(" -a "${__conf_bv: -2:2}" == ")'" ]; then - __conf_backup="$__conf_bn=$(eval "echo $__conf_bv")" + __backup="${__backup#declare }" + __bn="${__backup%% *}" + __bv="${__backup#* }" + if [[ "$__bn" == -*a* ]]; then + __bn="${__bv%%=*}" + __bv="${__bv#*=}" + if [ "${__bv:0:2}" == "'(" -a "${__bv: -2:2}" == ")'" ]; then + __backup="$__bn=$(eval "echo $__bv")" else - __conf_backup="$__conf_bn=$__conf_bv" + __backup="$__bn=$__bv" fi else - __conf_backup="$__conf_bv" + __backup="$__bv" fi fi - __conf_backups=("${__conf_backups[@]}" "$__conf_backup") - unset "$__conf_name" + __backups=("${__backups[@]}" "$__backup") + unset "$__name" done # charger le fichier - source "$__conf_file" + source "$__file" # puis restaurer les variables ou les fusionner avec une éventuelle nouvelle valeur - __conf_i=0 - for __conf_name in "${__CONF_ARRAY_VARS[@]}" "${__CONF_PATH_VARS[@]}"; do - __conf_backup="${__conf_backups[$__conf_i]}" - if [ -n "$(declare -p "$__conf_name" 2>/dev/null)" ]; then + __i=0 + for __name in "${__CONF_ARRAY_VARS[@]}" "${__CONF_PATH_VARS[@]}"; do + __backup="${__backups[$__i]}" + if [ -n "$(declare -p "$__name" 2>/dev/null)" ]; then # la variable a été redéfinie, la fusionner avec la précédente valeur - if array_contains __CONF_ARRAY_VARS "$__conf_name"; then - array_copy __conf_values "$__conf_name" - eval "$__conf_backup" - array_extend "$__conf_name" __conf_values - elif array_contains __CONF_PATH_VARS "$__conf_name"; then - __conf_values="${!__conf_name}" - eval "$__conf_backup" - uaddpath "$__conf_values" "$__conf_name" + if array_contains __CONF_ARRAY_VARS "$__name"; then + array_copy __values "$__name" + eval "$__backup" + array_extend "$__name" __values + elif array_contains __CONF_PATH_VARS "$__name"; then + __values="${!__name}" + eval "$__backup" + uaddpath "$__values" "$__name" fi else # la variable n'a pas été redéfinie, restaurer la précédente valeur - eval "$__conf_backup" + eval "$__backup" fi - __conf_i=$(($__conf_i + 1)) + __i=$(($__i + 1)) done done } @@ -296,34 +305,80 @@ function conf_install() { } 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 + # USAGE: conf_upgrade DEST [VARS...] + # Si les variables VARS... sont spécifiées, on appelle au préalable + # conf_init() + local __dest="$1"; shift + local __desc __namevalue __name __value + + [ $# -gt 0 ] && conf_init "$@" # 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}" == "#" ] && prefix="$desc" + if [ ! -f "$__dest" ]; then + local __prefix + for __desc in "${__CONF_DESCS[@]}"; do + [ "${__desc:0:1}" == "#" ] && __prefix="$__desc" break done - [ ${#prefix} -gt 0 ] || prefix="# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8" - echo "$prefix" >"$dest" + [ ${#__prefix} -gt 0 ] || __prefix="# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8" + echo "$__prefix" >"$__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" + 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" + if array_contains __CONF_ARRAY_VARS "$__name"; then + echo_seta2 "$__name" >>"$__dest" + else + echo_setv "$__name" "$__value" >>"$__dest" + fi fi done } + +function conf_update() { + # USAGE: conf_update [-n] DEST VARS... + # Pour chaque variable mentionnée, le fichier DEST est mis à jour avec sa + # valeur actuelle. Le fichier doit exister, et conf_init() *doit* avoir été + # appelé au préalable. + # Avec l'option -n, ne pas modifier l'état activé/désactivé des variables + # dans le fichier de configuration. En d'autres termes, si la variable était + # commentée dans le fichier, la laisser commentée, mais mettre quand même à + # jour la valeur + local enable=1 + if [ "$1" == -n ]; then + enable= + shift + fi + local dest="$1"; shift + [ -f "$dest" ] || return 1 + local from to + ac_set_tmpfile destf + ac_set_tmpfile destt + cat "$dest" >"$destf" + + local name setvar + for name in "$@"; do + if array_contains __CONF_ARRAY_VARS "$name"; then + setx setvar=echo_seta2 "$name" + else + setx setvar=echo_setv2 "$name" + fi + awkrun <"$destf" >"$destt" name="$name" setvar="$setvar" enable:int="$enable" ' +$0 ~ "^\\s*#*(\\s*export)?\\s*" name "=" { + match($0, "^(\\s*#*)((\\s*export)?\\s*)" name "=", vs) + if (enable) print vs[2] setvar + else print vs[1] vs[2] setvar + next +} +{ print }' + cat "$destt" >"$destf" + done + cat "$destf" >"$dest" + ac_clean "$destf" "$destt" + return 0 +}