##@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 on est dans le répertoire de # destination $2, sinon l'exprimer par rapport au répertoire de destination # $2 si c'est un chemin relatif. 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}' } # liste des variables qu'il faut remplacer dans les fichiers sources TEMPLATE_VARS=() function template_list() { # Lister les fichiers du répertoire source $1 qui seraient fusionnées avec # template_merge() ou supprimés avec template_unmerge() du répertoire # destination $2. Si des chemins sont spécifiés avec les arguments $3..@, ne # traiter que les fichiers qui correspondent à ces spécifications local srcdir="$1"; shift __template_check_srcdir "$srcdir" || return 1 setx srcdir=abspath "$srcdir" local destdir="${1:-.}"; shift __template_check_destdir "$destdir" || return 1 setx destdir=abspath "$destdir" local rel2pwd withinpath "$destdir" "$(pwd)" && rel2pwd=1 if [ $# -eq 0 ]; then [ -n "$rel2pwd" ] && set -- . || set -- "$destdir" fi local spec srcspec src dest list local -a srcfiles for spec in "$@"; do setx srcspec=__template_prel_abspath "$spec" "$destdir" withinpath "$destdir" "$srcspec" || continue srcspec="${srcspec#$destdir}" [ -e "$srcdir$srcspec" ] || continue array_from_lines srcfiles "$(find "$srcdir$srcspec" -type f)" for src in "${srcfiles[@]}"; do dest="$destdir/${src#$srcdir/}" list= if [ -L "$dest" ]; then : elif [ -f "$dest" ]; then testsame "$src" "$dest" && list=1 else list=1 fi [ -n "$list" ] || continue if [ -n "$rel2pwd" ]; then relpath "$dest" else echo "${src#$srcdir/}" fi done done | csort -u } function template_merge() { # Copier dans le répertoire destination $2 tous les fichiers provenant du # répertoire source $1 correspondant aux spécifications $3..@, si ces fichiers # n'ont pas été modifiés dans le répertoire de destination. local srcdir="$1"; shift __template_check_srcdir "$srcdir" || return 1 setx srcdir=abspath "$srcdir" local destdir="${1:-.}"; shift __template_check_destdir "$destdir" || return 1 setx destdir=abspath "$destdir" [ $# -gt 0 ] || set -- "$destdir" local spec srcspec src 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}" [ -e "$srcdir$srcspec" ] || continue ebegin "$(ppath "$destdir$srcspec")" s=0 array_from_lines srcfiles "$(find "$srcdir$srcspec" -type f)" for src in "${srcfiles[@]}"; do dest="$destdir/${src#$srcdir/}" if [ -L "$dest" ]; then edotw 0 "LOCALLY MODIFIED: $(ppath "$dest")" elif [ -f "$dest" ]; then if testsame "$src" "$dest"; then show_debug && edot 0 "ALREADY COPIED: $(ppath "$dest")" else edotw 0 "LOCALLY MODIFIED: $(ppath "$dest")" fi else mkdirof "$dest" cp "$src" "$dest"; r=$? edot $r "COPY: $(ppath "$dest")" [ $r -eq 0 ] || s=$r fi done eend $s done } function template_unmerge() { # Supprimer du répertoire de destination $2 tous les fichiers provenant du # répertoire source $1 et qui n'ont pas été modifiés. Si des chemins sont # spécifiés avec les arguments $3..@, ne traiter que les fichiers qui # correspondent à ces spécifications. local srcdir="$1"; shift __template_check_srcdir "$srcdir" || return 1 setx srcdir=abspath "$srcdir" local destdir="${1:-.}"; shift __template_check_destdir "$destdir" || return 1 setx destdir=abspath "$destdir" [ $# -gt 0 ] || set -- "$destdir" local spec srcspec src 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}" [ -e "$srcdir$srcspec" ] || continue s=0 ebegin "$(ppath "$destdir$srcspec")" array_from_lines files "$(find "$srcdir$srcspec" -type f)" for src in "${files[@]}"; do dest="$destdir/${src#$srcdir/}" if [ -L "$dest" ]; then edotw 0 "LOCALLY MODIFIED: $(ppath "$dest")" elif [ -f "$dest" ]; then if testsame "$src" "$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 } 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() local -a dirs [ -d "$1" ] || return 1 array_from_lines dirs "$(cd "$1"; find . -type d | __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 $2 et # les fichiers du répertoire source $1 local srcdir="$1"; shift __template_check_srcdir "$srcdir" || return 1 setx srcdir=abspath "$srcdir" local destdir="${1:-.}"; shift __template_check_destdir "$destdir" || return 1 setx destdir=abspath "$destdir" local src dest local -a srcfiles array_from_lines srcfiles "$(find "$srcdir" -type f)" for src in "${srcfiles[@]}"; do dest="$destdir/${src#$srcdir/}" if [ -f "$dest" ] && testdiff "$src" "$dest"; then diff -uwB "$src" "$dest" fi done | page_maybe -S } function templatesrc() { # 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 __templatectl_display_help() { :; } __TEMPLATECTL_SUPPLOPTS=() function __templatectl_parseopts() { parse_opts "${PRETTYOPTS[@]}" \ --help '$exit_with __templatectl_display_help' \ -s:,--srcdir: srcdir= \ -d:,--destdir: destdir= \ -l,--list '$list=1; templatectl_opt=1' \ -m,--merge '$merge=1; templatectl_opt=1' \ -z,--unmerge '$unmerge=1; templatectl_opt=1' \ -C,--clean '$clean=1; templatectl_opt=1' \ -g,--diff '$diff=1; templatectl_opt=1' \ "${__TEMPLATECTL_SUPPLOPTS[@]}" \ @ args -- "$@" } function __templatectl_do() { __template_check_srcdir "$srcdir" || return 1 [ -n "$destdir" ] || destdir=. __template_check_destdir "$destdir" || return 1 [ -n "$templatectl_auto" ] && list=1 [ -n "$list" ] && template_list "$srcdir" "$destdir" "$@" [ -n "$merge" ] && template_merge "$srcdir" "$destdir" "$@" [ -n "$unmerge" ] && template_unmerge "$srcdir" "$destdir" "$@" [ -n "$clean" ] && template_cleandest "$destdir" "$@" [ -n "$diff" ] && template_diff "$srcdir" "$destdir" "$@" return 0 } function templatectl() { # fonction de haut niveau qui facilite l'utilisation des fonctions template_* # définir la fonction override_display_templatectl_help() pour l'affichage de l'aide local -a args local list merge unmerge clean diff templatectl_opt templatectl_auto local destdir __templatectl_parseopts "$@" && set -- "${args[@]}" || { eerror "$args"; return 1; } [ -z "$templatectl_opt" ] && templatectl_auto=1 __templatectl_do "$@" }