# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 ##@cooked nocomments module: template "Mise à jour de templates à partir de modèles" function: template_locals "\ Afficher les variables qui doivent être locales Utiliser de cette façon: ~~~ eval \$(template_locals) ~~~" function template_locals() { echo "local -a userfiles; local updated" } function: template_copy_replace "\ Copier \$1 vers \$2 de façon inconditionnelle Si \$2 n'est pas spécifié, on assume que \$1 est de la forme '.file.ext' et \$2 vaudra alors 'file' si un fichier \${2#.}.local existe, prendre ce fichier à la place comme source Ajouter file au tableau userfiles" function template_copy_replace() { local src="$1" dest="$2" local srcdir srcname lsrcname setx srcdir=dirname "$src" setx srcname=basename "$src" if [ -z "$dest" ]; then dest="${srcname#.}" dest="${dest%.*}" dest="$srcdir/$dest" fi lsrcname="${srcname#.}.local" [ -e "$srcdir/$lsrcname" ] && src="$srcdir/$lsrcname" userfiles+=("$dest") cp -P "$src" "$dest" return 0 } function: template_copy_missing "\ Copier \$1 vers \$2 si ce fichier n'existe pas déjà Si \$2 n'est pas spécifié, on assume que \$1 est de la forme '.file.ext' et \$2 vaudra alors 'file' si un fichier \${2#.}.local existe, prendre ce fichier à la place comme source Ajouter file au tableau userfiles" function template_copy_missing() { local src="$1" dest="$2" local srcdir srcname lsrcname setx srcdir=dirname "$src" setx srcname=basename "$src" if [ -z "$dest" ]; then dest="${srcname#.}" dest="${dest%.*}" dest="$srcdir/$dest" fi userfiles+=("$dest") if [ ! -e "$dest" ]; then lsrcname="${srcname#.}.local" [ -e "$srcdir/$lsrcname" ] && src="$srcdir/$lsrcname" cp -P "$src" "$dest" return 0 fi return 1 } function: template_dump_vars "\ Lister les variables mentionnées dans les fichiers \$@ Seules sont prises en compte les variables dont le nom est de la forme [A-Z][A-Za-z_]* Cette fonction est utilisée par template_source_envs(). Elle utilise la fonction outil _template_dump_vars() qui peut être redéfinie si nécessaire." function template_dump_vars() { _template_dump_vars "$@" } function _template_dump_vars() { [ $# -gt 0 ] || return 0 cat "$@" | grep -E '^[A-Z][A-Za-z_]*=' | sed 's/=.*//' | sort -u } function: template_source_envs "\ Cette fonction doit être implémentée par l'utilisateur et doit: - initialiser le tableau template_vars qui donne la liste des variables scalaires - initialiser te tableau template_lists qui donne la liste des variables listes - charger ces variables depuis les fichiers \$@ Cette fonction utilise la fonction outil _template_source_envs() qui peut être redéfinie si nécessaire." function template_source_envs() { _template_source_envs "$@" } function _template_source_envs() { local e_ for e_ in "$@"; do [ -f "$e_" ] && source "$e_" done setx -a template_vars=template_dump_vars "$@" template_lists=() } function: template_resolve_scripts "\ Générer le script awk \$1 et le script sed \$2 qui remplacent dans les fichiers destination les marqueurs @@VAR@@ par la valeur de la variable \$VAR correspondante Les fichiers \$3..@ contiennent les valeurs des variables Les marqueurs supportés sont les suivants et sont évalués dans cet ordre: - XXXRANDOMXXX remplacer cette valeur par une chaine de 16 caractères au hasard - @@FOR:VARS@@ VARS étant une liste de valeurs séparées par des espaces: dupliquer la ligne autant de fois qu'il y a de valeurs dans \$VARS dans chaque ligne, remplacer les occurrences de @@VAR@@ par la valeur de l'itération courante - #@@IF:VAR@@ afficher la ligne si VAR est non vide, supprimer la ligne sinon - #@@UL:VAR@@ afficher la ligne si VAR est vide, supprimer la ligne sinon - #@@if:VAR@@ - #@@ul:VAR@@ variantes qui ne suppriment pas la ligne mais sont remplacées par # - @@VAR:-string@@ remplacer par 'string' si VAR a une valeur vide ou n'est pas défini, \$VAR sinon - @@VAR:+string@@ remplacer par 'string' si VAR est défini a une valeur non vide " function template_generate_scripts() { local awkscript="$1"; shift local sedscript="$1"; shift ( template_source_envs "$@" NL=$'\n' # random, for exec >"$awkscript" echo '@include "base.tools.awk"' echo 'BEGIN {' for list in "${template_lists[@]}"; do items="${!list}"; read -a items <<<"${items// / }" let i=0 echo " $list[0] = 0; delete $list" for item in "${items[@]}"; do item="${item//\\/\\\\}" item="${item//\"/\\\"}" echo " $list[$i] = \"$item\"" let i=i+1 done done echo '}' echo '{ if (should_generate_password()) { generate_password() } }' for list in "${template_lists[@]}"; do items="${!list}"; read -a items <<<"${items// / }" echo "/@@FOR:$list@@/ {" if [ ${#items[*]} -gt 0 ]; then if [ "${list%S}" != "$list" ]; then item="${list%S}" elif [ "${list%s}" != "$list" ]; then item="${list%s}" else item="$list" fi echo " sub(/@@FOR:$list@@/, \"\")" echo " for (i in $list) {" echo " print gensub(/@@$item@@/, $list[i], \"g\")" echo " }" fi echo " next" echo "}" done echo '{ print }' # if, ul, var exec >"$sedscript" for var in "${template_vars[@]}"; do value="${!var}" value="${value//\//\\\/}" value="${value//[/\\[}" value="${value//\*/\\\*}" value="${value//$NL/\\n}" if [ -n "$value" ]; then echo "s/#@@IF:${var}@@//g" echo "s/#@@if:${var}@@//g" echo "/#@@UL:${var}@@/d" echo "s/#@@ul:${var}@@/#/g" echo "s/@@${var}:-([^@]*)@@/${value}/g" echo "s/@@${var}:+([^@]*)@@/\\1/g" else echo "/#@@IF:${var}@@/d" echo "s/#@@if:${var}@@/#/g" echo "s/#@@UL:${var}@@//g" echo "s/#@@ul:${var}@@//g" echo "s/@@${var}:-([^@]*)@@/\\1/g" echo "s/@@${var}:+([^@]*)@@//g" fi echo "s/@@${var}@@/${value}/g" done ) #etitle "awkscript" cat "$awkscript" #etitle "sedscript" cat "$sedscript" } function template_process_userfiles() { local awkscript sedscript workfile userfile ac_set_tmpfile awkscript ac_set_tmpfile sedscript template_generate_scripts "$awkscript" "$sedscript" "$@" ac_set_tmpfile workfile for userfile in "${userfiles[@]}"; do if cat "$userfile" | awk -f "$awkscript" | sed -rf "$sedscript" >"$workfile"; then if testdiff "$workfile" "$userfile"; then # n'écrire le fichier que s'il a changé cat "$workfile" >"$userfile" fi fi done ac_clean "$awkscript" "$sedscript" "$workfile" }