675 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
			
		
		
	
	
			675 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
| ##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
 | |
| ## Gestion de fichiers modèles
 | |
| ##@cooked nocomments
 | |
| ##@require base
 | |
| uprovide template
 | |
| urequire base
 | |
| 
 | |
| function __template_prel_abspath() {
 | |
|     # afficher le chemin absolu du fichier $1. Si $1 est un chemin relatif, le
 | |
|     # répertoire de référence pour le calcul du chemin absolu dépend du
 | |
|     # répertoire courant: si l'on est dans un des sous-répertoires du répertoire
 | |
|     # de destination $2, calculer le chemin absolu par rapport au répertoire
 | |
|     # courant. Sinon, l'exprimer par rapport à $2.
 | |
|     if withinpath "$2" "$(pwd)"; then
 | |
|         abspath "$1"
 | |
|     else
 | |
|         abspath "$1" "$2"
 | |
|     fi
 | |
| }
 | |
| function __template_check_srcdir() {
 | |
|     [ -n "$1" ] || {
 | |
|         eerror "Vous devez spécifier le répertoire source"
 | |
|         return 1
 | |
|     }
 | |
|     [ -d "$1" ] || {
 | |
|         eerror "$1: répertoire source introuvable"
 | |
|         return 1
 | |
|     }
 | |
|     return 0
 | |
| }
 | |
| function __template_check_destdir() {
 | |
|     [ -n "$1" ] || {
 | |
|         eerror "Vous devez spécifier le répertoire de destination"
 | |
|         return 1
 | |
|     }
 | |
|     [ -d "$1" ] || {
 | |
|         eerror "$1: répertoire destination introuvable"
 | |
|         return 1
 | |
|     }
 | |
|     return 0
 | |
| }
 | |
| function __template_plsort() {
 | |
|     # Trier par taille du chemin
 | |
|     awk '{print length($0) ":" $0}' |
 | |
|     sort -n "$@" |
 | |
|     awk '{sub(/[0-9]+:/, ""); print}'
 | |
| }
 | |
| function __template_search_destdir() {
 | |
|     # Chercher à partir du répertoire courant si un des répertoires parents
 | |
|     # s'appelle $1. Retourner vrai si le répertoire a été trouvé.
 | |
|     local dir="$(pwd)" dirname
 | |
| 
 | |
|     while true; do
 | |
|         setx dirname=basename -- "$dir"
 | |
|         if [ "$dir" == / ]; then
 | |
|             # s'arrêter à la racine
 | |
|             return 1
 | |
|         elif [ "$dir" == "$HOME" ]; then
 | |
|             # s'arrêter au répertoire HOME
 | |
|             return 1
 | |
|         elif [ "$dirname" == "$1" ]; then
 | |
|             echo "$dir"
 | |
|             return 0
 | |
|         elif [ "$dirname" == ".$1" ]; then
 | |
|             echo "$dir"
 | |
|             return 0
 | |
|         fi
 | |
|         setx dir=dirname -- "$dir"
 | |
|     done
 | |
| }
 | |
| function __template_set_destdir() {
 | |
|     local __destdir="${1:-destdir}" __autocreate="${2:-autocreate}" __name="${3:-template}"
 | |
|     setv "$__autocreate"
 | |
|     if [ -z "${!__destdir}" ]; then
 | |
|         if [ -d "$__name" ]; then
 | |
|             setv "$__destdir" "$__name"
 | |
|         elif [ -d ".$__name" ]; then
 | |
|             setv "$__destdir" ".$__name"
 | |
|         elif setx "$__destdir" __template_search_destdir "$__name"; then
 | |
|             estepn "Sélection automatique de $(ppath "${!__destdir}")"
 | |
|         elif [ -e "$__name" ]; then
 | |
|             eerror "Vous devez spécifier le répertoire de destination avec -d"
 | |
|             return 1
 | |
|         else
 | |
|             setv "$__destdir" "$__name"
 | |
|             setv "$__autocreate" 1
 | |
|         fi
 | |
|     fi
 | |
|     setx "$__destdir" abspath "${!__destdir}"
 | |
|     return 0
 | |
| }
 | |
