From f4725018aa5fab5ae80ec54fe598c3f26d8f9883 Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Wed, 13 Sep 2017 08:13:11 +0400 Subject: [PATCH 1/6] squelette initial --- lib/ulib/multiconf | 77 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 lib/ulib/multiconf diff --git a/lib/ulib/multiconf b/lib/ulib/multiconf new file mode 100644 index 0000000..c7446e2 --- /dev/null +++ b/lib/ulib/multiconf @@ -0,0 +1,77 @@ +##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 +## Gestion de fichiers de configuration et de répertoires de configuration +##@cooked nocomments + +function conf_local() { + # afficher les commandes pour définir comme locales les variables utilisées + # par les fonctions conf_* + echo "local -a __CONF_ARRAY_VARS" +} + +function conf_auto() { + # charger la configuration pour l'outil $1 avec les variables $2..@ + + # conf_init n'est appelé que si des variables sont spécifiées, ce qui permet + # d'appeler conf_init au préalable si une configuration spécifique doit être + # faite. + # Ainsi: + # conf_auto NAME VARS... + # est équivalent à: + # conf_init VARS... + # conf_auto NAME + # est équivalent à: + # conf_init VARS... + # conf_resolve __CONF_FILES ~/etc/default/NAME.conf ~/etc/NAME.d/*.conf + # conf_load "${__CONF_FILES[@]}" + + local __name="$1"; shift + [ -n "$__name" ] || return 1 + [ $# -gt 0 ] && conf_init "$@" + local -a __CONF_FILES + conf_resolve __CONFS_FILES "$HOME/etc/default/$name.conf" "$HOME/$name.d/*.conf" + conf_load "${__CONFS_FILES[@]}" +} + +function conf_init() { + # définir les variables attendues pour chargement par conf_load + # 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. + # dans l'exemple suivant: + # conf_init NAME VALUE -a SRCDIRS DESTDIRS + # NAME et VALUE sont scalaires alors que SRCDIRS et DESTDIRS sont tableaux + # Les variables sont initialisées à zéro ou à la valeur spécifiée, e.g + # conf_init VAR=value + # L'option -s permet de revenir au mode scalaire + __CONF_ARRAY_VARS=() + local __var __array + while [ $# -gt 0 ]; do + case "$1" in + -a|--array) __array=1;; + -s|--scalar) __array=;; + *) + setv "$1" + [ -n "$__array" ] && array_addu __CONF_ARRAY_VARS "${1%%=*}" + ;; + esac + shift + done +} + +function conf_resolve() { + # initialiser le tableau $1 avec les fichiers de configuration correspondant + # aux arguments $2..@ + # - si on spécifie un fichier, il est pris tel quel s'il existe + # - si on spécifie un répertoire, tous les fichiers *.conf de ce répertoire + # sont pris + # - 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é + : +} + +function conf_load() { + # 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. + : +} From 72e0c369c333eecb97ec5a22c5995d41c88b498a Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Thu, 14 Sep 2017 08:28:40 +0400 Subject: [PATCH 2/6] maj doc --- lib/ulib/multiconf | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/ulib/multiconf b/lib/ulib/multiconf index c7446e2..ac9efb8 100644 --- a/lib/ulib/multiconf +++ b/lib/ulib/multiconf @@ -1,6 +1,7 @@ ##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 ## Gestion de fichiers de configuration et de répertoires de configuration ##@cooked nocomments +uprovide multiconf function conf_local() { # afficher les commandes pour définir comme locales les variables utilisées @@ -10,7 +11,6 @@ function conf_local() { function conf_auto() { # charger la configuration pour l'outil $1 avec les variables $2..@ - # conf_init n'est appelé que si des variables sont spécifiées, ce qui permet # d'appeler conf_init au préalable si une configuration spécifique doit être # faite. @@ -23,6 +23,13 @@ function conf_auto() { # conf_init VARS... # conf_resolve __CONF_FILES ~/etc/default/NAME.conf ~/etc/NAME.d/*.conf # conf_load "${__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: + # conf_auto PATH/TO/NAME VARS... + # est équivalent à: + # conf_init VARS... + # conf_resolve __CONF_FILES PATH/TO/NAME.conf PATH/TO/NAME.d/*.conf + # conf_load "${__CONF_FILES[@]}" local __name="$1"; shift [ -n "$__name" ] || return 1 @@ -40,7 +47,7 @@ function conf_init() { # dans l'exemple suivant: # conf_init NAME VALUE -a SRCDIRS DESTDIRS # NAME et VALUE sont scalaires alors que SRCDIRS et DESTDIRS sont tableaux - # Les variables sont initialisées à zéro ou à la valeur spécifiée, e.g + # Les variables sont initialisées à la valeur vide ou à la valeur spécifiée: # conf_init VAR=value # L'option -s permet de revenir au mode scalaire __CONF_ARRAY_VARS=() From c9886925a3843c231d8d5c55c1b8b5fde67b1221 Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Thu, 14 Sep 2017 21:51:23 +0400 Subject: [PATCH 3/6] =?UTF-8?q?fin=20impl=C3=A9mentation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/ulib/multiconf | 68 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 7 deletions(-) diff --git a/lib/ulib/multiconf b/lib/ulib/multiconf index ac9efb8..91f4e64 100644 --- a/lib/ulib/multiconf +++ b/lib/ulib/multiconf @@ -6,6 +6,8 @@ uprovide multiconf function conf_local() { # afficher les commandes pour définir comme locales les variables utilisées # 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" } @@ -35,20 +37,27 @@ function conf_auto() { [ -n "$__name" ] || return 1 [ $# -gt 0 ] && conf_init "$@" local -a __CONF_FILES - conf_resolve __CONFS_FILES "$HOME/etc/default/$name.conf" "$HOME/$name.d/*.conf" + if [[ "$__name" == */* ]]; then + conf_resolve __CONFS_FILES "$__name.conf" "$__name.d/*.conf" + else + conf_resolve __CONFS_FILES "$HOME/etc/default/$__name.conf" "$HOME/etc/$__name.d/*.conf" + fi conf_load "${__CONFS_FILES[@]}" } function conf_init() { - # définir les variables attendues pour chargement par conf_load + # définir les variables attendues lors du chargement des fichiers de + # configuration par conf_load # 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. # dans l'exemple suivant: # conf_init NAME VALUE -a SRCDIRS DESTDIRS # NAME et VALUE sont scalaires alors que SRCDIRS et DESTDIRS sont tableaux - # Les variables sont initialisées à la valeur vide ou à la valeur spécifiée: + # Les variables scalaires sont initialisées à la valeur vide ou à la valeur + # spécifiée e.g.: # conf_init VAR=value + # Les variables tableaux sont toujours initialisées à la valeur vide # L'option -s permet de revenir au mode scalaire __CONF_ARRAY_VARS=() local __var __array @@ -57,8 +66,12 @@ function conf_init() { -a|--array) __array=1;; -s|--scalar) __array=;; *) - setv "$1" - [ -n "$__array" ] && array_addu __CONF_ARRAY_VARS "${1%%=*}" + if [ -n "$__array" ]; then + eval "${1%%=*}=()" + array_addu __CONF_ARRAY_VARS "${1%%=*}" + else + setv "$1" + fi ;; esac shift @@ -74,11 +87,52 @@ function conf_resolve() { # - 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" + continue + elif [ -d "$__conf_spec" ]; then + __conf_spec="$__conf_spec/*.conf" + fi + splitwcs "$__conf_spec" __conf_dir __conf_wc + array_lsfiles __conf_files "${__conf_dir:-.}" "$__conf_wc" + array_extend "$__conf_dest" __conf_files + done } function conf_load() { # 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 + for __conf_file in "$@"; do + # faire une copie de sauvegarde puis supprimer les variables tableaux + __conf_backups=() + for __conf_name in "${__CONF_ARRAY_VARS[@]}"; do + __conf_backups=("${__conf_backups[@]}" "$(declare -p "$__conf_name")") + unset "$__conf_name" + done + # charger le fichier + source "$__conf_file" + # puis restaurer les variables ou les fusionner avec une éventuelle nouvelle valeur + __conf_i=0 + for __conf_name in "${__CONF_ARRAY_VARS[@]}"; do + __conf_backup="${__conf_backups[$__conf_i]}" + __conf_backup="${__conf_backup#declare * }" + if [ -n "$(declare -p "$__conf_name" 2>/dev/null)" ]; then + # la variable a été redéfinie, la fusionner avec la précédente valeur + array_copy __conf_values "$__conf_name" + eval "$__conf_backup" + array_extend "$__conf_name" __conf_values + else + # la variable n'a pas été redéfinie, restaurer la précédente valeur + eval "$__conf_backup" + fi + __conf_i=$(($__conf_i + 1)) + done + done } From 7d1ec9034551835c6ab3495c15e49df38174ad94 Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Thu, 14 Sep 2017 22:21:34 +0400 Subject: [PATCH 4/6] simplifier l'API --- lib/ulib/multiconf | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/lib/ulib/multiconf b/lib/ulib/multiconf index 91f4e64..a6ff13c 100644 --- a/lib/ulib/multiconf +++ b/lib/ulib/multiconf @@ -23,31 +23,29 @@ function conf_auto() { # conf_auto NAME # est équivalent à: # conf_init VARS... - # conf_resolve __CONF_FILES ~/etc/default/NAME.conf ~/etc/NAME.d/*.conf - # conf_load "${__CONF_FILES[@]}" + # conf_find_files __CONF_FILES ~/etc/default/NAME.conf ~/etc/NAME.d/*.conf + # 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: # conf_auto PATH/TO/NAME VARS... # est équivalent à: # conf_init VARS... - # conf_resolve __CONF_FILES PATH/TO/NAME.conf PATH/TO/NAME.d/*.conf - # conf_load "${__CONF_FILES[@]}" - + # conf_find_files __CONF_FILES PATH/TO/NAME.conf PATH/TO/NAME.d/*.conf + # conf_load_files "${__CONF_FILES[@]}" local __name="$1"; shift [ -n "$__name" ] || return 1 [ $# -gt 0 ] && conf_init "$@" local -a __CONF_FILES if [[ "$__name" == */* ]]; then - conf_resolve __CONFS_FILES "$__name.conf" "$__name.d/*.conf" + conf_load "$__name.conf" "$__name.d/*.conf" else - conf_resolve __CONFS_FILES "$HOME/etc/default/$__name.conf" "$HOME/etc/$__name.d/*.conf" + conf_load "$HOME/etc/default/$__name.conf" "$HOME/etc/$__name.d/*.conf" fi - conf_load "${__CONFS_FILES[@]}" } function conf_init() { # définir les variables attendues lors du chargement des fichiers de - # configuration par conf_load + # configuration par conf_load_files # 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. @@ -78,7 +76,18 @@ function conf_init() { done } -function conf_resolve() { +function conf_load() { + # charger les fichiers de configuration spécifiés + # conf_load SPECS... + # est équivalent à: + # conf_find_files __CONF_FILES SPECS... + # conf_load_files "${__CONF_FILES[@]}" + local -a __CONF_FILES + conf_find_files __CONFS_FILES "$@" + conf_load_files "${__CONFS_FILES[@]}" +} + +function conf_find_files() { # initialiser le tableau $1 avec les fichiers de configuration correspondant # aux arguments $2..@ # - si on spécifie un fichier, il est pris tel quel s'il existe @@ -104,7 +113,7 @@ function conf_resolve() { done } -function conf_load() { +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 From 0372a5c44c03577ab3944fad18c7a50f973bcf87 Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Thu, 14 Sep 2017 22:21:53 +0400 Subject: [PATCH 5/6] ufile charge les fichiers de ~/etc/ufile.d/ --- lib/default/ufile | 4 ---- ufile | 20 ++++---------------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/lib/default/ufile b/lib/default/ufile index cb065f1..755d24a 100644 --- a/lib/default/ufile +++ b/lib/default/ufile @@ -1,9 +1,5 @@ # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 -# Fichiers externes à inclure. Chacun de ces fichiers peut contenir des -# définitions de fonctions et de la variables RULES -INCLUDES=() - # Règles pour le classement des fichiers. Chaque règle est de la forme # pattern:destdir[:renamef] RULES=() diff --git a/ufile b/ufile index b87b156..9640f61 100755 --- a/ufile +++ b/ufile @@ -1,7 +1,7 @@ #!/bin/bash # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 source "$(dirname "$0")/lib/ulib/ulib" || exit 1 -urequire DEFAULTS +urequire DEFAULTS multiconf function display_help() { uecho "$scriptname: classer des fichiers selon certains règles @@ -126,8 +126,7 @@ parse_args "$@"; set -- "${args[@]}" ## charger toutes les règles -RULES=() -INCLUDES=() +conf_init -a RULES if [ -n "$config" ]; then if [ "$action" != edit ]; then # le fichier doit exister, sauf en mode édition où il sera créé s'il @@ -140,22 +139,11 @@ if [ -n "$config" ]; then else set_defaults ufile fi -array_copy rules RULES -for include in "${INCLUDES[@]}"; do - if [ -f "$include" ]; then - RULES=() - source "$include" - array_extend rules RULES - else - ewarn "$include: fichier introuvable" - fi -done -array_copy RULES rules +conf_load "$HOME/etc/ufile.d/*.conf" ## actions particulières if [ "$action" == list ]; then - echo "# $(echo_seta2 INCLUDES)" array_to_lines RULES exit 0 elif [ "$action" == edit ]; then @@ -180,7 +168,7 @@ else fi [ $# -gt 0 ] || die "Vous devez spécifier des fichiers à classer" -[ ${#RULES[*]} -gt 0 ] || die "Vous devez spécifier des règles pour le classement des fichiers dans ~/etc/default/ufile" +[ ${#RULES[*]} -gt 0 ] || die "Vous devez spécifier des règles pour le classement des fichiers dans ~/etc/default/ufile ou ~/etc/ufile.d/*.conf" # vérifier les règles for rule in "${RULES[@]}"; do From a916180ef2d49e4766feea4e44287f658fc59f81 Mon Sep 17 00:00:00 2001 From: Jephte Clain Date: Thu, 14 Sep 2017 23:11:26 +0400 Subject: [PATCH 6/6] =?UTF-8?q?ajouter=20conf=5Finstall=20pour=20installer?= =?UTF-8?q?=20les=20fichiers=20de=20configuration=20dans=20un=20r=C3=A9per?= =?UTF-8?q?toire=20standardis=C3=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/ulib/install | 16 ++++++++++++++-- lib/ulib/multiconf | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/lib/ulib/install b/lib/ulib/install index 89de2fc..014bb33 100644 --- a/lib/ulib/install +++ b/lib/ulib/install @@ -111,7 +111,15 @@ function copy_update_ask() { # Copier ou mettre à jour le fichier $1 vers le fichier $2. # Si le fichier existe déjà, la différence est affichée, et une confirmation # est demandée pour l'écrasement du fichier. + # si $1 commence par '-' alors on s'en sert comme option pour configurer le + # niveau d'interaction pour demander la confirmation. les paramètres sont + # alors décalés # Retourner vrai si le fichier a été copié sans erreur. + local interopt=-c + if [[ "$1" == -* ]]; then + interopt="$1" + shift + fi local src="$1" dest="$2" [ -d "$dest" ] && dest="$dest/$(basename -- "$src")" @@ -119,10 +127,14 @@ function copy_update_ask() { [ -f "$dest" ] || copy_replace "$src" "$dest" if testdiff "$src" "$dest"; then - diff -u "$dest" "$src" - if ask_yesno -c "Voulez-vous remplacer $(ppath "$dest") par la nouvelle version?" C; then + check_interaction "$interopt" && diff -u "$dest" "$src" + if ask_yesno "$interopt" "Voulez-vous remplacer $(ppath "$dest") par la nouvelle version?" C; then copy_replace "$src" "$dest" "$3" return $? + elif ! check_interaction "$interopt"; then + ewarn "Les mises à jours suivantes sont disponibles:" + diff -u "$dest" "$src" + ewarn "Le fichier $(ppath "$dest") n'a pas été mis à jour" fi fi return 1 diff --git a/lib/ulib/multiconf b/lib/ulib/multiconf index a6ff13c..0fda462 100644 --- a/lib/ulib/multiconf +++ b/lib/ulib/multiconf @@ -2,6 +2,7 @@ ## Gestion de fichiers de configuration et de répertoires de configuration ##@cooked nocomments uprovide multiconf +urequire install function conf_local() { # afficher les commandes pour définir comme locales les variables utilisées @@ -145,3 +146,37 @@ function conf_load_files() { done done } + +function conf_install() { + # USAGE: conf_install DEST SRCS... + # installer les fichiers de SRCS dans le répertoire standardisé DEST + # ## destination + # - si DEST est un nom sans chemin, e.g NAME, alors la destination est + # ~/etc/NAME.d + # - si DEST est un nom avec chemin, alors la valeur est prise telle quelle + # comme destination, et le répertoire est créé le cas échéant. + # Si un fichier existe déjà dans la destination, afficher une demande de + # confirmation avant de l'écraser + # ## source + # - 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 + local src dir wc + local dest="$1"; shift + [[ "$dest" == */* ]] || dest="$HOME/etc/$dest.d" + mkdir -p "$dest" || return 1 + for src in "$@"; do + if [ -f "$src" ]; then + srcs=("$src") + elif [ -d "$src" ]; then + array_lsfiles srcs "$src" "*.conf" + else + splitwcs "$src" dir wc + array_lsfiles srcs "$dir" "$wc" + fi + for src in "${srcs[@]}"; do + copy_update_ask -y "$src" "$dest" + done + done +}