# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 ##@cooked nocomments module: base.output "Fonctions de base: affichage" nulib__load: _output_vanilla NULIB__TAB=$'\t' NULIB__LATIN1=iso-8859-1 NULIB__LATIN9=iso-8859-15 NULIB__UTF8=utf-8 [ -n "$LANG" ] || export LANG=fr_FR.UTF-8 if [ ! -x "$(which iconv 2>/dev/null)" ]; then function iconv() { cat; } fi function nulib__lang_encoding() { case "${LANG,,}" in *@euro) echo "iso-8859-15";; *.utf-8|*.utf8) echo "utf-8";; *) echo "iso-8859-1";; esac } function nulib__norm_encoding() { local enc="${1,,}" enc="${enc//[-_]/}" case "$enc" in latin|latin1|iso8859|iso88591|8859|88591) echo "iso-8859-1";; latin9|iso885915|885915) echo "iso-8859-15";; utf|utf8) echo "utf-8";; *) echo "$1";; esac } function nulib__init_encoding() { local default_encoding="$(nulib__lang_encoding)" [ -n "$default_encoding" ] || default_encoding=utf-8 [ -n "$NULIB_OUTPUT_ENCODING" ] || NULIB_OUTPUT_ENCODING="$default_encoding" NULIB_OUTPUT_ENCODING="$(nulib__norm_encoding "$NULIB_OUTPUT_ENCODING")" [ -n "$NULIB_INPUT_ENCODING" ] || NULIB_INPUT_ENCODING="$NULIB_OUTPUT_ENCODING" NULIB_INPUT_ENCODING="$(nulib__norm_encoding "$NULIB_INPUT_ENCODING")" } [ -n "$NULIB_LANG" -a -z "$LANG" ] && export NULIB_LANG LANG="$NULIB_LANG" nulib__init_encoding function noerror() { # lancer la commande "$@" et masquer son code de retour [ $# -gt 0 ] || set : "$@" || return 0 } function noout() { # lancer la commande "$@" en supprimant sa sortie standard [ $# -gt 0 ] || return 0 "$@" >/dev/null } function noerr() { # lancer la commande "$@" en supprimant sa sortie d'erreur [ $# -gt 0 ] || return 0 "$@" 2>/dev/null } function isatty() { # tester si STDOUT n'est pas une redirection tty -s <&1 } function in_isatty() { # tester si STDIN n'est pas une redirection tty -s } function out_isatty() { # tester si STDOUT n'est pas une redirection. identique à isatty() tty -s <&1 } function err_isatty() { # tester si STDERR n'est pas une redirection tty -s <&2 } ################################################################################ function uecho() { # $1 étant une chaine encodée en utf-8, l'afficher dans l'encoding de sortie $2 # qui vaut par défaut $NULIB_OUTPUT_ENCODING local value="$1" to="${2:-$NULIB_OUTPUT_ENCODING}" if [ "$to" == "$NULIB__UTF8" ]; then recho "$value" else iconv -f -utf-8 -t "$to" <<<"$value" fi } function uecho_() { # $1 étant une chaine encodée en utf-8, l'afficher sans passer à la ligne dans # l'encoding de sortie $2 qui vaut par défaut $NULIB_OUTPUT_ENCODING local value="$1" to="${2:-$NULIB_OUTPUT_ENCODING}" if [ "$to" == "$NULIB__UTF8" ]; then recho_ "$value" else recho_ "$value" | iconv -f utf-8 -t "$to" fi } export NULIB_QUIETLOG export NULIB__TMPLOG function: quietc "\ N'afficher la sortie de la commande \$@ que si on est en mode DEBUG ou si elle se termine en erreur" function quietc() { local r [ -z "$NULIB__TMPLOG" ] && ac_set_tmpfile NULIB__TMPLOG "$@" >&"$NULIB__TMPLOG"; r=$? [ -n "$NULIB_QUIETLOG" ] && cat "$NULIB__TMPLOG" >>"$NULIB_QUIETLOG" [ $r -ne 0 -o -n "$NULIB_DEBUG" ] && cat "$NULIB__TMPLOG" return $r } function: quietc_logto "\ Si quietc est utilisé, sauvegarder quand même la sortie dans le fichier \$1 Utiliser l'option -a pour ajouter au fichier au lieu de l'écraser e.g quietc_logto -a path/to/logfile Tous les autres arguments sont du contenu ajoutés au fichier, e.g quietc_logto -a path/to/logfile \"\\ ================================================================================ = \$(date +%F-%T)\"" function quietc_logto() { local append if [ "$1" == -a ]; then shift append=1 fi NULIB_QUIETLOG="$1"; shift [ -n "$NULIB_QUIETLOG" ] || return if [ -z "$append" ]; then >"$NULIB_QUIETLOG" fi if [ $# -gt 0 ]; then echo "$*" >>"$NULIB_QUIETLOG" fi } function: quietc_echo "Ajouter \$* dans le fichier mentionné par quietc_logto() le cas échéant" function quietc_echo() { if [ -n "$NULIB_QUIETLOG" ]; then echo "$*" >>"$NULIB_QUIETLOG" fi } # faut-il dater les messages des fonctions e* et action? # Faire NULIB_ELOG_DATE=1 en début de script pour activer cette fonctionnalité # faut-il rajouter aussi le nom du script? (nécessite NULIB_ELOG_DATE) # Faire NULIB_ELOG_MYNAME=1 en début de script pour activer cette fonctionnalité export NULIB_ELOG_DATE NULIB_ELOG_MYNAME function __edate() { [ -n "$NULIB_ELOG_DATE" ] || return local prefix="$(date +"[%F %T.%N] ")" [ -n "$NULIB_ELOG_MYNAME" ] && prefix="$prefix$MYNAME " echo "$prefix" } export NULIB_ELOG_OVERWRITE function __set_no_colors() { :; } function elogto() { # Activer NULIB_ELOG_DATE et rediriger STDOUT et STDERR vers le fichier $1 # Si deux fichiers sont spécifiés, rediriger STDOUT vers $1 et STDERR vers $2 # Si aucun fichier n'est spécifié, ne pas faire de redirection # Si la redirection est activée, forcer l'utilisation de l'encoding UTF8 # Si NULIB_ELOG_OVERWRITE=1, alors le fichier en sortie est écrasé. Sinon, les # lignes en sortie lui sont ajoutées NULIB_ELOG_DATE=1 NULIB_ELOG_MYNAME=1 if [ -n "$1" -a -n "$2" ]; then LANG=fr_FR.UTF8 NULIB_OUTPUT_ENCODING="$NULIB__UTF8" __set_no_colors 1 if [ -n "$NULIB_ELOG_OVERWRITE" ]; then exec >"$1" 2>"$2" else exec >>"$1" 2>>"$2" fi elif [ -n "$1" ]; then LANG=fr_FR.UTF8 NULIB_OUTPUT_ENCODING="$NULIB__UTF8" __set_no_colors 1 if [ -n "$NULIB_ELOG_OVERWRITE" ]; then exec >"$1" 2>&1 else exec >>"$1" 2>&1 fi fi } # variables utilisées pour l'affichage indenté des messages et des titres # NULIB__ESTACK est la liste des invocations de 'etitle' et 'action' en cours export NULIB__ESTACK NULIB__INDENT= function __eindent0() { # afficher le nombre d'espaces correspondant à l'indentation local indent="${NULIB__ESTACK//?/ }" indent="${indent% }$NULIB__INDENT" [ -n "$indent" ] && echo "$indent" } function __eindent() { # indenter les lignes de $1, sauf la première local -a lines; local line first=1 local indent="$(__eindent0)$2" setx -a lines=recho "$1" for line in "${lines[@]}"; do if [ -n "$first" ]; then recho "$line" first= else recho "$indent$line" fi done } function __complete() { # compléter $1 avec $3 jusqu'à obtenir une taille de $2 caractères local columns="${COLUMNS:-80}" local line="$1" maxi="${2:-$columns}" sep="${3:- }" while [ ${#line} -lt $maxi ]; do line="$line$sep" done echo "$line" } PRETTYOPTS=() function set_verbosity() { case "$1" in -D|--debug) NULIB_DEBUG=1;; esac } function check_verbosity() { return 0; } function get_verbosity_option() { :;} # tester respectivement si on doit afficher les messages d'erreur, # d'avertissement, d'information, de debug function show_error() { return 0; } function show_warn() { return 0; } function show_info() { return 0; } function show_verbose() { return 0; } function show_debug() { [ -n "$NULIB_DEBUG" ]; } # note: toutes les fonctions d'affichage e* écrivent sur stderr function esection() { # Afficher une section. Toutes les indentations sont remises à zéro show_info || return eval "$NULIB__DISABLE_SET_X" NULIB__ESTACK= __esection "$*" 1>&2 eval "$NULIB__ENABLE_SET_X" } function etitle() { # Afficher le titre $1. Le contenu sous des titres imbriqués est affiché # indenté. # - si $2..$* est spécifié, c'est une commande qui est lancée dans le contexte # du titre, ensuite le titre est automatiquement terminé # - sinon il faut terminer le titre explicitement avec eend local title="$1"; shift # etitle NULIB__ESTACK="$NULIB__ESTACK:t" if show_info; then eval "$NULIB__DISABLE_SET_X" __etitle "$title" 1>&2 eval "$NULIB__ENABLE_SET_X" fi # commande local r=0 if [ $# -gt 0 ]; then "$@"; r=$? eend fi return $r } function eend() { # Terminer un titre if [ "${NULIB__ESTACK%:t}" != "$NULIB__ESTACK" ]; then NULIB__ESTACK="${NULIB__ESTACK%:t}" fi } function edesc() { # Afficher une description sous le titre courant show_info || return eval "$NULIB__DISABLE_SET_X" __edesc "$*" 1>&2 eval "$NULIB__ENABLE_SET_X" } function ebanner() { # Afficher un message très important encadré, puis attendre 5 secondes show_error || return eval "$NULIB__DISABLE_SET_X" __ebanner "$*" 1>&2 eval "$NULIB__ENABLE_SET_X" sleep 5 } function eimportant() { # Afficher un message très important show_error || return eval "$NULIB__DISABLE_SET_X" __eimportant "$*" 1>&2 eval "$NULIB__ENABLE_SET_X" } function qimportant() { eimportant "$*"; quietc_echo "IMPORTANT: $*"; } function eattention() { # Afficher un message important show_warn || return eval "$NULIB__DISABLE_SET_X" __eattention "$*" 1>&2 eval "$NULIB__ENABLE_SET_X" } function qattention() { eattention "$*"; quietc_echo "ATTENTION: $*"; } function eerror() { # Afficher un message d'erreur show_error || return eval "$NULIB__DISABLE_SET_X" __eerror "$*" 1>&2 eval "$NULIB__ENABLE_SET_X" } function qerror() { eerror "$*"; quietc_echo "ERROR: $*"; } function eerror_unless() { # Afficher $1 avec eerror() si la commande $2..@ retourne FAUX. dans tous les cas, retourner le code de retour de la commande. local msg="$1"; shift local r=1 if [ $# -eq 0 ]; then [ -n "$msg" ] && eerror "$msg" else "$@"; r=$? if [ $r -ne 0 -a -n "$msg" ]; then eerror "$msg" fi fi return $r } function eerror_if() { # Afficher $1 avec eerror() si la commande $2..@ retourne VRAI. dans tous les cas, retourner le code de retour de la commande. local msg="$1"; shift local r=0 if [ $# -gt 0 ]; then "$@"; r=$? if [ $r -eq 0 -a -n "$msg" ]; then eerror "$msg" fi fi return $r } function set_die_return() { NULIB__DIE="return 1" } function die() { [ $# -gt 0 ] && eerror "$@" local die="${NULIB__DIE:-exit 1}" eval "$die" || return } function die_with { [ $# -gt 0 ] && eerror "$1" shift [ $# -gt 0 ] && "$@" local die="${NULIB__DIE:-exit 1}" eval "$die" || return } function die_unless() { # Afficher $1 et quitter le script avec die() si la commande $2..@ retourne FAUX local msg="$1"; shift local die="${NULIB__DIE:-exit 1}" local r=1 if [ $# -eq 0 ]; then [ -n "$msg" ] && eerror "$msg" else "$@"; r=$? if [ $r -ne 0 -a -n "$msg" ]; then eerror "$msg" fi fi if [ $r -ne 0 ]; then eval "${die% *} $r" || return $r fi return $r } function die_if() { # Afficher $1 et quitter le script avec die() si la commande $2..@ retourne VRAI. sinon, retourner le code de retour de la commande local msg="$1"; shift local die="${NULIB__DIE:-exit 1}" local r=0 if [ $# -gt 0 ]; then "$@"; r=$? if [ $r -eq 0 -a -n "$msg" ]; then eerror "$msg" fi fi if [ $r -eq 0 ]; then eval "${die% *} $r" || return $r fi return $r } function exit_with { if [ $# -gt 0 ]; then "$@"; fi exit $? } function ewarn() { # Afficher un message d'avertissement show_warn || return eval "$NULIB__DISABLE_SET_X" __ewarn "$*" 1>&2 eval "$NULIB__ENABLE_SET_X" } function qwarn() { ewarn "$*"; quietc_echo "WARN: $*"; } function enote() { # Afficher un message d'information de même niveau qu'un avertissement show_info || return eval "$NULIB__DISABLE_SET_X" __enote "$*" 1>&2 eval "$NULIB__ENABLE_SET_X" } function qnote() { enote "$*"; quietc_echo "NOTE: $*"; } function einfo() { # Afficher un message d'information show_info || return eval "$NULIB__DISABLE_SET_X" __einfo "$*" 1>&2 eval "$NULIB__ENABLE_SET_X" } function qinfo() { einfo "$*"; quietc_echo "INFO: $*"; } function eecho() { # Afficher un message d'information sans préfixe show_info || return eval "$NULIB__DISABLE_SET_X" __eecho "$*" 1>&2 eval "$NULIB__ENABLE_SET_X" } function qecho() { eecho "$*"; quietc_echo "$*"; } function eecho_() { show_info || return eval "$NULIB__DISABLE_SET_X" __eecho_ "$*" 1>&2 eval "$NULIB__ENABLE_SET_X" } function trace() { # Afficher la commande $1..@, la lancer, puis afficher son code d'erreur si une # erreur se produit local r cmd="$(qvals "$@")" show_info && { __eecho "\$ $cmd" 1>&2; } "$@"; r=$? if [ $r -ne 0 ]; then if show_info; then __eecho "^ [EC #$r]" 1>&2 elif show_error; then __eecho "^ $cmd [EC #$r]" 1>&2 fi fi return $r } function trace_error() { # Lancer la commande $1..@, puis afficher son code d'erreur si une erreur se # produit. La différence avec trace() est que la commande n'est affichée que si # une erreur se produit. local r "$@"; r=$? if [ $r -ne 0 ]; then local cmd="$(qvals "$@")" if show_error; then __eecho "^ $cmd [EC #$r]" 1>&2 fi fi return $r } function edebug() { # Afficher un message de debug show_debug || return eval "$NULIB__DISABLE_SET_X" __edebug "$*" 1>&2 eval "$NULIB__ENABLE_SET_X" } # Afficher la description d'une opération. Cette fonction est particulièrement # appropriée dans le contexte d'un etitle. # Les variantes e (error), w (warning), n (note), i (info) permettent d'afficher # des couleurs différentes, mais toutes sont du niveau info. function estep() { show_info || return; eval "$NULIB__DISABLE_SET_X"; __estep "$*" 1>&2; eval "$NULIB__ENABLE_SET_X"; } function estepe() { show_info || return; eval "$NULIB__DISABLE_SET_X"; __estepe "$*" 1>&2; eval "$NULIB__ENABLE_SET_X"; } function estepw() { show_info || return; eval "$NULIB__DISABLE_SET_X"; __estepw "$*" 1>&2; eval "$NULIB__ENABLE_SET_X"; } function estepn() { show_info || return; eval "$NULIB__DISABLE_SET_X"; __estepn "$*" 1>&2; eval "$NULIB__ENABLE_SET_X"; } function estepi() { show_info || return; eval "$NULIB__DISABLE_SET_X"; __estepi "$*" 1>&2; eval "$NULIB__ENABLE_SET_X"; } function estep_() { show_info || return; eval "$NULIB__DISABLE_SET_X"; __estep_ "$*" 1>&2; eval "$NULIB__ENABLE_SET_X"; } function estepe_() { show_info || return; eval "$NULIB__DISABLE_SET_X"; __estepe_ "$*" 1>&2; eval "$NULIB__ENABLE_SET_X"; } function estepw_() { show_info || return; eval "$NULIB__DISABLE_SET_X"; __estepw_ "$*" 1>&2; eval "$NULIB__ENABLE_SET_X"; } function estepn_() { show_info || return; eval "$NULIB__DISABLE_SET_X"; __estepn_ "$*" 1>&2; eval "$NULIB__ENABLE_SET_X"; } function estepi_() { show_info || return; eval "$NULIB__DISABLE_SET_X"; __estepi_ "$*" 1>&2; eval "$NULIB__ENABLE_SET_X"; } function qstep() { estep "$*"; quietc_echo "* $*"; } function action() { # commencer l'action $1 # - si $2..$* est spécifié, c'est une commande qui est lancée dans le contexte # de l'action, ensuite l'action est terminée en succès ou en échec suivant le # code de retour. ne pas afficher la sortie de la commande comme avec quietc() # - sinon il faut terminer le titre explicitement avec eend eval "$NULIB__DISABLE_SET_X" local action="$1"; shift local r=0 if [ $# -gt 0 ]; then [ -z "$NULIB__TMPLOG" ] && ac_set_tmpfile NULIB__TMPLOG [ -n "$action" ] && quietc_echo "$(__edate) ACTION: $action:" "$@" >&"$NULIB__TMPLOG"; r=$? [ -n "$NULIB_QUIETLOG" ] && cat "$NULIB__TMPLOG" >>"$NULIB_QUIETLOG" if [ $r -ne 0 -o -n "$NULIB_DEBUG" ]; then NULIB__ESTACK="$NULIB__ESTACK:a" [ -n "$action" ] && action="$action:" __action "$action" 1>&2 cat "$NULIB__TMPLOG" aresult $r else if [ $r -eq 0 ]; then [ -n "$action" ] || action="succès" __asuccess "$action" 1>&2 else [ -n "$action" ] || action="échec" __afailure "$action" 1>&2 fi fi else NULIB__ESTACK="$NULIB__ESTACK:a" [ -n "$action" ] && action="$action:" __action "$action" 1>&2 fi eval "$NULIB__ENABLE_SET_X" return $r } function asuccess() { # terminer l'action en cours avec le message de succès $* [ "${NULIB__ESTACK%:a}" != "$NULIB__ESTACK" ] || return eval "$NULIB__DISABLE_SET_X" [ -n "$*" ] || set -- "succès" NULIB__INDENT=" " __asuccess "$*" 1>&2 NULIB__ESTACK="${NULIB__ESTACK%:a}" eval "$NULIB__ENABLE_SET_X" return 0 } function afailure() { # terminer l'action en cours avec le message d'échec $* [ "${NULIB__ESTACK%:a}" != "$NULIB__ESTACK" ] || return eval "$NULIB__DISABLE_SET_X" [ -n "$*" ] || set -- "échec" NULIB__INDENT=" " __afailure "$*" 1>&2 NULIB__ESTACK="${NULIB__ESTACK%:a}" eval "$NULIB__ENABLE_SET_X" return 1 } function aresult() { # terminer l'action en cours avec un message de succès ou d'échec $2..* en # fonction du code de retour $1 (0=succès, sinon échec) [ "${NULIB__ESTACK%:a}" != "$NULIB__ESTACK" ] || return eval "$NULIB__DISABLE_SET_X" local r="${1:-0}"; shift if [ "$r" == 0 ]; then [ -n "$*" ] || set -- "succès" NULIB__INDENT=" " __asuccess "$*" 1>&2 else [ -n "$*" ] || set -- "échec" NULIB__INDENT=" " __afailure "$*" 1>&2 fi NULIB__ESTACK="${NULIB__ESTACK%:a}" eval "$NULIB__ENABLE_SET_X" return $r } function adone() { # terminer l'action en cours avec le message neutre $* [ "${NULIB__ESTACK%:a}" != "$NULIB__ESTACK" ] || return eval "$NULIB__DISABLE_SET_X" [ -n "$*" ] && NULIB__INDENT=" " __adone "$*" 1>&2 NULIB__ESTACK="${NULIB__ESTACK%:a}" eval "$NULIB__ENABLE_SET_X" return 0 }