| function __template_set_var() {
 | |
|     # Mettre à jour la variable $1 avec la valeur $2 en tenant compte de
 | |
|     # certaines dépendances. Par exemple, si on modifie host, il faut mettre à
 | |
|     # jour hostname.
 | |
|     # La variable __TEMPLATE_DEFAULTF_var contient le nom d'une fonction qui
 | |
|     # retourne la valeur par défaut de la variable. Cette fonction est appelée
 | |
|     # avec le nom de la variable comme premier argument.
 | |
|     # La variable __TEMPLATE_UPDATEF_var contient le nom d'une fonction qui met
 | |
|     # à jour les variables dépendantes. Cette fonction est appelée avec le nom
 | |
|     # de la variable comme premier argument et sa nouvelle valeur en deuxième
 | |
|     # argument.
 | |
|     # Retourner vrai si la valeur a été changée
 | |
|     local __orig_value="${!1}"
 | |
|     local __defaultf="__TEMPLATE_DEFAULTF_$1" __updatef="__TEMPLATE_UPDATEF_$1"
 | |
| 
 | |
|     array_contains TEMPLATE_DYNAMIC_VARS "$1" || array_addu TEMPLATE_STATIC_VARS "$1"
 | |
|     [ "$3" == writable ] && array_del TEMPLATE_NOWRITE_VARS
 | |
| 
 | |
|     [ -z "$2" -a -n "${!__defaultf}" ] && set -- "$1" "$("${!__defaultf}" "$1")"
 | |
|     setv "$1" "$2"
 | |
|     [ -n "${!__updatef}" ] && "${!__updatef}" "$1" "$2"
 | |
|     [ "$2" != "$__orig_value" ]
 | |
| }
 | |
| 
 | |
| # liste des variables qu'il faut remplacer dans les fichiers sources
 | |
| TEMPLATE_STATIC_VARS=()
 | |
