355 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
			
		
		
	
	
			355 lines
		
	
	
		
			12 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 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_setup_tmpfile() {
 | 
						|
    if [ ${#TEMPLATE_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_VARS[*]} -gt 0 ]; then
 | 
						|
        ac_clean "$tmpfile"
 | 
						|
    fi
 | 
						|
}
 | 
						|
function __template_fillvars() {
 | 
						|
    # Pour chacune des variables VAR de TEMPLATE_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_VARS[*]} -eq 0 ] && { echo "$1"; return; }
 | 
						|
 | 
						|
    # chercher si le fichier contient au moins un des tags de TEMPLATE_VARS
 | 
						|
    local __var __tag __found
 | 
						|
    for __var in "${TEMPLATE_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
 | 
						|
    for __var in "${TEMPLATE_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() {
 | 
						|
# 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 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}"
 | 
						|
 | 
						|
        [ -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 | csort -u
 | 
						|
 | 
						|
    __template_clean_tmpfile
 | 
						|
}
 | 
						|
 | 
						|
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.
 | 
						|
# Les fichiers sources ayant l'extension .template sont ignorés par défaut, sauf
 | 
						|
# s'ils sonts demandés explicitement.
 | 
						|
    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 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}"
 | 
						|
 | 
						|
        [ -e "$srcdir$srcspec" ] || continue
 | 
						|
        ebegin "$(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
 | 
						|
 | 
						|
    __template_clean_tmpfile
 | 
						|
}
 | 
						|
 | 
						|
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 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}"
 | 
						|
 | 
						|
        [ -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
 | 
						|
 | 
						|
    __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()
 | 
						|
    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 tmpfile; __template_setup_tmpfile
 | 
						|
 | 
						|
    local src content dest
 | 
						|
    local -a srcfiles
 | 
						|
    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 | page_maybe -S
 | 
						|
 | 
						|
    __template_clean_tmpfile
 | 
						|
}
 | 
						|
 | 
						|
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: __templatectl_srcdir= \
 | 
						|
        -d:,--destdir: __templatectl_destdir= \
 | 
						|
        -l,--list '$__templatectl_list=1; __templatectl_opt=1' \
 | 
						|
        -m,--merge '$__templatectl_merge=1; __templatectl_opt=1' \
 | 
						|
        -z,--unmerge '$__templatectl_unmerge=1; __templatectl_opt=1' \
 | 
						|
        -C,--clean '$__templatectl_clean=1; __templatectl_opt=1' \
 | 
						|
        -g,--diff '$__templatectl_diff=1; __templatectl_opt=1' \
 | 
						|
        "${__TEMPLATECTL_SUPPLOPTS[@]}" \
 | 
						|
        @ args -- "$@"
 | 
						|
}
 | 
						|
 | 
						|
function __templatectl_do() {
 | 
						|
    __template_check_srcdir "$__templatectl_srcdir" || return 1
 | 
						|
    [ -n "$__templatectl_destdir" ] || __templatectl_destdir=.
 | 
						|
    __template_check_destdir "$__templatectl_destdir" || return 1
 | 
						|
    [ -n "$__templatectl_auto" ] && __templatectl_list=1
 | 
						|
 | 
						|
    [ -n "$__templatectl_list" ] && template_list "$__templatectl_srcdir" "$__templatectl_destdir" "$@"
 | 
						|
    [ -n "$__templatectl_merge" ] && template_merge "$__templatectl_srcdir" "$__templatectl_destdir" "$@"
 | 
						|
    [ -n "$__templatectl_unmerge" ] && template_unmerge "$__templatectl_srcdir" "$__templatectl_destdir" "$@"
 | 
						|
    [ -n "$__templatectl_clean" ] && template_cleandest "$__templatectl_destdir" "$@"
 | 
						|
    [ -n "$__templatectl_diff" ] && template_diff "$__templatectl_srcdir" "$__templatectl_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 __templatectl_list __templatectl_merge __templatectl_unmerge __templatectl_clean __templatectl_diff __templatectl_opt __templatectl_auto
 | 
						|
    local __templatectl_destdir
 | 
						|
 | 
						|
    __templatectl_parseopts "$@" && set -- "${args[@]}" || { eerror "$args"; return 1; }
 | 
						|
    [ -z "$__templatectl_opt" ] && __templatectl_auto=1
 | 
						|
    __templatectl_do "$@"
 | 
						|
}
 |