| function __template_setup_tmpfile() {
 | |
|     if [ ${#TEMPLATE_STATIC_VARS[*]} -gt 0 ]; then
 | |
|         # S'il y a des variables à remplacer, préparer un fichier temporaire
 | |
|         ac_set_tmpfile tmpfile
 | |
|     fi
 | |
| }
 | |
| function __template_clean_tmpfile() {
 | |
|     if [ ${#TEMPLATE_STATIC_VARS[*]} -gt 0 ]; then
 | |
|         ac_clean "$tmpfile"
 | |
|     fi
 | |
| }
 | |
| function __template_fillvars() {
 | |
|     # Pour chacune des variables VAR de TEMPLATE_STATIC_VARS, remplacer dans le
 | |
|     # fichier $1 les occurences de @@VAR@@ par la valeur $VAR
 | |
|     # Afficher le chemin vers le fichier temporaire qui contient le fichier
 | |
|     # modifié. Si $2 est spécifié, prendre ce chemin comme fichier temporaire.
 | |
|     # Sinon, créer un nouveau fichier temporaire. Si le fichier ne contient
 | |
|     # aucune occurence de variable, afficher le chemin original $1.
 | |
|     [ ${#TEMPLATE_STATIC_VARS[*]} -eq 0 ] && { echo "$1"; return; }
 | |
| 
 | |
|     # chercher si le fichier contient au moins un des tags de
 | |
|     # TEMPLATE_STATIC_VARS
 | |
|     local __var __tag __found
 | |
|     for __var in "${TEMPLATE_STATIC_VARS[@]}"; do
 | |
|         __tag="@@${__var}@@"
 | |
|         if quietgrep "$__tag" "$1"; then
 | |
|             __found=1
 | |
|             break
 | |
|         fi
 | |
|     done
 | |
|     [ -n "$__found" ] || { echo "$1"; return; }
 | |
| 
 | |
|     # construire le script sed pour le remplacement des variables
 | |
|     local __script __first=1 __repl
 | |
|     for __var in "${TEMPLATE_STATIC_VARS[@]}"; do
 | |
|         [ -n "$__first" ] || __script="$__script"$'\n'
 | |
|         __first=
 | |
|         __script="${__script}s/@@${__var}@@/$(qseds "${!__var}")/g"
 | |
|     done
 | |
| 
 | |
|     sed "$__script" <"$1" >"$2"
 | |
|     echo "$2"
 | |
| }
 | |
| 
 | |
| function template_list() {
 | |
| # Soit $N le séparateur --, lister les fichiers des répertoires sources
 | |
| # $2..$(N-1) qui seraient fusionnés avec template_merge() ou supprimés avec
 | |
| # template_unmerge() du répertoire destination $1. Si des chemins sont spécifiés
 | |
| # avec les arguments $(N+1)..@, ne traiter que les fichiers qui correspondent à
 | |
| # ces spécifications. Exemple:
 | |
| #     template_list destdir srcdirs... -- specs...
 | |
|     local destdir="${1:-.}"; shift
 | |
|     __template_check_destdir "$destdir" || return 1
 | |
|     setx destdir=abspath "$destdir"
 | |
| 
 | |
|     local -a srcdirs; local srcdir
 | |
|     while [ $# -gt 0 ]; do
 | |
|         srcdir="$1"; shift
 | |
|         [ "$srcdir" == -- ] && break
 | |
|         __template_check_srcdir "$srcdir" || return 1
 | |
|         setx srcdir=abspath "$srcdir"
 | |
|         array_add srcdirs "$srcdir"
 | |
|     done
 | |
| 
 | |
|     local rel2pwd
 | |
|     withinpath "$destdir" "$(pwd)" && rel2pwd=1
 | |
| 
 | |
|     if [ $# -eq 0 ]; then
 | |
|         [ -n "$rel2pwd" ] && set -- . || set -- "$destdir"
 | |
|     fi
 | |
| 
 | |
|     local tmpfile; __template_setup_tmpfile
 | |
| 
 | |
|     local spec srcspec src content dest list
 | |
|     local -a srcfiles
 | |
|     for spec in "$@"; do
 | |
|         setx srcspec=__template_prel_abspath "$spec" "$destdir"
 | |
|         withinpath "$destdir" "$srcspec" || continue
 | |
|         srcspec="${srcspec#$destdir}"
 | |
| 
 | |
|         for srcdir in "${srcdirs[@]}"; do
 | |
|             [ -e "$srcdir$srcspec" ] || continue
 | |
|             array_from_lines srcfiles "$(find "$srcdir$srcspec" -type f)"
 | |
|             for src in "${srcfiles[@]}"; do
 | |
|                 setx content=__template_fillvars "$src" "$tmpfile"
 | |
|                 dest="$destdir/${src#$srcdir/}"
 | |
| 
 | |
|                 list=
 | |
|                 if [ -L "$dest" ]; then
 | |
|                     :
 | |
|                 elif [ -f "$dest" ]; then
 | |
|                     testsame "$content" "$dest" && list=1
 | |
|                 else
 | |
|                     list=1
 | |
|                 fi
 | |
|                 [ -n "$list" ] || continue
 | |
| 
 | |
|                 if [ -n "$rel2pwd" ]; then
 | |
|                     relpath "$dest"
 | |
|                 else
 | |
|                     echo "${src#$srcdir/}"
 | |
|                 fi
 | |
|             done
 | |
|         done
 | |
|     done | csort -u
 | |
| 
 | |
|     __template_clean_tmpfile
 | |
| }
 | |
| 
 | |
| function template_merge() {
 | |
| # Soit $N le séparateur --, copier dans le répertoire destination $1 les
 | |
| # fichiers des répertoires sources $2..$(N-1) correspondant aux spécifications
 | |
| # $(N+1)..@, si ces fichiers n'ont pas été modifiés dans le répertoire de
 | |
| # destination.
 | |
| # Les fichiers sources ayant l'extension .template sont ignorés par défaut, sauf
 | |
| # s'ils sonts demandés explicitement. Exemple:
 | |
| #     template_merge destdir srcdirs... -- specs...
 | |
|     local destdir="${1:-.}"; shift
 | |
|     __template_check_destdir "$destdir" || return 1
 | |
|     setx destdir=abspath "$destdir"
 | |
| 
 | |
|     local -a srcdirs; local srcdir
 | |
|     while [ $# -gt 0 ]; do
 | |
|         srcdir="$1"; shift
 | |
|         [ "$srcdir" == -- ] && break
 | |
|         __template_check_srcdir "$srcdir" || return 1
 | |
|         setx srcdir=abspath "$srcdir"
 | |
|         array_add srcdirs "$srcdir"
 | |
|     done
 | |
| 
 | |
|     [ $# -gt 0 ] || set -- "$destdir"
 | |
| 
 | |
|     local tmpfile; __template_setup_tmpfile
 | |
| 
 | |
|     local spec template srcspec src content dest
 | |
|     local srcfiles
 | |
|     for spec in "$@"; do
 | |
|         setb template=[ "${spec%.template}" != "$spec" ]
 | |
|         setx srcspec=__template_prel_abspath "$spec"
 | |
|         if ! withinpath "$destdir" "$srcspec"; then
 | |
|             ewarn "$spec: fichier ignoré"
 | |
|             continue
 | |
|         fi
 | |
|         srcspec="${srcspec#$destdir}"
 | |
| 
 | |
|         for srcdir in "${srcdirs[@]}"; do
 | |
|             if [ -z "$template" -a ! -e "$srcdir$srcspec" -a -e "$srcdir$srcspec.template" ]; then
 | |
|                 srcspec="$srcspec.template"
 | |
|                 template=1
 | |
|             fi
 | |
|             [ -e "$srcdir$srcspec" ] || continue
 | |
|             ebegin "$(basename -- "$srcdir") --> $(ppath "$destdir$srcspec")"
 | |
|             s=0
 | |
|             if [ -n "$template" ]; then
 | |
|                 array_from_lines srcfiles "$(find "$srcdir$srcspec" -type f)"
 | |
|             else
 | |
|                 array_from_lines srcfiles "$(find "$srcdir$srcspec" -type f | grep -v '\.template$')"
 | |
|             fi
 | |
|             for src in "${srcfiles[@]}"; do
 | |
|                 setx content=__template_fillvars "$src" "$tmpfile"
 | |
|                 dest="$destdir/${src#$srcdir/}"
 | |
|                 [ -n "$template" ] && dest="${dest%.template}"
 | |
| 
 | |
|                 if [ -L "$dest" ]; then
 | |
|                     edotw 0 "LOCALLY MODIFIED: $(ppath "$dest")"
 | |
|                 elif [ -f "$dest" ]; then
 | |
|                     if testsame "$content" "$dest"; then
 | |
|                         show_debug && edot 0 "ALREADY COPIED: $(ppath "$dest")"
 | |
|                     else
 | |
|                         edotw 0 "LOCALLY MODIFIED: $(ppath "$dest")"
 | |
|                     fi
 | |
|                 else
 | |
|                     mkdirof "$dest"
 | |
|                     cp "$content" "$dest"; r=$?
 | |
|                     edot $r "COPY: $(ppath "$dest")"
 | |
|                     [ $r -eq 0 ] || s=$r
 | |
|                 fi
 | |
|             done
 | |
|             eend $s
 | |
|         done
 | |
|     done
 | |
| 
 | |
|     __template_clean_tmpfile
 | |
| }
 | |
| 
 | |
| function template_unmerge() {
 | |
| # Soit $N le séparateur --, supprimer du répertoire destination $1 les fichiers
 | |
| # provenant des répertoires sources $2..$(N-1) et qui n'ont pas été modifiés. Si
 | |
| # des chemins sont spécifiés avec les arguments $(N+1)..@, ne traiter que les
 | |
| # fichiers qui correspondent à ces spécifications. Exemple:
 | |
| #     template_unmerge destdir srcdirs... -- specs...
 | |
|     local destdir="${1:-.}"; shift
 | |
|     __template_check_destdir "$destdir" || return 1
 | |
|     setx destdir=abspath "$destdir"
 | |
| 
 | |
|     local -a srcdirs; local srcdir
 | |
|     while [ $# -gt 0 ]; do
 | |
|         srcdir="$1"; shift
 | |
|         [ "$srcdir" == -- ] && break
 | |
|         __template_check_srcdir "$srcdir" || return 1
 | |
|         setx srcdir=abspath "$srcdir"
 | |
|         array_add srcdirs "$srcdir"
 | |
|     done
 | |
| 
 | |
|     [ $# -gt 0 ] || set -- "$destdir"
 | |
| 
 | |
|     local tmpfile; __template_setup_tmpfile
 | |
| 
 | |
|     local spec srcspec src content dest
 | |
|     local srcfiles
 | |
|     for spec in "$@"; do
 | |
|         setx srcspec=__template_prel_abspath "$spec"
 | |
|         if ! withinpath "$destdir" "$srcspec"; then
 | |
|             ewarn "$spec: fichier ignoré"
 | |
|             continue
 | |
|         fi
 | |
|         srcspec="${srcspec#$destdir}"
 | |
| 
 | |
|         for srcdir in "${srcdirs[@]}"; do
 | |
|             [ -e "$srcdir$srcspec" ] || continue
 | |
|             s=0
 | |
|             ebegin "$(ppath "$destdir$srcspec")"
 | |
|             array_from_lines files "$(find "$srcdir$srcspec" -type f)"
 | |
|             for src in "${files[@]}"; do
 | |
|                 setx content=__template_fillvars "$src" "$tmpfile"
 | |
|                 dest="$destdir/${src#$srcdir/}"
 | |
| 
 | |
|                 if [ -L "$dest" ]; then
 | |
|                     edotw 0 "LOCALLY MODIFIED: $(ppath "$dest")"
 | |
|                 elif [ -f "$dest" ]; then
 | |
|                     if testsame "$content" "$dest"; then
 | |
|                         rm -f "$dest"; r=$?
 | |
|                         edot $r "REMOVE: $(ppath "$dest")"
 | |
|                         [ $r -eq 0 ] || s=$r
 | |
|                     else
 | |
|                         edotw 0 "LOCALLY MODIFIED: $(ppath "$dest")"
 | |
|                     fi
 | |
|                 else
 | |
|                     show_debug && edot 0 "ALREADY REMOVED: $(ppath "$dest")"
 | |
|                 fi
 | |
|             done
 | |
|             eend $s
 | |
|         done
 | |
|     done
 | |
| 
 | |
|     __template_clean_tmpfile
 | |
| }
 | |
| 
 | |
| function template_cleandest() {
 | |
| # Supprimer dans le répertoire de destination $1 tous les répertoires vides.
 | |
| # Cette fonction est habituellement utilisée après template_unmerge()
 | |
| # Ignorer les chemins qui contiennent .git/ et .svn/
 | |
|     local -a dirs
 | |
|     [ -d "$1" ] || return 1
 | |
|     array_from_lines dirs "$(cd "$1"; find . -type d | grep -v .git/ | grep -v .svn/ | __template_plsort -r)"
 | |
|     array_del dirs .
 | |
|     (cd "$1"; rmdir "${dirs[@]}" 2>/dev/null)
 | |
| }
 | |
| 
 | |
| function template_diff() {
 | |
| # Afficher les différences entre les fichiers du répertoire de destination $1 et
 | |
| # les fichiers des répertoires sources $2..@
 | |
|     local destdir="${1:-.}"; shift
 | |
|     __template_check_destdir "$destdir" || return 1
 | |
|     setx destdir=abspath "$destdir"
 | |
| 
 | |
|     local -a srcdirs; local srcdir
 | |
|     while [ $# -gt 0 ]; do
 | |
|         srcdir="$1"; shift
 | |
|         [ "$srcdir" == -- ] && break
 | |
|         __template_check_srcdir "$srcdir" || return 1
 | |
|         setx srcdir=abspath "$srcdir"
 | |
|         array_add srcdirs "$srcdir"
 | |
|     done
 | |
| 
 | |
|     local tmpfile; __template_setup_tmpfile
 | |
| 
 | |
|     local src content dest
 | |
|     local -a srcfiles
 | |
|     for srcdir in "${srcdirs[@]}"; do
 | |
|         array_from_lines srcfiles "$(find "$srcdir" -type f)"
 | |
|         for src in "${srcfiles[@]}"; do
 | |
|             setx content=__template_fillvars "$src" "$tmpfile"
 | |
|             dest="$destdir/${src#$srcdir/}"
 | |
|             if [ -f "$dest" ] && testdiff "$content" "$dest"; then
 | |
|                 diff -uwB "$content" "$dest"
 | |
|             fi
 | |
|         done
 | |
|     done | page_maybe -S
 | |
| 
 | |
|     __template_clean_tmpfile
 | |
| }
 | |
| 
 | |
| function template_srcdir() {
 | |
| # Obtenir le chemin vers le répertoire source de templates $1, situé dans
 | |
| # ULIBDIR/templates
 | |
|     urequire ulib
 | |
|     if [ -n "$ULIBDIR" ]; then
 | |
|         echo "$ULIBDIR/templates/$1"
 | |
|     else
 | |
|         abspath "templates/$1"
 | |
|     fi
 | |
| }
 | |
| 
 | |
| function template_build_vars() {
 | |
| # Initialiser les tableaux $1 et $2 avec la description des variables $3..@
 | |
| # les descriptions sont de la forme var[:depvars,...]=desc
 | |
| # $1 reçoit les noms (depvars... var) parce que les variables dépendantes
 | |
| # doivent toujours être placées AVANT la variable maitre
 | |
| # $2 reçoit les noms (depvars...)
 | |
| # pour chaque description, une variable __TEMPLATE_DESC_var est créée avec
 | |
| # la valeur desc
 | |
|     local __t_destvs="$1"; shift
 | |
|     local __t_destnw="$1"; shift
 | |
|     local -a __t_depvars
 | |
|     local __t_vardesc __t_var __t_depvar __t_desc
 | |
|     for __t_vardesc in "$@"; do
 | |
|         splitvar "$__t_vardesc" __t_depvar __t_desc
 | |
|         splitpair "$__t_depvar" __t_var __t_depvar
 | |
|         array_split __t_depvars "$__t_depvar" ,
 | |
|         for __t_depvar in "${__t_depvars[@]}"; do
 | |
|             array_addu "$__t_destvs" "$__t_depvar"
 | |
|             [ -n "$__t_destnw" ] && array_addu "$__t_destnw" "$__t_depvar"
 | |
|         done
 | |
|         array_del "$__t_destvs" "$__t_var"
 | |
|         array_add "$__t_destvs" "$__t_var"
 | |
|         eval "__TEMPLATE_DESC_$__t_var=\"\$__t_desc\""
 | |
|     done
 | |
| }
 | |
| 
 | |
| function templatectl_config() {
 | |
| # Obtenir le chemin vers le fichier de configuration pour le répertoire $1 Si
 | |
| # l'un des fichiers CONFIG.conf ou .CONFIG existent déjà, prendre ceux-là.
 | |
| # Sinon, si $2==nohideconfig, utiliser le nom CONFIG.conf, sinon utiliser
 | |
| # .CONFIG
 | |
|     local config="$(basename -- "$TEMPLATECTL_CONFIG")"
 | |
|     if [ -f "$1/$config.conf" ]; then echo "$1/$config.conf"
 | |
|     elif [ -f "$1/.$config" ]; then echo "$1/.$config"
 | |
|     elif [ "$2" == nohideconfig ]; then echo "$1/$config.conf"
 | |
|     else echo "$1/.$config"
 | |
|     fi
 | |
| }
 | |
| 
 | |
| function templatectl_loadvars() {
 | |
| # Charger les valeurs des variables depuis le fichier $1
 | |
| # Les variables suivantes doivent être définies:
 | |
| # - Le tableau TEMPLATECTL_DEFAULTS permet de donner une valeur par défaut aux
 | |
| #   variables mentionnées dans TEMPLATE_STATIC_VARS. C'est une liste de valeurs
 | |
| #   de la forme 'name=value'
 | |
| # - Le tableau TEMPLATECTL_VARS contient des variables supplémentaires
 | |
| #   spécifiées par l'utilisateur. C'est une liste de valeurs de la forme
 | |
| #   'name=value'
 | |
| # - TEMPLATE_STATIC_VARS doit contenir une liste de noms de variables qui
 | |
| #   peuvent être remplacés dans les fichiers de template.
 | |
| # - TEMPLATE_DYNAMIC_VARS contient une liste de noms de variables valides, mais
 | |
| #   qui ne doivent pas être remplacés, en effet, ils sont utilisés pour le
 | |
| #   déploiement des fichiers.
 | |
| # - TEMPLATE_NOWRITE_VARS contient une liste de noms de variables qui ne
 | |
| #   devraient pas être écrits dans le fichier des variables, sauf si elles
 | |
| #   reçoivent une valeur explicite de la part de l'utilisateur. Ce tableau est
 | |
| #   mis à jour lors de l'analyse du tableau TEMPLATECTL_VARS
 | |
| # - TEMPLATE_USER_VARS contient une liste de noms de tableaux qui sont définis
 | |
| #   en plus et qui peuvent être utilisés par des scripts annexes
 | |
|     local -a __template_vars __dynamic_vars
 | |
|     local __t_var __t_name __t_value
 | |
| 
 | |
|     array_copy __template_vars TEMPLATECTL_DEFAULTS
 | |
|     configdir="$(dirname -- "$1")"
 | |
|     [ -f "$1" ] && source "$1"
 | |
| 
 | |
|     for __t_var in "${__template_vars[@]}"; do
 | |
|         splitvar "$__t_var" __t_name __t_value
 | |
|         __template_set_var "$__t_name" "$__t_value"
 | |
|     done
 | |
|     array_contains TEMPLATE_STATIC_VARS configdir && __template_set_var configdir "$configdir"
 | |
|     for __t_var in "${__dynamic_vars[@]}"; do
 | |
|         splitvar "$__t_var" __t_name __t_value
 | |
|         array_del TEMPLATE_STATIC_VARS "$__t_name"
 | |
|         array_addu TEMPLATE_DYNAMIC_VARS "$__t_name"
 | |
|         __template_set_var "$__t_name" "$__t_value"
 | |
|     done
 | |
|     array_contains TEMPLATE_DYNAMIC_VARS configdir && __template_set_var configdir "$configdir"
 | |
| 
 | |
|     is_defined TEMPLATE_USER_VARS || TEMPLATE_USER_VARS=()
 | |
|     for __t_var in "${TEMPLATE_USER_VARS[@]}"; do
 | |
|         is_defined "$__t_var" || array_new "$__t_var"
 | |
|     done
 | |
| 
 | |
|     local __t_modified=1
 | |
|     for __t_var in "${TEMPLATECTL_VARS[@]}"; do
 | |
|         splitvar "$__t_var" __t_name __t_value
 | |
|         __template_set_var "$__t_name" "$__t_value" writable && __t_modified=0
 | |
|     done
 | |
|     return $__t_modified
 | |
| }
 | |
| 
 | |
| function templatectl_writevars() {
 | |
| # Ecrire les variables dans le fichier $1
 | |
|     local __t_var __t_desc
 | |
|     echo "# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8" >"$1"
 | |
|     for __t_var in "${TEMPLATE_USER_VARS[@]}"; do
 | |
|         __t_desc="__TEMPLATE_DESC_$__t_var"
 | |
|         [ -n "${!__t_desc}" ] && echo "# ${!__t_desc}" >>"$1"
 | |
|         if is_array "$__t_var"; then
 | |
|             set_array_cmd "$__t_var" >>"$1"
 | |
|         else
 | |
|             echo_setv "$__t_var" "${!__t_var}" >>"$1"
 | |
|         fi
 | |
|     done
 | |
|     if [ ${#TEMPLATE_DYNAMIC_VARS[*]} -gt 0 ]; then
 | |
|         echo "__dynamic_vars=(" >>"$1"
 | |
|         for __t_var in "${TEMPLATE_DYNAMIC_VARS[@]}"; do
 | |
|             array_contains TEMPLATE_NOWRITE_VARS "$__t_var" && continue
 | |
|             __t_desc="__TEMPLATE_DESC_$__t_var"
 | |
|             [ -n "${!__t_desc}" ] && echo "# ${!__t_desc}" >>"$1"
 | |
|             echo_setv "$__t_var" "${!__t_var}" >>"$1"
 | |
|         done
 | |
|         echo ")" >>"$1"
 | |
|     fi
 | |
|     echo "__template_vars=(# ne pas modifier" >>"$1"
 | |
|     for __t_var in "${TEMPLATE_STATIC_VARS[@]}"; do
 | |
|         array_contains TEMPLATE_NOWRITE_VARS "$__t_var" && continue
 | |
|         __t_desc="__TEMPLATE_DESC_$__t_var"
 | |
|         [ -n "${!__t_desc}" ] && echo "# ${!__t_desc}" >>"$1"
 | |
|         echo_setv "$__t_var" "${!__t_var}" >>"$1"
 | |
|     done
 | |
|     echo ")" >>"$1"
 | |
| }
 | |
| 
 | |
| function templatectl_list_vars() {
 | |
| # Afficher les valeurs des variables
 | |
|     local __var
 | |
|     echo "# template vars"
 | |
|     for __var in "${TEMPLATE_STATIC_VARS[@]}"; do
 | |
|         echo_setv "$__var=${!__var}"
 | |
|     done
 | |
|     if [ ${#TEMPLATE_DYNAMIC_VARS[*]} -gt 0 ]; then
 | |
|         echo "# dynamic vars"
 | |
|         for __var in "${TEMPLATE_DYNAMIC_VARS[@]}"; do
 | |
|             echo_setv "$__var=${!__var}"
 | |
|         done
 | |
|     fi
 | |
| }
 | |
| 
 | |
| __TEMPLATECTL_HELP="\
 | |
| -d, --destdir DESTDIR
 | |
|     Spécifier le répertoire local dans lequel copier les fichiers templates
 | |
| -s, --srcdir SRCDIR
 | |
|     Ajouter un répertoire à la liste des répertoires sources pour les templates.
 | |
|     Si ce n'est pas un chemin, c'est le nom d'un répertoire dans le répertoires
 | |
|     des templates par défaut.
 | |
| -l, --list
 | |
|     Lister les templates disponibles.
 | |
| -m, --merge
 | |
|     Copier les templates spécifiés dans le répertoire local s'il n'y existent
 | |
|     pas déjà. Les templates ayant l'extension '.template' doivent être demandés
 | |
|     explicitement. Sinon, ils sont ignorés.
 | |
| -z, --unmerge
 | |
|     Supprimer les fichiers du répertoire local s'ils n'ont pas été modifiés par
 | |
|     rapport aux templates.
 | |
| -C, --clean
 | |
|     Supprimer les répertoires vides dans le répertoire local. Peut être utile
 | |
|     après -z
 | |
| -g, --diff
 | |
|     Afficher les différences entre les templates et les fichiers du répertoire
 | |
|     local.
 | |
| -L, --list-vars
 | |
|     Afficher pour information les valeurs par défaut des variables de template.
 | |
| -v, --var NAME=VALUE
 | |
|     Spécifier la valeur d'une variable. Toutes les variables sont autorisées,
 | |
|     sauf celles qui figurent dans la liste des variables dynamiques.
 | |
| -w, --write-vars
 | |
|     Ecrire dans le fichier $TEMPLATECTL_CONFIG les valeurs des variables, ce qui
 | |
|     permet après édition du fichier d'éviter de les spécifier à chaque fois avec
 | |
|     l'option -v
 | |
|     Le fichier n'est pas écrasé s'il existe déjà."
 | |
| function __display_templatectl_help() { uecho "$__TEMPLATECTL_HELP"; }
 | |
| function templatectl() {
 | |
| # Fonction de haut niveau qui facilite l'utilisation des fonctions template_*
 | |
| # définir la fonction __display_templatectl_help() pour l'affichage de l'aide
 | |
| # - Le tableau TEMPLATECTL_SRCDIRS doit contenir la liste des répertoires
 | |
| #   sources pour les templates. Alternativement, il est possible de définir la
 | |
| #   variable TEMPLATECTL_SRCDIR s'il n'y a qu'un seul répertoire source pour le
 | |
| #   template
 | |
| # - TEMPLATECTL_CONFIG est le nom de base du fichier à partir duquel sont
 | |
| #   chargées les variables et dans lequel sont écrites les variables avec
 | |
| #   l'option --write-vars
 | |
| #   Si le nom de base est CONFIG, le fichier s'appelera .CONFIG si l'option
 | |
| #   --hide-config est utilisée (par défaut) ou CONFIG.conf si l'option
 | |
| #   --no-hide-config est utilisée
 | |
| # Les variables de template_loadvars() sont aussi prises en compte
 | |
|     local -a __tc_srcdirs; local __tc_srcdir
 | |
|     if [ ${#TEMPLATECTL_SRCDIRS[*]} -gt 0 ]; then
 | |
|         :
 | |
|     elif [ -n "$TEMPLATECTL_SRCDIR" ]; then
 | |
|         local -a TEMPLATECTL_SRCDIRS
 | |
|         TEMPLATECTL_SRCDIRS=("$TEMPLATECTL_SRCDIR")
 | |
|     fi
 | |
|     for __tc_srcdir in "${TEMPLATECTL_SRCDIRS[@]}"; do
 | |
|         if ! withpath "$__tc_srcdir"; then
 | |
|             __tc_srcdir="$(template_srcdir "$__tc_srcdir")"
 | |
|         fi
 | |
|         array_add __tc_srcdirs "$__tc_srcdir"
 | |
|     done
 | |
| 
 | |
|     local -a __tc_args
 | |
|     local __tc_auto=1 __tc_load_vars=1
 | |
|     local __tc_destdir __tc_config __tc_nohideconfig
 | |
|     local __tc_list __tc_merge __tc_unmerge __tc_clean __tc_diff __tc_list_vars __tc_write_vars
 | |
|     parse_opts "${PRETTYOPTS[@]}" \
 | |
|         --help '$exit_with __display_templatectl_help' \
 | |
|         -d:,--destdir: __tc_destdir= \
 | |
|         -s:,--srcdir: __tc_srcdirs \
 | |
|         --config: __tc_config= \
 | |
|         --no-hide-config __tc_nohideconfig=1 \
 | |
|         --hide-config __tc_nohideconfig= \
 | |
|         --load-vars __tc_load_vars=1 \
 | |
|         --no-load-vars __tc_load_vars= \
 | |
|         --noop __tc_auto= \
 | |
|         -l,--list '$__tc_list=1; __tc_auto=' \
 | |
|         -m,--merge '$__tc_merge=1; __tc_auto=' \
 | |
|         -z,--unmerge '$__tc_unmerge=1; __tc_auto=' \
 | |
|         -C,--clean '$__tc_clean=1; __tc_auto=' \
 | |
|         -g,--diff '$__tc_diff=1; __tc_auto=' \
 | |
|         -L,--list-vars '$__tc_list_vars=1; __tc_auto=' \
 | |
|         -v:,--var: TEMPLATECTL_VARS \
 | |
|         -w,--write-vars __tc_write_vars=1 \
 | |
|         @ __tc_args -- "$@" && set -- "${__tc_args[@]}" || { eerror "$__tc_args"; return 1; }
 | |
| 
 | |
|     [ -n "$__tc_destdir" ] || __tc_destdir=.
 | |
|     __template_check_destdir "$__tc_destdir" || return 1
 | |
| 
 | |
|     array_isempty __tc_srcdirs && return 1
 | |
|     for __tc_srcdir in "${__tc_srcdirs[@]}"; do
 | |
|         __template_check_srcdir "$__tc_srcdir" || return 1
 | |
|     done
 | |
| 
 | |
|     [ -n "$__tc_config" ] || __tc_config="$(templatectl_config "$destdir" ${__tc_nohideconfig:+nohideconfig})"
 | |
|     if [ -n "$__tc_load_vars" ]; then
 | |
|         templatectl_loadvars "$__tc_config"
 | |
|     fi
 | |
|     if [ -n "$__tc_write_vars" ]; then
 | |
|         if [ -f "$__tc_config" ]; then
 | |
|             ewarn "Refus d'écraser le fichier existant $(ppath "$__tc_config")"
 | |
|         else
 | |
|             templatectl_writevars "$__tc_config"
 | |
|         fi
 | |
|     fi
 | |
| 
 | |
|     [ -n "$__tc_auto" ] && __tc_list=1
 | |
|     [ -n "$__tc_list_vars" ] && templatectl_list_vars
 | |
|     [ -n "$__tc_list" ] && template_list "$__tc_destdir" "${__tc_srcdirs[@]}" -- "$@"
 | |
|     [ -n "$__tc_merge" ] && template_merge "$__tc_destdir" "${__tc_srcdirs[@]}" -- "$@"
 | |
|     [ -n "$__tc_unmerge" ] && template_unmerge "$__tc_destdir" "${__tc_srcdirs[@]}" -- "$@"
 | |
|     [ -n "$__tc_clean" ] && template_cleandest "$__tc_destdir" "$@"
 | |
|     [ -n "$__tc_diff" ] && template_diff "$__tc_destdir" "${__tc_srcdirs[@]}" -- "$@"
 | |
| }
 |