début migration nulib

This commit is contained in:
Jephté Clain 2023-10-03 05:41:24 +04:00
parent 662bdb92dd
commit eba69bea41
19 changed files with 4236 additions and 0 deletions

30
.udir Normal file
View File

@ -0,0 +1,30 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
# Utiliser 'udir --help-vars' pour une description de la signification des
# variables suivantes:
udir_desc="librairies de base pour scripts bash, awk, php, python"
udir_note=""
udir_types=(uinst)
uinc=release
uinc_options=()
uinc_args=()
preconfig_scripts=()
configure_variables=(dest)
configure_dest_for=(lib/profile.d/nucore)
config_scripts=(lib/uinst/conf)
install_profiles=true
profiledir=lib/profile.d
bashrcdir=lib/bashrc.d
defaultdir=lib/default
workdir_rsync_options=()
workdir_excludes=()
workdir_includes=()
copy_files=true
destdir=/opt
destdir_override_userhost=
destdir_ssh=
destdir_force_remote=
srcdir=.
files=()
owner=root:
modes=(u=rwX,g=rX,o=rX)
root_scripts=(lib/uinst/rootconf)

176
bash/base.args.sh Normal file
View File

@ -0,0 +1,176 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
##@cooked nocomments
module: base.args "Fonctions de base: analyse d'arguments"
require: base.arr
function: myargs_local "Afficher des commandes pour rendre locales des variables utilisées par myargs()
Cela permet d'utiliser myargs() à l'intérieur d'une fonction. Par défaut, la génération automatique de l'autocomplete est désactivée."
function myargs_local() {
# par défaut, désactiver génération de autocomplete
echo "local NUCORE_ARGS_HELP_DESC NUCORE_ARGS_HELP_USAGE NUCORE_ARGS_HELP_OPTIONS args"
echo "local NUCORE_ARGS_DISABLE_AC=1"
echo "local NUCORE_ARGS_ONERROR_RETURN=1"
}
function: myargs: "Débuter la description des arguments reconnus par ce script.
Arguments
: \$1 est un résumé de l'objet de ce script
: \$2 est le nom du script s'il est différent de \$MYNAME
Le mode opératoire est généralement le suivant:
~~~
myargs:
desc \"faire un traitement\"
usage \"MYNAME [options] <args>\"
arg -o:,--output:file output= \"spécifier le fichier destination\"
arg -h:,--host:host hosts+ \"spécifier les hôtes concernés\"
arg -c,--count count=1
parse \"\$@\"; set -- \"\${args[@]}\"
~~~"
function myargs:() {
NUCORE_ARGS_HELP_DESC=
NUCORE_ARGS_HELP_USAGE=
NUCORE_ARGS_HELP_OPTIONS=()
args=()
function desc() { myargs_desc "$@"; }
function usage() { myargs_usage "$@"; }
function arg() { myargs_add "$@"; }
function parse() { myargs_parse "$@"; }
}
function: myargs_desc ""
function myargs_desc() {
NUCORE_ARGS_HELP_DESC="$*"
}
function: myargs_usage ""
function myargs_usage() {
NUCORE_ARGS_HELP_USAGE="$*"
}
function: myargs_add "Ajouter une définition d'option
Syntaxes
: arg MODE
: arg [MODE] -OPTIONS ACTION DESC
: arg [MODE] VARIABLE DESC
MODE peut être l'un des caractères '+', '-', '%' et a un effet sur l'analyse
entière de la ligne de commande
* Les caractères '+' et '-' influent sur la méthode d'analyse. Par défaut, les
options sont valides n'importe où sur la ligne de commande. Avec '+',
l'analyse s'arrête au premier argument qui n'est pas une option. Avec '-', les
options sont valides n'importe ou sur la ligne de commande, mais les arguments
ne sont pas réordonnés, et apparaissent dans l'ordre de leur mention.
* Le caractère '%' demande que toutes les variables mentionnées à partir de ce
moment soient initialisées. Elle sont garanties d'être vides.
Avec la première syntaxe, on définit précisément l'option. Deux formes sont
supportées. La forme détermine le type d'action
* Avec la forme '-OPT VAR[=VALUE]', OPT est une description d'option, VAR un nom
de variable à mettre à jour, et VALUE une valeur éventuelle pour les options
sans argument. Si plusieurs options sont mentionnées, séparées par des
virgules, alors tous les options partagent les mêmes paramètres.
OPT peut être de la forme '-o' ou '--longopt' pour des options sans arguments.
Dans ce cas, VAR obtient le nombre de fois que l'option est mentionnée (vide
pour aucune mention, '1' pour une seule mention, etc.), sauf si on utilise la
forme VAR=VALUE, auquel cas la variable obtient la valeur VALUE, et le nombre
d'occurences de l'option n'est pas compté.
Pour faciliter la lecture:
* '--longopt .' est équivalent à '--longopt longopt'
* '--longopt: .' est équivalent à '--longopt: longopt='
Avec les formes '-o:' et '--longopt:', l'option prend un argument obligatoire.
Avec les formes '-o::' et '--longopt::', l'option prend un argument facultatif
(dans ce cas, la valeur de l'option sur la ligne de commande doit
obligatoirement être collée à l'option.)
Si ces options sont mentionnées plusieurs fois sur la ligne de commande, alors
la variable de destination est un tableau qui contient toutes les valeurs. Le
traitement de la valeur d'une variable dépend de la forme utilisée.
* Avec une option sans argument, le comportement est celui décrit ci-dessus.
* Avec une option qui prend des arguments, la forme '-o: VAR' considère que
VAR est un tableau qui contiendra toutes les valeurs mentionnées dans les
options. Avec la forme '-o: VAR=', la variable n'est pas un tableau et
contient toujours la dernière valeur spécifiée.
* Dans la forme 'opt \$cmd', la commande cmd est executée avec eval *dès* que
l'option est rencontrée. La variable option_ contient l'option, e.g. '-o' ou
'--longopt'. Le cas échéant, la variable value_ contient la valeur de
l'option. La fonction 'set@ NAME' met à jour la variable NAME, soit en lui
donnant la valeur \$value_, soit en l'incrémentant, suivant le type d'option.
La fonction 'inc@ NAME' incrémente la variable NAME, 'res@ NAME [VALUE]'
initialise la variable à la valeur VALUE, 'add@ NAME [VALUE]' ajoute VALUE à
la fin du tableau NAME. Par défaut, VALUE vaut \$value_
Avec la deuxième syntaxe, l'option est déterminée sur la base du nom de la
variable.
* Une variable de la forme 'sansarg' est pour une option simple qui ne prend pas
d'argument
* Une variable de la forme 'avecarg=[default-value]' est pour une option qui
prend un argument.
L'option générée est une option longue. En l'occurence, les options générées
sont respectivement '--sansarg' et '--avecarg:'
Les variables et les options sont toujours en minuscule. Pour les variables, le
caractère '-' est remplacé par '_'. Si une option contient une lettre en
majuscule, l'option courte correspondante à cette lettre sera aussi reconnue.
"
function myargs_add() {
# description des options
array_add args "${@:1:2}"
# puis construire la description de l'option pour l'aide
local -a os; local o odesc
array_split os "$1" ,
for o in "${os[@]}"; do
o="${o%%:*}"
[ -n "$odesc" ] && odesc="$odesc, "
odesc="$odesc$o"
done
for o in "${os[@]}"; do
if [[ "$o" == *:* ]]; then
if [ "${2#\$}" != "$2" ]; then
o=ARG
else
o="${2%%=*}"
o="${o^^}"
fi
[ -n "$odesc" ] && odesc="$odesc "
odesc="$odesc$o"
fi
break
done
array_add NUCORE_ARGS_HELP_OPTIONS "$odesc"
[ -n "$3" ] && array_add NUCORE_ARGS_HELP_OPTIONS "$3"
}
function: myargs_show_help ""
function myargs_show_help() {
local help="$MYNAME"
[ -n "$NUCORE_ARGS_HELP_DESC" ] && help="$help: $NUCORE_ARGS_HELP_DESC"
[ -n "$NUCORE_ARGS_HELP_USAGE" ] && help="$help
USAGE
$NUCORE_ARGS_HELP_USAGE"
[ ${#NUCORE_ARGS_HELP_OPTIONS[*]} -gt 0 ] && help="$help
OPTIONS"
echo "$help"
for help in "${NUCORE_ARGS_HELP_OPTIONS[@]}"; do
echo "$help"
done
}
function: myargs_parse ""
function myargs_parse() {
[ -z "$NUCORE_NO_DISABLE_SET_X" ] && [[ $- == *x* ]] && { set +x; local NUCORE_ARGS_SET_X=1; }
local r=0
if ! parse_opts "${PRETTYOPTS[@]}" "${args[@]}" @ args -- "$@"; then
edie "$args"
r=$?
fi
[ -n "$NUCORE_ARGS_SET_X" ] && set -x; return $r
}

361
bash/base.arr.sh Normal file
View File

@ -0,0 +1,361 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
##@cooked nocomments
module: base.arr "Fonctions de base: gestion des variables tableaux"
require: base.core base.str
function: array_count "retourner le nombre d'éléments du tableau \$1"
function array_count() {
eval "echo \${#$1[*]}"
}
function: array_isempty "tester si le tableau \$1 est vide"
function array_isempty() {
eval "[ \${#$1[*]} -eq 0 ]"
}
function: array_new "créer un tableau vide dans la variable \$1"
function array_new() {
eval "$1=()"
}
function: array_copy "copier le contenu du tableau \$2 dans le tableau \$1"
function array_copy() {
eval "$1=(\"\${$2[@]}\")"
}
function: array_add "ajouter les valeurs \$2..@ à la fin du tableau \$1"
function array_add() {
local __aa_a="$1"; shift
eval "$__aa_a+=(\"\$@\")"
}
function: array_ins "insérer les valeurs \$2..@ au début du tableau \$1"
function array_ins() {
local __aa_a="$1"; shift
eval "$__aa_a=(\"\$@\" \"\${$__aa_a[@]}\")"
}
function: array_del "supprimer *les* valeurs \$2 du tableau \$1"
function array_del() {
local __ad_v
local -a __ad_vs
eval '
for __ad_v in "${'"$1"'[@]}"; do
if [ "$__ad_v" != "$2" ]; then
__ad_vs=("${__ad_vs[@]}" "$__ad_v")
fi
done'
array_copy "$1" __ad_vs
}
function: array_addu "ajouter la valeur \$2 au tableau \$1, si la valeur n'y est pas déjà
Retourner vrai si la valeur a été ajoutée"
function array_addu() {
local __as_v
eval '
for __as_v in "${'"$1"'[@]}"; do
[ "$__as_v" == "$2" ] && return 1
done'
array_add "$1" "$2"
return 0
}
function: array_insu "insérer la valeur \$2 au début du tableau tableau \$1, si la valeur n'y est pas déjà
Retourner vrai si la valeur a été ajoutée."
function array_insu() {
local __as_v
eval '
for __as_v in "${'"$1"'[@]}"; do
[ "$__as_v" == "$2" ] && return 1
done'
array_ins "$1" "$2"
return 0
}
function: array_fillrange "Initialiser le tableau \$1 avec les nombres de \$2(=1) à \$3(=10) avec un step de \$4(=1)"
function array_fillrange() {
local -a __af_vs
local __af_i="${2:-1}" __af_to="${3:-10}" __af_step="${4:-1}"
while [ "$__af_i" -le "$__af_to" ]; do
__af_vs=("${__af_vs[@]}" "$__af_i")
__af_i=$(($__af_i + $__af_step))
done
array_copy "$1" __af_vs
}
function: array_eq "tester l'égalité des tableaux \$1 et \$2"
function array_eq() {
local -a __ae_a1 __ae_a2
array_copy __ae_a1 "$1"
array_copy __ae_a2 "$2"
[ ${#__ae_a1[*]} -eq ${#__ae_a2[*]} ] || return 1
local __ae_v __ae_i=0
for __ae_v in "${__ae_a1[@]}"; do
[ "$__ae_v" == "${__ae_a2[$__ae_i]}" ] || return 1
__ae_i=$(($__ae_i + 1))
done
return 0
}
function: array_contains "tester si le tableau \$1 contient la valeur \$2"
function array_contains() {
local __ac_v
eval '
for __ac_v in "${'"$1"'[@]}"; do
[ "$__ac_v" == "$2" ] && return 0
done'
return 1
}
function: array_icontains "tester si le tableau \$1 contient la valeur \$2, sans tenir compte de la casse"
function array_icontains() {
local __ac_v
eval '
for __ac_v in "${'"$1"'[@]}"; do
[ "${__ac_v,,} == "${2,,}" ] && return 0
done'
return 1
}
function: array_find "si le tableau \$1 contient la valeur \$2, afficher l'index de la valeur. Si le tableau \$3 est spécifié, afficher la valeur à l'index dans ce tableau"
function array_find() {
local __af_i __af_v
__af_i=0
eval '
for __af_v in "${'"$1"'[@]}"; do
if [ "$__af_v" == "$2" ]; then
if [ -n "$3" ]; then
recho "${'"$3"'[$__af_i]}"
else
echo "$__af_i"
fi
return 0
fi
__af_i=$(($__af_i + 1))
done'
return 1
}
function: array_reverse "Inverser l'ordre des élément du tableau \$1"
function array_reverse() {
local -a __ar_vs
local __ar_v
array_copy __ar_vs "$1"
array_new "$1"
for __ar_v in "${__ar_vs[@]}"; do
array_ins "$1" "$__ar_v"
done
}
function: array_replace "dans le tableau \$1, remplacer toutes les occurences de \$2 par \$3..*"
function array_replace() {
local __ar_sn="$1"; shift
local __ar_f="$1"; shift
local -a __ar_s __ar_d
local __ar_v
array_copy __ar_s "$__ar_sn"
for __ar_v in "${__ar_s[@]}"; do
if [ "$__ar_v" == "$__ar_f" ]; then
__ar_d=("${__ar_d[@]}" "$@")
else
__ar_d=("${__ar_d[@]}" "$__ar_v")
fi
done
array_copy "$__ar_sn" __ar_d
}
function: array_each "Pour chacune des valeurs ITEM du tableau \$1, appeler la fonction \$2 avec les arguments (\$3..@ ITEM)"
function array_each() {
local __ae_v
local -a __ae_a
array_copy __ae_a "$1"; shift
for __ae_v in "${__ae_a[@]}"; do
"$@" "$__ae_v"
done
}
function: array_map "Pour chacune des valeurs ITEM du tableau \$1, appeler la fonction \$2 avec les arguments (\$3..@ ITEM), et remplacer la valeur par le résultat de la fonction"
function array_map() {
local __am_v
local -a __am_a __am_vs
local __am_an="$1"; shift
local __am_f="$1"; shift
array_copy __am_a "$__am_an"
for __am_v in "${__am_a[@]}"; do
__am_vs=("${__am_vs[@]}" "$("$__am_f" "$@" "$__am_v")")
done
array_copy "$__am_an" __am_vs
}
function: array_first "afficher la première valeur du tableau \$1"
function array_first() {
eval "recho \"\${$1[@]:0:1}\""
}
function: array_last "afficher la dernière valeur du tableau \$1"
function array_last() {
eval "recho \"\${$1[@]: -1:1}\""
}
function: array_copy_firsts "copier toutes les valeurs du tableau \$2(=\$1) dans le tableau \$1, excepté la dernière"
function array_copy_firsts() {
eval "$1=(\"\${${2:-$1}[@]:0:\$((\${#${2:-$1}[@]}-1))}\")"
}
function: array_copy_lasts "copier toutes les valeurs du tableau \$2(=\$1) dans le tableau \$1, excepté la première"
function array_copy_lasts() {
eval "$1=(\"\${${2:-$1}[@]:1}\")"
}
function: array_extend "ajouter le contenu du tableau \$2 au tableau \$1"
function array_extend() {
eval "$1=(\"\${$1[@]}\" \"\${$2[@]}\")"
}
function: array_extendu "ajouter chacune des valeurs du tableau \$2 au tableau \$1, si ces valeurs n'y sont pas déjà
Retourner vrai si au moins une valeur a été ajoutée"
function array_extendu() {
local __ae_v __ae_s=1
eval '
for __ae_v in "${'"$2"'[@]}"; do
array_addu "$1" "$__ae_v" && __ae_s=0
done'
return "$__ae_s"
}
function: array_extend_firsts "ajouter toutes les valeurs du tableau \$2 dans le tableau \$1, excepté la dernière"
function array_extend_firsts() {
eval "$1=(\"\${$1[@]}\" \"\${$2[@]:0:\$((\${#$2[@]}-1))}\")"
}
function: array_extend_lasts "ajouter toutes les valeurs du tableau \$2 dans le tableau \$1, excepté la première"
function array_extend_lasts() {
eval "$1=(\"\${$1[@]}\" \"\${$2[@]:1}\")"
}
function: array_xsplit "créer le tableau \$1 avec chaque élément de \$2 (un ensemble d'éléments séparés par \$3, qui vaut ':' par défaut)"
function array_xsplit() {
eval "$1=($(recho_ "$2" | lawk -v RS="${3:-:}" '
{
gsub(/'\''/, "'\'\\\\\'\''")
print "'\''" $0 "'\''"
}'))" #"
}
function: array_xsplitc "variante de array_xsplit() où le séparateur est ',' par défaut"
function array_xsplitc() {
array_xsplit "$1" "$2" "${3:-,}"
}
function: array_split "créer le tableau \$1 avec chaque élément de \$2 (un ensemble d'éléments séparés par \$3, qui vaut ':' par défaut)
Les éléments vides sont ignorés. par exemple \"a::b\" est équivalent à \"a:b\""
function array_split() {
eval "$1=($(recho_ "$2" | lawk -v RS="${3:-:}" '
/^$/ { next }
{
gsub(/'\''/, "'\'\\\\\'\''")
print "'\''" $0 "'\''"
}'))" #"
}
function: array_splitc "variante de array_split() où le séparateur est ',' par défaut"
function array_splitc() {
array_split "$1" "$2" "${3:-,}"
}
function: array_xsplitl "créer le tableau \$1 avec chaque ligne de \$2"
function array_xsplitl() {
eval "$1=($(recho_ "$2" | strnl2lf | lawk '
{
gsub(/'\''/, "'\'\\\\\'\''")
print "'\''" $0 "'\''"
}'))" #"
}
function: array_splitl "créer le tableau \$1 avec chaque ligne de \$2
Les lignes vides sont ignorés."
function array_splitl() {
eval "$1=($(recho_ "$2" | strnl2lf | lawk '
/^$/ { next }
{
gsub(/'\''/, "'\'\\\\\'\''")
print "'\''" $0 "'\''"
}'))" #"
}
function: array_join "afficher le contenu du tableau \$1 sous forme d'une liste de valeurs séparées par \$2 (qui vaut ':' par défaut)
* Si \$1==\"@\", alors les éléments du tableaux sont les arguments de la fonction à partir de \$3
* Si \$1!=\"@\" et que le tableau est vide, afficher \$3
* Si \$1!=\"@\", \$4 et \$5 sont des préfixes et suffixes à rajouter à chaque élément"
function array_join() {
local __aj_an __aj_l __aj_j __aj_s="${2:-:}" __aj_pf __aj_sf
if [ "$1" == "@" ]; then
__aj_an="\$@"
shift; shift
else
__aj_an="\${$1[@]}"
__aj_pf="$4"
__aj_sf="$5"
fi
eval '
for __aj_l in "'"$__aj_an"'"; do
__aj_j="${__aj_j:+$__aj_j'"$__aj_s"'}$__aj_pf$__aj_l$__aj_sf"
done'
if [ -n "$__aj_j" ]; then
recho "$__aj_j"
elif [ "$__aj_an" != "\$@" -a -n "$3" ]; then
recho "$3"
fi
}
function: array_joinc "afficher les éléments du tableau \$1 séparés par ','"
function array_joinc() {
array_join "$1" , "$2" "$3" "$4"
}
function: array_joinl "afficher les éléments du tableau \$1 à raison d'un élément par ligne"
function array_joinl() {
array_join "$1" "
" "$2" "$3" "$4"
}
function: array_mapjoin "map le tableau \$1 avec la fonction \$2, puis afficher le résultat en séparant chaque élément par \$3
Les arguments et la sémantique sont les mêmes que pour array_join() en
tenant compte de l'argument supplémentaire \$2 qui est la fonction pour
array_map() (les autres arguments sont décalés en conséquence)"
function array_mapjoin() {
local __amj_src="$1" __amj_func="$2" __amj_sep="$3"
shift; shift; shift
if [ "$__amj_src" == "@" ]; then
local -a __amj_tmpsrc
__amj_tmpsrc=("$@")
__amj_src=__amj_tmpsrc
set --
fi
local -a __amj_tmp
array_copy __amj_tmp "$__amj_src"
array_map __amj_tmp "$__amj_func"
array_join __amj_tmp "$__amj_sep" "$@"
}
function: array_fix_paths "Corriger les valeurs du tableau \$1. Les valeurs contenant le séparateur \$2(=':') sont séparées en plusieurs valeurs.
Par exemple avec le tableau input=(a b:c), le résultat est input=(a b c)"
function array_fix_paths() {
local __afp_an="$1" __afp_s="${2:-:}"
local -a __afp_vs
local __afp_v
array_copy __afp_vs "$__afp_an"
array_new "$__afp_an"
for __afp_v in "${__afp_vs[@]}"; do
array_split __afp_v "$__afp_v" "$__afp_s"
array_extend "$__afp_an" __afp_v
done
}

458
bash/base.core.sh Normal file
View File

@ -0,0 +1,458 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
##@cooked nocomments
module: base.core "Fonctions de base: fondement"
function: echo_ "afficher la valeur \$* sans passer à la ligne"
function echo_() { echo -n "$*"; }
function: recho "afficher une valeur brute.
contrairement à la commande echo, ne reconnaitre aucune option (i.e. -e, -E, -n
ne sont pas signifiants)"
function recho() {
if [[ "${1:0:2}" == -[eEn] ]]; then
local first="${1:1}"; shift
echo -n -
echo "$first" "$@"
else
echo "$@"
fi
}
function: recho_ "afficher une valeur brute, sans passer à la ligne.
contrairement à la commande echo, ne reconnaitre aucune option (i.e. -e, -E, -n
ne sont pas signifiants)"
function recho_() {
if [[ "${1:0:2}" == -[eEn] ]]; then
local first="${1:1}"; shift
echo -n -
echo -n "$first" "$@"
else
echo -n "$@"
fi
}
function: _qval "Dans la chaine \$*, remplacer:
~~~
\\ par \\\\
\" par \\\"
\$ par \\\$
\` par \\\`
~~~
Cela permet de quoter une chaine à mettre entre guillements.
note: la protection de ! n'est pas effectuée, parce que le comportement du shell
est incohérent entre le shell interactif et les scripts. Pour une version plus
robuste, il est nécessaire d'utiliser un programme externe tel que sed ou awk"
function _qval() {
local s="$*"
s="${s//\\/\\\\}"
s="${s//\"/\\\"}"
s="${s//\$/\\\$}"
s="${s//\`/\\\`}"
recho_ "$s"
}
function: should_quote "Tester si la chaine \$* doit être mise entre quotes"
function should_quote() {
# pour optimiser, toujours mettre entre quotes si plusieurs arguments sont
# spécifiés ou si on spécifie une chaine vide ou de plus de 80 caractères
[ $# -eq 0 -o $# -gt 1 -o ${#1} -eq 0 -o ${#1} -gt 80 ] && return 0
# sinon, tester si la chaine contient des caractères spéciaux
local s="$*"
s="${s//[a-zA-Z0-9]/}"
s="${s//,/}"
s="${s//./}"
s="${s//+/}"
s="${s//\//}"
s="${s//-/}"
s="${s//_/}"
s="${s//=/}"
[ -n "$s" ]
}
function: qval "Afficher la chaine \$* quotée avec \""
function qval() {
echo -n \"
_qval "$@"
echo \"
}
function: qvalm "Afficher la chaine \$* quotée si nécessaire avec \""
function qvalm() {
if should_quote "$@"; then
echo -n \"
_qval "$@"
echo \"
else
recho "$@"
fi
}
function: qvalr "Afficher la chaine \$* quotée si nécessaire avec \", sauf si elle est vide"
function qvalr() {
if [ -z "$*" ]; then
:
elif should_quote "$@"; then
echo -n \"
_qval "$@"
echo \"
else
recho "$@"
fi
}
function: qvals "Afficher chaque argument de cette fonction quotée le cas échéant avec \", chaque valeur étant séparée par un espace"
function qvals() {
local arg first=1
for arg in "$@"; do
[ -z "$first" ] && echo -n " "
if should_quote "$arg"; then
echo -n \"
_qval "$arg"
echo -n \"
else
recho_ "$arg"
fi
first=
done
[ -z "$first" ] && echo
}
function: qwc "Dans la chaine \$*, remplacer:
~~~
\\ par \\\\
\" par \\\"
\$ par \\\$
\` par \\\`
~~~
puis quoter la chaine avec \", sauf les wildcards *, ? et [class]
Cela permet de quoter une chaine permettant de glober des fichiers, e.g
~~~
eval \"ls \$(qwc \"\$value\")\"
~~~
note: la protection de ! n'est pas effectuée, parce que le comportement du shell
est incohérent entre le shell interactif et les scripts. Pour une version plus
robuste, il est nécessaire d'utiliser un programme externe tel que sed ou awk"
function qwc() {
local s="$*"
s="${s//\\/\\\\}"
s="${s//\"/\\\"}"
s="${s//\$/\\\$}"
s="${s//\`/\\\`}"
local r a b c
while [ -n "$s" ]; do
a=; b=; c=
a=; [[ "$s" == *\** ]] && { a="${s%%\**}"; a=${#a}; }
b=; [[ "$s" == *\?* ]] && { b="${s%%\?*}"; b=${#b}; }
c=; [[ "$s" == *\[* ]] && { c="${s%%\[*}"; c=${#c}; }
if [ -z "$a" -a -z "$b" -a -z "$c" ]; then
r="$r\"$s\""
break
fi
if [ -n "$a" ]; then
[ -n "$b" ] && [ $a -lt $b ] && b=
[ -n "$c" ] && [ $a -lt $c ] && c=
fi
if [ -n "$b" ]; then
[ -n "$a" ] && [ $b -lt $a ] && a=
[ -n "$c" ] && [ $b -lt $c ] && c=
fi
if [ -n "$c" ]; then
[ -n "$a" ] && [ $c -lt $a ] && a=
[ -n "$b" ] && [ $c -lt $b ] && b=
fi
if [ -n "$a" ]; then # PREFIX*
a="${s%%\**}"
s="${s#*\*}"
[ -n "$a" ] && r="$r\"$a\""
r="$r*"
elif [ -n "$b" ]; then # PREFIX?
a="${s%%\?*}"
s="${s#*\?}"
[ -n "$a" ] && r="$r\"$a\""
r="$r?"
elif [ -n "$c" ]; then # PREFIX[class]
a="${s%%\[*}"
b="${s#*\[}"; b="${b%%\]*}"
s="${s:$((${#a} + ${#b} + 2))}"
[ -n "$a" ] && r="$r\"$a\""
r="$r[$b]"
fi
done
recho_ "$r"
}
function: qlines "Traiter chaque ligne de l'entrée standard pour en faire des chaines quotées avec '"
function qlines() {
sed "s/'/'\\\\''/g; s/.*/'&'/g"
}
function: setv "initialiser la variable \$1 avec la valeur \$2..*
note: en principe, la syntaxe est 'setv var values...'. cependant, la syntaxe 'setv var=values...' est supportée aussi"
function setv() {
local s__var="$1"; shift
if [[ "$s__var" == *=* ]]; then
set -- "${s__var#*=}" "$@"
s__var="${s__var%%=*}"
fi
eval "$s__var=\"\$*\""
}
function: _setv "Comme la fonction setv() mais ne supporte que la syntaxe '_setv var values...'
Cette fonction est légèrement plus rapide que setv()"
function _setv() {
local s__var="$1"; shift
eval "$s__var=\"\$*\""
}
function: echo_setv "Afficher la commande qui serait lancée par setv \"\$@\""
function echo_setv() {
local s__var="$1"; shift
if [[ "$s__var" == *=* ]]; then
set -- "${s__var#*=}" "$@"
s__var="${s__var%%=*}"
fi
echo "$s__var=$(qvalr "$*")"
}
function: echo_setv2 "Afficher la commande qui recrée la variable \$1.
Equivalent à
~~~
echo_setv \"\$1=\${!1}\"
~~~
Si d'autres arguments que le nom de la variable sont spécifiés, cette fonction
se comporte comme echo_setv()"
function echo_setv2() {
local s__var="$1"; shift
if [[ "$s__var" == *=* ]]; then
set -- "${s__var#*=}" "$@"
s__var="${s__var%%=*}"
fi
if [ $# -eq 0 ]; then
echo_setv "$s__var" "${!s__var}"
else
echo_setv "$s__var" "$@"
fi
}
function: seta "initialiser le tableau \$1 avec les valeurs \$2..@
note: en principe, la syntaxe est 'seta array values...'. cependant, la syntaxe
'seta array=values...' est supportée aussi"
function seta() {
local s__array="$1"; shift
if [[ "$s__array" == *=* ]]; then
set -- "${s__array#*=}" "$@"
s__array="${s__array%%=*}"
fi
eval "$s__array=(\"\$@\")"
}
function: _seta "Comme la fonction seta() mais ne supporte que la syntaxe '_seta array values...'
Cette fonction est légèrement plus rapide que seta()"
function _seta() {
local s__array="$1"; shift
eval "$s__array=(\"\$@\")"
}
function: echo_seta "Afficher la commande qui serait lancée par seta \"\$@\""
function echo_seta() {
local s__var="$1"; shift
if [[ "$s__var" == *=* ]]; then
set -- "${s__var#*=}" "$@"
s__var="${s__var%%=*}"
fi
echo "$s__var=($(qvals "$@"))"
}
function: echo_seta2 "Afficher la commande qui recrée le tableau \$1
Si d'autres arguments que le nom de tableau sont spécifiés, cette fonction se
comporte comme echo_seta()"
function echo_seta2() {
local s__var="$1"; shift
if [[ "$s__var" == *=* ]]; then
set -- "${s__var#*=}" "$@"
s__var="${s__var%%=*}"
elif [ $# -eq 0 ]; then
eval "set -- \"\${$s__var[@]}\""
fi
echo "$s__var=($(qvals "$@"))"
}
function: setx "Initialiser une variable avec le résultat d'une commande
* syntaxe 1: initialiser la variable \$1 avec le résultat de la commande \"\$2..@\"
~~~
setx var cmd
~~~
note: en principe, la syntaxe est 'setx var cmd args...'. cependant, la syntaxe
'setx var=cmd args...' est supportée aussi
* syntaxe 2: initialiser le tableau \$1 avec le résultat de la commande
\"\$2..@\", chaque ligne du résultat étant un élément du tableau
~~~
setx -a array cmd
~~~
note: en principe, la syntaxe est 'setx -a array cmd args...'. cependant, la
syntaxe 'setx -a array=cmd args...' est supportée aussi"
function setx() {
if [ "$1" == -a ]; then
shift
local s__array="$1"; shift
if [[ "$s__array" == *=* ]]; then
set -- "${s__array#*=}" "$@"
s__array="${s__array%%=*}"
fi
eval "$s__array=($("$@" | qlines))"
else
local s__var="$1"; shift
if [[ "$s__var" == *=* ]]; then
set -- "${s__var#*=}" "$@"
s__var="${s__var%%=*}"
fi
eval "$s__var="'"$("$@")"'
fi
}
function: _setvx "Comme la fonction setx() mais ne supporte que l'initialisation d'une variable scalaire avec la syntaxe '_setvx var cmd args...' pour gagner (un peu) en rapidité d'exécution."
function _setvx() {
local s__var="$1"; shift
eval "$s__var="'"$("$@")"'
}
function: _setax "Comme la fonction setx() mais ne supporte que l'initialisation d'un tableau avec la syntaxe '_setax array cmd args...' pour gagner (un peu) en rapidité d'exécution."
function _setax() {
local s__array="$1"; shift
eval "$s__array=($("$@" | qlines))"
}
function: is_defined "tester si la variable \$1 est définie"
function is_defined() {
[ -n "$(declare -p "$1" 2>/dev/null)" ]
}
function: is_array "tester si la variable \$1 est un tableau"
function is_array() {
[[ "$(declare -p "$1" 2>/dev/null)" =~ declare\ -[^\ ]*a[^\ ]*\ ]]
}
function: array_local "afficher les commandes pour faire une copie dans la variable locale \$1 du tableau \$2"
function array_local() {
if [ "$1" == "$2" ]; then
declare -p "$1" 2>/dev/null || echo "local -a $1"
else
echo "local -a $1; $1=(\"\${$2[@]}\")"
fi
}
function: upvar "Implémentation de upvar() de http://www.fvue.nl/wiki/Bash:_Passing_variables_by_reference
USAGE
~~~
local varname && upvar varname values...
~~~
* @param varname Variable name to assign value to
* @param values Value(s) to assign. If multiple values (> 1), an array is
assigned, otherwise a single value is assigned."
function upvar() {
if unset -v "$1"; then
if [ $# -lt 2 ]; then
eval "$1=\"\$2\""
else
eval "$1=(\"\${@:2}\")"
fi
fi
}
function: array_upvar "Comme upvar() mais force la création d'un tableau, même s'il y a que 0 ou 1 argument"
function array_upvar() {
unset -v "$1" && eval "$1=(\"\${@:2}\")"
}
function: upvars "Implémentation modifiée de upvars() de http://www.fvue.nl/wiki/Bash:_Passing_variables_by_reference
Par rapport à l'original, il n'est plus nécessaire de préfixer une variable
scalaire avec -v, et -a peut être spécifié sans argument.
USAGE
~~~
local varnames... && upvars [varname value | -aN varname values...]...
~~~
* @param -a assigns remaining values to varname as array
* @param -aN assigns next N values to varname as array. Returns 1 if wrong
number of options occurs"
function upvars() {
while [ $# -gt 0 ]; do
case "$1" in
-a)
unset -v "$2" && eval "$2=(\"\${@:3}\")"
break
;;
-a*)
unset -v "$2" && eval "$2=(\"\${@:3:${1#-a}}\")"
shift $((${1#-a} + 2)) || return 1
;;
*)
unset -v "$1" && eval "$1=\"\$2\""
shift; shift
;;
esac
done
}
function: set_debug "Passer en mode DEBUG"
function set_debug() {
export NUCORE_DEBUG=1
}
function: is_debug "Tester si on est en mode DEBUG"
function is_debug() {
[ -n "$NUCORE_DEBUG" ]
}
function: lawk "Lancer GNUawk avec la librairie 'base'"
function lawk() {
gawk -i base.awk "$@"
}
function: cawk "Lancer GNUawk avec LANG=C et la librairie 'base'
Le fait de forcer la valeur de LANG permet d'éviter les problèmes avec la locale"
function cawk() {
LANG=C gawk -i base.awk "$@"
}
function: lsort "Lancer sort avec support de la locale courante"
function: csort "Lancer sort avec LANG=C pour désactiver le support de la locale
Avec LANG!=C, sort utilise les règles de la locale pour le tri, et par
exemple, avec LANG=fr_FR.UTF-8, la locale indique que les ponctuations doivent
être ignorées."
function lsort() { sort "$@"; }
function csort() { LANG=C sort "$@"; }
function: lgrep "Lancer grep avec support de la locale courante"
function: cgrep "Lancer grep avec LANG=C pour désactiver le support de la locale"
function lgrep() { grep "$@"; }
function cgrep() { LANG=C grep "$@"; }
function: lsed "Lancer sed avec support de la locale courante"
function: csed "Lancer sed avec LANG=C pour désactiver le support de la locale"
function lsed() { sed "$@"; }
function csed() { LANG=C sed "$@"; }
function: ldiff "Lancer diff avec support de la locale courante"
function: cdiff "Lancer diff avec LANG=C pour désactiver le support de la locale"
function ldiff() { diff "$@"; }
function cdiff() { LANG=C diff "$@"; }

468
bash/base.eval.sh Normal file
View File

@ -0,0 +1,468 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
##@cooked nocomments
module: base.eval "Fonctions de base: évaluation d'expressions"
require: base.str base.arr
################################################################################
# Chaines
function: evals "Appliquer à une chaine de caractères une suite de traitements, e.g:
~~~
evals var deref +suffix
~~~
est équivalent à
~~~
echo \"\${var}suffix\"
~~~
En commençant avec la valeur initiale \$1, les arguments \$2..* sont des
opérations à appliquer dans l'ordre.
Les opérations suivantes considèrent que la valeur courante est un nom de
variable:
~~~
:- := :? :+ deref dcount
~~~
Toutes les autres opérations travaillent directement avec la valeur
courante. Les opérations suivantes appliquent une transformation:
~~~
# % / : ^ , +# -# +% -% + - mid repl
~~~
IMPORTANT: aucune de ces fonctions ne met en échappement les valeur des
patterns. Ainsi, si un pattern contient des caractères interdits comme \\ ou \$,
il faut d'abord le traiter avec _qval()
Les opérations suivantes font un test sur la valeur et retournent immédiatement:
~~~
= == != < > -eq -ne -lt -le -gt -ge -n -z
~~~
La syntaxe des opérateurs standards de bash est reprise autant que possible, i.e
si on a l'habitude d'écrire ${varOP} en bash, alors la syntaxe à utiliser à
priori est 'evals var OP' ou 'evals var deref OP' suivant les
opérateurs.
Autres opérateurs:
~~~
deref indirection
dcount nombre d'éléments du tableau
+#STR ajouter un préfixe
-#STR supprimer un préfixe
+%STR ou +STR ajouter un suffixe
-%STR ou -STR supprimer un suffixe
mid RANGE traiter la chaine avec strmid()
repl FROM TO traiter la chaine avec strrepl()
~~~
Tout autre opérateur est traité comme un appel à une fonction qui prend un seul
argument, la valeur courante, et qui affiche le résultat."
function evals() {
local -a es__tmp
local es__value="$1"; shift
while [ $# -gt 0 ]; do
case "$1" in
# l'argument est le nom de la variable
:-*|:=*|:\?*|:+*) eval 'es__value="${'"${es__value}$1"'}"';;
d|deref) es__value="${!es__value}";;
dc|dcount|ds|dsize)
es__value="${es__value}[@]"
es__tmp=("${!es__value}")
es__value="${#es__tmp[@]}"
;;
# l'argument est la valeur de la variable
\#*|%*|/*|:*|^*|,*) eval 'es__value="${es__value'"$1"'}"';;
l|length) es__value="${#es__value}";;
=|==|!=|\<|\>|-eq|-ne|-lt|-le|-gt|-ge)
es__tmp=(\[ "$es__value" "$@" ]); "${es__tmp[@]}"; return $?;;
-n|-z) es__tmp=(\[ "$1" "$es__value" ]); "${es__tmp[@]}"; return $?;;
+#*) eval 'es__value="'"${1#+#}"'$es__value"';;
-#*) eval 'es__value="${es__value'"${1#-}"'}"';;
+%*) eval 'es__value="$es__value"'"${1#+%}";;
+*) eval 'es__value="$es__value"'"${1#+}";;
-%*) eval 'es__value="${es__value'"${1#-}"'}"';;
-*) eval 'es__value="${es__value%'"${1#-}"'}"';;
mid|strmid) eval 'es__value="$(strmid "$2" "$es__value")"'; shift;;
repl|strrepl) eval 'es__value="$(strrepl "$2" "$3" "$es__value")"'; shift; shift;;
*) es__value="$("$1" "$es__value")";;
esac
shift
done
echo "$es__value"
}
function: setxs "équivalent à setx \$1 evals \$2..@"
function setxs() {
local -a ss__args
if [ "$1" == -a ]; then ss__args=(-a); shift; fi
local ss__var="$1"; shift
if [[ "$ss__var" == *=* ]]; then
set -- "${ss__var#*=}" "$@"
ss__var="${ss__var%%=*}"
fi
ss__args=("${ss__args[@]}" "$ss__var")
setx "${ss__args[@]}" evals "$@"
}
function: cmds "lancer une commande avec comme argument le résultat de evals
Par exemple, les deux commandes suivantes sont équivalentes:
~~~
cmds CMD ARGS... // EVALARGS
CMD ARGS... \"\$(evals EVALARGS)\"
~~~"
function cmds() {
local cs__arg
local -a cs__cmd
while [ $# -gt 0 ]; do
cs__arg="$1"; shift
[ "$cs__arg" == // ] && break
cs__cmd=("${cs__cmd[@]}" "$cs__arg")
done
"${cs__cmd[@]}" "$(evals "$@")"
}
function: evalm "construire une chaine en mixant chaines statiques et évaluations de commandes
Par exemple, les deux commandes suivantes sont équivalentes:
~~~
evalm //\"string\" cmd args // cmd args //\"string\"
echo \"string\$(cmd args)\$(cmd args)string\"
~~~"
function evalm() {
local em__val em__arg
local -a em__cmd
while [ $# -gt 0 ]; do
em__arg="$1"
if [ "${em__arg#//}" != "$em__arg" ]; then
em__val="$em__val${em__arg#//}"
shift
continue
fi
em__cmd=()
while [ $# -gt 0 ]; do
em__arg="$1"
[ "${em__arg#//}" != "$em__arg" ] && break
shift
if [ "${em__arg%//}" != "$em__arg" ]; then
local em__tmp="${em__arg%//}"
if [ -z "${em__tmp//\\/}" ]; then
em__arg="${em__arg#\\}"
em__cmd=("${em__cmd[@]}" "$em__arg")
continue
fi
fi
em__cmd=("${em__cmd[@]}" "$em__arg")
done
[ ${#em__cmd[*]} -gt 0 ] && em__val="$em__val$("${em__cmd[@]}")"
done
echo "$em__val"
}
function: setxm "équivalent à setx \$1 evalm \$2..@"
function setxm() {
local -a sm__args
if [ "$1" == -a ]; then sm__args=(-a); shift; fi
local sm__var="$1"; shift
if [[ "$sm__var" == *=* ]]; then
set -- "${sm__var#*=}" "$@"
sm__var="${sm__var%%=*}"
fi
sm__args=("${sm__args[@]}" "$sm__var")
setx "${sm__args[@]}" evalm "$@"
}
function: cmdm "lancer une commande avec comme argument le résultat de evalm
Par exemple, les deux commandes suivantes sont équivalentes:
~~~
cmdm CMD ARGS... // EVALARGS
CMD ARGS... \"\$(evalm EVALARGS)\"
~~~"
function cmdm() {
local cm__arg
local -a cm__cmd
while [ $# -gt 0 ]; do
cm__arg="$1"; shift
[ "$cm__arg" == // ] && break
cm__cmd=("${cm__cmd[@]}" "$cm__arg")
done
"${cm__cmd[@]}" "$(evalm "$@")"
}
################################################################################
# Nombres
function: evali "Evaluer une expression numérique"
function evali() {
echo "$(($*))"
}
################################################################################
# Tableaux
################################################################################
# Composition
function: evalc "Implémenter une syntaxe lisible et naturelle permettant d'enchainer des traitements sur une valeur.
Par exemple, la commande
~~~
evalc cmd1... // cmd2... // cmd3...
~~~
est équivalente à la commande
~~~
cmd3... \"\$(cmd2... \"\$(cmd1...)\")\"
~~~"
function evalc() {
local ec__arg ec__cmd ec__finalcmd
while [ $# -gt 0 ]; do
ec__arg="$1"; shift
if [ "$ec__arg" == // ]; then
if [ ${#ec__cmd} -gt 0 ]; then
if [ ${#ec__finalcmd} -eq 0 ]; then ec__finalcmd="$ec__cmd"
else ec__finalcmd="$ec__cmd \$($ec__finalcmd)"
fi
fi
ec__cmd=
continue
elif [ "${ec__arg%//}" != "$ec__arg" ]; then
local tmp="${ec__arg%//}"
[ -z "${tmp//\\/}" ] && ec__arg="${ec__arg#\\}"
fi
ec__cmd="$ec__cmd \"$(_qval "$ec__arg")\""
done
if [ ${#ec__cmd} -gt 0 ]; then
if [ ${#ec__finalcmd} -eq 0 ]; then ec__finalcmd="$ec__cmd"
else ec__finalcmd="$ec__cmd \$($ec__finalcmd)"
fi
fi
eval "$ec__finalcmd"
}
function: setxc "équivalent à setx \$1 evalc \$2..@"
function setxc() {
local -a sx__args
if [ "$1" == -a ]; then sx__args=(-a); shift; fi
local sx__var="$1"; shift
if [[ "$sx__var" == *=* ]]; then
set -- "${sx__var#*=}" "$@"
sx__var="${sx__var%%=*}"
fi
sx__args=("${sx__args[@]}" "$sx__var")
setx "${sx__args[@]}" evalc "$@"
}
################################################################################
# Chainage
function: evalp "Implémenter une syntaxe alternative permettant d'enchainer des traitements sur un flux de données.
Par exemple, la commande
~~~
evalp cmd1... // cmd2... // cmd3...
~~~
affiche le résultat de la commande
~~~
cmd1... | cmd2... | cmd3...
~~~
Typiquement, cette fonction permet de faciliter la *construction* d'un
enchainement de commandes par programme, ou de faciliter l'utilisation de la
fonction setx() pour récupérer le résultat d'un enchainement. Dans les autres
cas, il est plus simple et naturel d'écrire les enchainements avec la syntaxe de
bash."
function evalp() {
local ep__arg ep__cmd
while [ $# -gt 0 ]; do
ep__arg="$1"; shift
if [ "$ep__arg" == // ]; then
ep__cmd="$ep__cmd |"
continue
elif [ "${ep__arg%//}" != "$ep__arg" ]; then
local ep__tmp="${ep__arg%//}"
if [ -z "${ep__tmp//\\/}" ]; then
ep__arg="${ep__arg#\\}"
fi
fi
ep__cmd="${ep__cmd:+$ep__cmd }\"$(_qval "$ep__arg")\""
done
eval "$ep__cmd"
}
function: setxp "équivalent à setx \$1 evalp \$2..@"
function setxp() {
local -a sp__args
if [ "$1" == -a ]; then sp__args=(-a); shift; fi
local sp__var="$1"; shift
if [[ "$sp__var" == *=* ]]; then
set -- "${sp__var#*=}" "$@"
sp__var="${sp__var%%=*}"
fi
sp__args=("${sp__args[@]}" "$sp__var")
setx "${sp__args[@]}" evalp "$@"
}
function: cmdp "lancer une commande avec comme argument le résultat de evalp
Par exemple, les deux commandes suivantes sont équivalentes:
~~~
cmdp CMD ARGS... // EVALARGS
CMD ARGS... \"\$(evalp EVALARGS)\"
~~~"
function cmdp() {
local cp__arg
local -a cp__cmd
while [ $# -gt 0 ]; do
cp__arg="$1"; shift
[ "$cp__arg" == // ] && break
cp__cmd=("${cp__cmd[@]}" "$cp__arg")
done
"${cp__cmd[@]}" "$(evalp "$@")"
}
################################################################################
# Générique
function: evalx ""
function evalx() {
:
}
function: setxx "équivalent à setx \$1 evalx \$2..@"
function setxx() {
local -a sx__args
if [ "$1" == -a ]; then sx__args=(-a); shift; fi
local sx__var="$1"; shift
if [[ "$sx__var" == *=* ]]; then
set -- "${sx__var#*=}" "$@"
sx__var="${sx__var%%=*}"
fi
sx__args=("${sx__args[@]}" "$sx__var")
setx "${sx__args[@]}" evalx "$@"
}
function: cmdx "lancer une commande avec comme argument le résultat de evalx
Par exemple, les deux commandes suivantes sont équivalentes:
~~~
cmdx CMD ARGS... // EVALARGS
CMD ARGS... \"\$(evalx EVALARGS)\"
~~~"
function cmdx() {
local cx__arg
local -a cx__cmd
while [ $# -gt 0 ]; do
cx__arg="$1"; shift
[ "$cx__arg" == // ] && break
cx__cmd=("${cx__cmd[@]}" "$cx__arg")
done
"${cx__cmd[@]}" "$(evalx "$@")"
}
function: cmdsplitf "\
Cette fonction doit être appelée avec N arguments (avec N>1). Elle analyse et
découpe l'argument \$N comme avec une ligne de commande du shell. Ensuite, elle
appelle la fonction \$1 avec les arguments de \$2 à \${N-1}, suivi des arguments
obtenus lors de l'analyse de l'argument \$N. Par exemple, la commande suivante:
~~~
strsplitf cmd arg1 \"long arg2\" \"arg3 'long arg4'\"
~~~
est équivalente à:
~~~
cmd arg1 \"long arg2\" arg3 \"long arg4\"
~~~
Retourner le code 127 si la fonction à appeler n'est pas spécifiée. Retourner le
code 126 si une erreur s'est produite lors de l'analyse de l'argument \$N"
function cmdsplitf() {
[ $# -gt 0 ] || return 127
local func count
func="$1"; shift
count=$#
if [ $count -gt 0 ]; then
eval 'set -- "${@:1:$(($count-1))}" '"${!count}" || return 126
fi
"$func" "$@"
}
################################################################################
# Tests
function: testx "Faire un test unaire avec la commande [ sur une valeur calculée avec evalx.
Utiliser la syntaxe 'testx op cmds...' e.g.
~~~
testx -z cmd1 // cmd2
~~~"
function testx() {
local t__op="$1"; shift
local t__val="$(evalx "$@")"
[ $t__op "$t__val" ]
}
function: test2x "Faire une test binaire avec la commande [ entre une valeur spécifiée et une valeur calculée avec evalx.
Utiliser la syntaxe 'test2x value op cmds...' e.g.
~~~
test2x value == cmd1 // cmd2
~~~"
function test2x() {
local t__val1="$1"; shift
local t__op="$1"; shift
local t__val2="$(evalx "$@")"
[ "$t__val1" $t__op "$t__val2" ]
}
function: testrx "Faire une test binaire avec la commande [[ entre une valeur spécifiée et une valeur calculée avec evalx.
Utiliser la syntaxe 'testrx value op cmds...' e.g.
~~~
testrx value == cmd1 // cmd2
~~~"
function testrx() {
local t__val1="$1"; shift
local t__op="$1"; shift
local t__val2="$(evalx "$@")"
eval '[[ "$t__val1" '"$t__op"' "$t__val2" ]]'
}
function: testp "Faire un test unaire avec la commande [ sur une valeur calculée avec evalp.
Utiliser la syntaxe 'testp op cmds...' e.g.
~~~
testp -z cmd1 // cmd2
~~~"
function testp() {
local t__op="$1"; shift
local t__val="$(evalp "$@")"
[ $t__op "$t__val" ]
}
function: test2p "Faire une test binaire avec la commande [ entre une valeur spécifiée et une valeur calculée avec evalp.
Utiliser la syntaxe 'test2p value op cmds...' e.g.
~~~
test2p value == cmd1 // cmd2
~~~"
function test2p() {
local t__val1="$1"; shift
local t__op="$1"; shift
local t__val2="$(evalp "$@")"
[ "$t__val1" $t__op "$t__val2" ]
}
function: testrp "Faire une test binaire avec la commande [[ entre une valeur spécifiée et une valeur calculée avec evalp.
Utiliser la syntaxe 'testrp value op cmds...' e.g.
~~~
testrp value == cmd1 // cmd2
~~~"
function testrp() {
local t__val1="$1"; shift
local t__op="$1"; shift
local t__val2="$(evalp "$@")"
eval '[[ "$t__val1" '"$t__op"' "$t__val2" ]]'
}

53
bash/base.init.sh Normal file
View File

@ -0,0 +1,53 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
##@cooked nocomments
module: base.init "Fonctions de base: initialiser l'environnement"
if [ -z "$NUCORE_NO_INIT_ENV" ]; then
# Emplacement du script courant
if [ "$0" == "-bash" ]; then
MYNAME=
MYDIR=
MYSELF=
elif [ ! -f "$0" -a -f "${0#-}" ]; then
MYNAME="$(basename -- "${0#-}")"
MYDIR="$(dirname -- "${0#-}")"
MYDIR="$(cd "$MYDIR"; pwd)"
MYSELF="$MYDIR/$MYNAME"
else
MYNAME="$(basename -- "$0")"
MYDIR="$(dirname -- "$0")"
MYDIR="$(cd "$MYDIR"; pwd)"
MYSELF="$MYDIR/$MYNAME"
fi
[ -n "$NUCOREDIR" ] || NUCOREDIR="$MYDIR"
# Repertoire temporaire
[ -z "$TMPDIR" -a -d "$HOME/tmp" ] && TMPDIR="$HOME/tmp"
[ -z "$TMPDIR" ] && TMPDIR="${TMP:-${TEMP:-/tmp}}"
export TMPDIR
# User
[ -z "$USER" -a -n "$LOGNAME" ] && export USER="$LOGNAME"
# Le fichier nucorerc doit être chargé systématiquement
[ -f /etc/debian_chroot ] && NUCORE_CHROOT=1
[ -f /etc/nucorerc ] && . /etc/nucorerc
[ -f ~/.nucorerc ] && . ~/.nucorerc
# Type de système sur lequel tourne le script
UNAME_SYSTEM=`uname -s`
[ "${UNAME_SYSTEM#CYGWIN}" != "$UNAME_SYSTEM" ] && UNAME_SYSTEM=Cygwin
[ "${UNAME_SYSTEM#MINGW32}" != "$UNAME_SYSTEM" ] && UNAME_SYSTEM=Mingw
UNAME_MACHINE=`uname -m`
if [ -n "$NUCORE_CHROOT" ]; then
# Dans un chroot, il est possible de forcer les valeurs
[ -n "$NUCORE_UNAME_SYSTEM" ] && eval "UNAME_SYSTEM=$NUCORE_UNAME_SYSTEM"
[ -n "$NUCORE_UNAME_MACHINE" ] && eval "UNAME_MACHINE=$NUCORE_UNAME_MACHINE"
fi
# Nom d'hôte respectivement avec et sans domaine
# contrairement à $HOSTNAME, cette valeur peut être spécifiée, comme par ruinst
[ -n "$MYHOST" ] || MYHOST="$HOSTNAME"
[ -n "$MYHOSTNAME" ] || MYHOSTNAME="${HOSTNAME%%.*}"
export MYHOST MYHOSTNAME
fi

1291
bash/base.io.sh Normal file

File diff suppressed because it is too large Load Diff

158
bash/base.path.sh Normal file
View File

@ -0,0 +1,158 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
##@cooked nocomments
module: base.path "Fonctions de base: gestion des chemins et des fichiers"
require: base.core
function: in_path "tester l'existence d'un programme dans le PATH"
function in_path() {
[ -n "$1" -a -x "$(which "$1" 2>/dev/null)" ]
}
function: delpath "supprimer le chemin \$1 de \$2(=PATH)"
function delpath() {
local _qdir="${1//\//\\/}"
eval "export ${2:-PATH}; ${2:-PATH}"'="${'"${2:-PATH}"'#$1:}"; '"${2:-PATH}"'="${'"${2:-PATH}"'%:$1}"; '"${2:-PATH}"'="${'"${2:-PATH}"'//:$_qdir:/:}"; [ "$'"${2:-PATH}"'" == "$1" ] && '"${2:-PATH}"'='
}
function: addpath "Ajouter le chemin \$1 à la fin, dans \$2(=PATH), s'il n'y existe pas déjà"
function addpath() {
local _qdir="${1//\//\\/}"
eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="${'"${2:-PATH}"':+$'"${2:-PATH}"':}$1"'
}
function: inspathm "Ajouter le chemin \$1 au début, dans \$2(=PATH), s'il n'y existe pas déjà"
function inspathm() {
local _qdir="${1//\//\\/}"
eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="$1${'"${2:-PATH}"':+:$'"${2:-PATH}"'}"'
}
function: inspath "S'assurer que le chemin \$1 est au début de \$2(=PATH)"
function inspath() {
delpath "$@"
inspathm "$@"
}
function: push_cwd "enregistrer le répertoire courant dans la variable \$2(=cwd) et se placer dans le répertoire \$1"
function push_cwd() {
eval "${2:-cwd}"'="$(pwd)"'
cd "$1"
}
function: pop_cwd "se placer dans le répertoire \${!\$2}(=\$cwd) puis retourner le code d'erreur \$1(=0)"
function pop_cwd() {
eval 'cd "$'"${2:-cwd}"'"'
return "${1:-0}"
}
################################################################################
## fichiers temporaires
function: mktempf "générer un fichier temporaire et retourner son nom"
function mktempf() {
mktemp "${1:-"$TMPDIR/tmp.XXXXXX"}"
}
function: mktempd "générer un répertoire temporaire et retourner son nom"
function mktempd() {
mktemp -d "${1:-"$TMPDIR/tmp.XXXXXX"}"
}
function ac__forgetall() { NUCORE__AC_FILES=(); }
ac__forgetall
function ac__trap() {
local file
for file in "${NUCORE__AC_FILES[@]}"; do
[ -e "$file" ] && rm -rf "$file" 2>/dev/null
done
ac__forgetall
}
trap ac__trap 1 3 15 EXIT
function: autoclean "\
Ajouter les fichiers spécifiés à la liste des fichiers à supprimer à la fin du
programme"
function autoclean() {
local file
for file in "$@"; do
[ -n "$file" ] && NUCORE__AC_FILES=("${NUCORE__AC_FILES[@]}" "$file")
done
}
function: ac_cleanall "\
Supprimer *tous* les fichiers temporaires gérés par autoclean tout de suite."
function ac_cleanall() {
ac__trap
}
function: ac_clean "\
Supprimer les fichier temporaires \$1..@ si et seulement s'ils ont été générés
par ac_set_tmpfile() ou ac_set_tmpdir()"
function ac_clean() {
local file acfile found
local -a acfiles
for acfile in "${NUCORE__AC_FILES[@]}"; do
found=
for file in "$@"; do
if [ "$file" == "$acfile" ]; then
found=1
[ -e "$file" ] && rm -rf "$file" 2>/dev/null
break
fi
done
[ -z "$found" ] && acfiles=("${acfiles[@]}" "$acfile")
done
NUCORE__AC_FILES=("${acfiles[@]}")
}
function: ac_set_tmpfile "\
Créer un fichier temporaire avec le motif \$2, l'ajouter à la liste des
fichiers à supprimer en fin de programme, et mettre sa valeur dans la
variable \$1
En mode debug, si (\$5 est vide ou \${!5} est une valeur vraie), et si \$3 n'est
pas vide, prendre ce fichier au lieu de générer un nouveau fichier temporaire.
Si \$4==keep, ne pas écraser le fichier \$3 s'il existe."
function ac_set_tmpfile() {
local se__d
if is_debug; then
if [ -n "$5" ]; then
is_yes "${!5}" && se__d=1
else
se__d=1
fi
fi
if [ -n "$se__d" -a -n "$3" ]; then
_setv "$1" "$3"
[ -f "$3" -a "$4" == keep ] || >"$3"
else
local se__t="$(mktempf "$2")"
autoclean "$se__t"
_setv "$1" "$se__t"
fi
}
function: ac_set_tmpdir "\
Créer un répertoire temporaire avec le motif \$2, l'ajouter à la liste des
fichiers à supprimer en fin de programme, et mettre sa valeur dans la
variable \$1
En mode debug, si (\$4 est vide ou \${!4} est une valeur vraie), et si \$3 n'est
pas vide, prendre ce nom de répertoire au lieu de créer un nouveau répertoire
temporaire"
function ac_set_tmpdir() {
local sr__d
if is_debug; then
if [ -n "$4" ]; then
is_yes "${!4}" && sr__d=1
else
sr__d=1
fi
fi
if [ -n "$sr__d" -a -n "$3" ]; then
_setv "$1" "$3"
mkdir -p "$3"
else
local sr__t="$(mktempd "$2")"
autoclean "$sr__t"
_setv "$1" "$sr__t"
fi
}

19
bash/base.sh Normal file
View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
##@cooked nocomments
# shim pour les fonctions de nucore.sh au cas où ce module n'est pas chargée
if [ -z "$NUCOREDIR" -o "$NUCOREDIR" != "$NUCOREINIT" ]; then
function module:() { :; }
function function:() { :; }
function require:() { :; }
fi
##@include base.init.sh
##@include base.core.sh
##@include base.str.sh
##@include base.arr.sh
##@include base.io.sh
##@include base.eval.sh
##@include base.split.sh
##@include base.path.sh
##@include base.args.sh
module: base "Chargement de tous les modules base.*"
require: base.init base.core base.str base.arr base.io base.eval base.split base.path base.args

189
bash/base.split.sh Normal file
View File

@ -0,0 +1,189 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
##@cooked nocomments
module: base.split "Fonctions de base: analyse et découpage de valeurs"
require: base.arr
function: splitfsep "\
Découper \$1 de la forme first[SEPsecond] entre first, qui est placé dans la
variable \$3(=first) et second, qui est placée dans la variable \$4(=second). \$2
est la valeur SEP. Le découpage est faite sur la *première* occurence de SEP."
function splitfsep() {
if [[ "$1" == *"$2"* ]]; then
setv "${3:-first}" "${1%%$2*}"
setv "${4:-second}" "${1#*$2}"
else
setv "${3:-first}" "$1"
setv "${4:-second}"
fi
}
function: splitfsep2 "\
Découper \$1 de la forme [firstSEP]second entre first, qui est placé dans la
variable \$3(=first) et second, qui est placée dans la variable \$4(=second). \$2
est la valeur SEP. Le découpage est faite sur la *première* occurence de SEP."
function splitfsep2() {
if [[ "$1" == *"$2"* ]]; then
setv "${3:-first}" "${1%%$2*}"
setv "${4:-second}" "${1#*$2}"
else
setv "${3:-first}"
setv "${4:-second}" "$1"
fi
}
function: splitlsep "\
Découper \$1 de la forme first[SEPsecond] entre first, qui est placé dans la
variable \$3(=first) et second, qui est placée dans la variable \$4(=second). \$2
est la valeur SEP. Le découpage est faite sur la *dernière* occurence de SEP."
function splitlsep() {
if [[ "$1" == *"$2"* ]]; then
setv "${3:-first}" "${1%$2*}"
setv "${4:-second}" "${1##*$2}"
else
setv "${3:-first}" "$1"
setv "${4:-second}"
fi
}
function: splitlsep2 "\
Découper \$1 de la forme [firstSEP]second entre first, qui est placé dans la
variable \$3(=first) et second, qui est placée dans la variable \$4(=second). \$2
est la valeur SEP. Le découpage est faite sur la *dernière* occurence de SEP."
function splitlsep2() {
if [[ "$1" == *"$2"* ]]; then
setv "${3:-first}" "${1%$2*}"
setv "${4:-second}" "${1##*$2}"
else
setv "${3:-first}"
setv "${4:-second}" "$1"
fi
}
function: splitvar "\
Découper \$1 de la forme name[=value] entre le nom, qui est placé dans la
variable \$2(=name) et la valeur, qui est placée dans la variable \$3(=value)"
function splitvar() {
splitfsep "$1" = "${2:-name}" "${3:-value}"
}
function: splitpath "\
Découper \$1 de la forme [dir/]name entre le répertoire, qui est placé dans la
variable \$2(=dir), et le nom du fichier, qui est placé dans la variable
\$3(=name)"
function splitpath() {
splitlsep2 "$1" / "${2:-dir}" "${3:-name}"
}
function: splitname "\
Découper \$1 de la forme basename[.ext] entre le nom de base du fichier, qui
est placé dans la variable \$2(=basename) et l'extension, qui est placée dans
la variable \$3(=ext)
Attention, si \$1 est un chemin, le résultat risque d'être faussé. Par exemple,
'splitname a.b/c' ne donne pas le résultat escompté."
function splitname() {
splitlsep "$1" . "${2:-basename}" "${3:-ext}"
}
function: splithost "\
Découper \$1 de la forme hostname[.domain] entre le nom d'hôte, qui est placé
dans la variable \$2(=hostname) et le domaine, qui est placée dans la variable
\$3(=domain)"
function splithost() {
splitfsep "$1" . "${2:-hostname}" "${3:-domain}"
}
function: splituserhost "\
Découper \$1 de la forme [user@]host entre le nom de l'utilisateur, qui est placé
dans la variable \$2(=user) et le nom d'hôte, qui est placée dans la variable
\$3(=host)"
function splituserhost() {
splitfsep2 "$1" @ "${2:-user}" "${3:-host}"
}
function: splitpair "\
Découper \$1 de la forme first[:second] entre la première valeur, qui est placé
dans la variable \$2(=src) et la deuxième valeur, qui est placée dans la variable
\$3(=dest)"
function splitpair() {
splitfsep "$1" : "${2:-src}" "${3:-dest}"
}
function: splitproxy "\
Découper \$1 de la forme http://[user:password@]host[:port]/ entre les valeurs
\$2(=host), \$3(=port), \$4(=user), \$5(=password)
S'il n'est pas spécifié, port vaut 3128 par défaut"
function splitproxy() {
local sy__tmp sy__host sy__port sy__creds sy__user sy__password
sy__tmp="${1#http://}"
if [[ "$sy__tmp" == *@* ]]; then
sy__creds="${sy__tmp%%@*}"
sy__tmp="${sy__tmp#${sy__creds}@}"
splitpair "$sy__creds" sy__user sy__password
fi
sy__tmp="${sy__tmp%%/*}"
splitpair "$sy__tmp" sy__host sy__port
[ -n "$sy__port" ] || sy__port=3128
setv "${2:-host}" "$sy__host"
setv "${3:-port}" "$sy__port"
setv "${4:-user}" "$sy__user"
setv "${5:-password}" "$sy__password"
}
function: spliturl "\
Découper \$1 de la forme scheme://[user:password@]host[:port]/path entre les
valeurs \$2(=scheme), \$3(=user), \$4(=password), \$5(=host), \$6(=port), \$7(=path)
S'il n'est pas spécifié, port vaut 80 pour http, 443 pour https, 21 pour ftp"
function spliturl() {
local sl__tmp sl__scheme sl__creds sl__user sl__password sl__host sl__port sl__path
sl__scheme="${1%%:*}"
sl__tmp="${1#${sl__scheme}://}"
if [[ "$sl__tmp" == */* ]]; then
sl__path="${sl__tmp#*/}"
sl__tmp="${sl__tmp%%/*}"
fi
if [[ "$sl__tmp" == *@* ]]; then
sl__creds="${sl__tmp%%@*}"
sl__tmp="${sl__tmp#${sl__creds}@}"
splitpair "$sl__creds" sl__user sl__password
fi
splitpair "$sl__tmp" sl__host sl__port
if [ -z "$sl__port" ]; then
[ "$sl__scheme" == "http" ] && sl__port=80
[ "$sl__scheme" == "https" ] && sl__port=443
[ "$sl__scheme" == "ftp" ] && sl__port=21
fi
setv "${2:-scheme}" "$sl__scheme"
setv "${3:-user}" "$sl__user"
setv "${4:-password}" "$sl__password"
setv "${5:-host}" "$sl__host"
setv "${6:-port}" "$sl__port"
setv "${7:-path}" "$sl__path"
}
function: splitwcs "\
Découper un nom de chemin \$1 entre la partie sans wildcards, qui est placée dans
la variables \$2(=basedir), et la partie avec wildcards, qui est placée dans la
variable \$3(=filespec)"
function splitwcs() {
local ss__p="$1"
local ss__dd="${2:-basedir}" ss__df="${3:-filespec}" ss__part ss__d ss__f
local -a ss__parts
array_split ss__parts "$ss__p" "/"
for ss__part in "${ss__parts[@]}"; do
if [[ "$ss__part" == *\** ]] || [[ "$ss__part" == *\?* ]] || [ -n "$ss__f" ]; then
ss__f="${ss__f:+$ss__f/}$ss__part"
else
ss__d="${ss__d:+$ss__d/}$ss__part"
fi
done
[ "${ss__p#/}" != "$ss__p" ] && ss__d="/$ss__d"
_setv "$ss__dd" "$ss__d"
_setv "$ss__df" "$ss__f"
}

140
bash/base.str.sh Normal file
View File

@ -0,0 +1,140 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
##@cooked nocomments
module: base.str "Fonctions de base: gestion des valeurs chaines"
function: strmid "Afficher la plage \$1 de la valeur \$2..*
La plage peut être d'une des formes 'start', '[start]:length'. Si start est
négatif, le compte est effectué à partir de la fin de la chaine. Si length est
négatif, il est rajouté à la longueur de la chaine à partir de start"
function strmid() {
local range="$1"; shift
local str="$*"
if [[ "$range" == *:-* ]]; then
local max=${#str}
[ $max -eq 0 ] && return
local start="${range%%:*}"
[ -n "$start" ] || start=0
while [ "$start" -lt 0 ]; do
start=$(($max$start))
done
max=$(($max-$start))
local length="${range#*:}"
while [ "$length" -lt 0 ]; do
length=$(($max$length))
done
range="$start:$length"
fi
eval 'echo "${str:'" $range"'}"'
}
function: strrepl "Remplacer dans la valeur \$3..* le motif \$1 par la chaine \$2
\$1 peut commencer par l'un des caractères /, #, % pour indiquer le type de recherche"
function strrepl() {
local pattern="$1"; shift
local repl="$1"; shift
local str="$*"
local cmd='echo "${str/'
if [ "${pattern#/}" != "$pattern" ]; then
pattern="${pattern#/}"
cmd="$cmd/"
elif [ "${pattern#\#}" != "$pattern" ]; then
pattern="${pattern#\#}"
cmd="$cmd#"
elif [ "${pattern#%}" != "$pattern" ]; then
pattern="${pattern#%}"
cmd="$cmd%"
fi
cmd="$cmd"'$pattern/$repl}"'
eval "$cmd"
}
function: strlcomp "transformer dans le flux en entrée en UTF-8 certains caractères en leur équivalent transformable en latin1.
si cette fonction est appelée avec des arguments, prendre \$* comme valeur du flux en entrée."
function strlcomp() {
if [ $# -gt 0 ]; then strlcomp <<<"$*"
else LANG=fr_FR.UTF-8 sed $'
s/[\xE2\x80\x90\xE2\x80\x91\xE2\x80\x92\xE2\x80\x93\xE2\x80\x94\xE2\x80\x95]/-/g
s/[]/\x27/g
s/[«»“”]/"/g
s/[\xC2\xA0\xE2\x80\x87\xE2\x80\xAF\xE2\x81\xA0]/ /g
s/[\xE2\x80\xA6]/.../g
s/[œ]/oe/g
s/[Œ]/OE/g
s/[æ]/ae/g
s/[Æ]/AE/g
s/a\xCC\x80/à/g
s/e\xCC\x81/é/g; s/e\xCC\x80/è/g; s/e\xCC\x82/ê/g; s/e\xCC\x88/ë/g
s/i\xCC\x88/ï/g; s/i\xCC\x82/î/g
s/o\xCC\x82/ô/g; s/o\xCC\x88/ö/g
s/u\xCC\x88/ü/g; s/u\xCC\x82/û/g
s/c\xCC\xA7/ç/g
s/A\xCC\x80/À/g
s/E\xCC\x81/É/g; s/E\xCC\x80/È/g; s/E\xCC\x82/Ê/g; s/E\xCC\x88/Ë/g
s/I\xCC\x88/Ï/g; s/I\xCC\x82/Î/g
s/O\xCC\x82/Ô/g; s/O\xCC\x88/Ö/g
s/U\xCC\x88/Ü/g; s/U\xCC\x82/Û/g
s/C\xCC\xA7/Ç/g
'
fi
}
function: strnacc "supprimer les accents dans le flux en entrée en UTF-8
si cette fonction est appelée avec des arguments, prendre \$* comme valeur du flux en entrée."
function strnacc() {
if [ $# -gt 0 ]; then strnacc <<<"$*"
else LANG=fr_FR.UTF-8 sed '
s/[à]/a/g
s/[éèêë]/e/g
s/[ïî]/i/g
s/[ôö]/o/g
s/[üû]/u/g
s/[ç]/c/g
s/[À]/A/g
s/[ÉÈÊË]/E/g
s/[ÏÎ]/I/g
s/[ÔÖ]/O/g
s/[ÜÛ]/U/g
s/[Ç]/C/g
'
fi
}
function: stripnl "Supprimer dans le flux en entrée les caractères de fin de ligne
si cette fonction est appelée avec des arguments, prendre \$* comme valeur du flux en entrée."
function stripnl() {
if [ $# -gt 0 ]; then stripnl <<<"$*"
else tr -d '\r\n'
fi
}
function: nl2lf "transformer dans le flux en entrée les fins de ligne en LF
si cette fonction est appelée avec des arguments, prendre \$* comme valeur du flux en entrée."
function nl2lf() {
if [ $# -gt 0 ]; then nl2lf <<<"$*"
else lawk 'BEGIN {RS="\r|\r\n|\n"} {print}'
fi
}
function: nl2crlf "transformer dans le flux en entrée les fins de ligne en CRLF
si cette fonction est appelée avec des arguments, prendre \$* comme valeur du flux en entrée."
function nl2crlf() {
if [ $# -gt 0 ]; then nl2crlf <<<"$*"
else lawk 'BEGIN {RS="\r|\r\n|\n"} {print $0 "\r"}'
fi
}
function: nl2cr "transformer dans le flux en entrée les fins de ligne en CR
si cette fonction est appelée avec des arguments, prendre \$* comme valeur du flux en entrée."
function nl2cr() {
if [ $# -gt 0 ]; then nl2cr <<<"$*"
else lawk 'BEGIN {RS="\r|\r\n|\n"; ORS=""} {print $0 "\r"}'
fi
}

704
bash/git.sh Normal file
View File

@ -0,0 +1,704 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
##@cooked nocomments
##@require nucore.sh
##@require base
module: git "Fonctions pour faciliter l'utilisation de git"
require: nucore base
function: git_geturl ""
function git_geturl() {
git config --get remote.origin.url
}
function: git_have_annex ""
function git_have_annex() {
[ -n "$(git config --get annex.uuid)" ]
}
NUCORE_GIT_FUNCTIONS=(
git_check_gitvcs git_ensure_gitvcs
git_list_branches git_list_rbranches
git_have_branch git_have_rbranch
git_get_branch git_is_branch
git_have_remote git_track_branch
git_check_cleancheckout git_ensure_cleancheckout
git_is_ancestor git_should_ff git_should_push
git_is_merged
)
NUCORE_GIT_FUNCTIONS_MAP=(
cg:git_check_gitvcs eg:git_ensure_gitvcs
lbs:git_list_branches rbs:git_list_rbranches
hlb:git_have_branch hrb:git_have_rbranch
gb:git_get_branch ib:git_is_branch
hr:git_have_remote tb:git_track_branch
cc:git_check_cleancheckout ec:git_ensure_cleancheckout
ia:git_is_ancestor sff:git_should_ff spu:git_should_push
im:git_is_merged
)
function: git_check_gitvcs ""
function git_check_gitvcs() {
git rev-parse --show-toplevel >&/dev/null
}
function: git_ensure_gitvcs ""
function git_ensure_gitvcs() {
git_check_gitvcs || edie "Ce n'est pas un dépôt git" || return
}
function: git_list_branches ""
function git_list_branches() {
git for-each-ref refs/heads/ --format='%(refname:short)' | csort
}
function: git_list_rbranches ""
function git_list_rbranches() {
git for-each-ref "refs/remotes/${1:-origin}/" --format='%(refname:short)' | csort
}
function: git_list_pbranches "lister les branches locales et celles qui existent dans l'origine \$1(=origin) et qui pourraient devenir une branche locale avec la commande git checkout -b"
function git_list_pbranches() {
local prefix="${1:-origin}/"
{
git for-each-ref refs/heads/ --format='%(refname:short)'
git for-each-ref "refs/remotes/$prefix" --format='%(refname:short)' | grep -F "$prefix" | cut -c $((${#prefix} + 1))-
} | grep -vF HEAD | csort -u
}
function: git_have_branch ""
function git_have_branch() {
git_list_branches | grep -qF "$1"
}
function: git_have_rbranch ""
function git_have_rbranch() {
git_list_rbranches "${2:-origin}" | grep -qF "$1"
}
function: git_get_branch ""
function git_get_branch() {
git rev-parse --abbrev-ref HEAD 2>/dev/null
}
function: git_get_branch_remote ""
function git_get_branch_remote() {
local branch="$1"
[ -n "$branch" ] || branch="$(git_get_branch)"
[ -n "$branch" ] || return
git config --get "branch.$branch.remote"
}
function: git_get_branch_merge ""
function git_get_branch_merge() {
local branch="$1"
[ -n "$branch" ] || branch="$(git_get_branch)"
[ -n "$branch" ] || return
git config --get "branch.$branch.merge"
}
function: git_get_branch_rbranch ""
function git_get_branch_rbranch() {
local branch="$1" remote="$2" merge
[ -n "$branch" ] || branch="$(git_get_branch)"
[ -n "$branch" ] || return
[ -n "$remote" ] || remote="$(git_get_branch_remote "$branch")"
[ -n "$remote" ] || return
merge="$(git_get_branch_merge "$branch")"
[ -n "$merge" ] || return
echo "refs/remotes/$remote/${merge#refs/heads/}"
}
function: git_is_branch ""
function git_is_branch() {
[ "$(git_get_branch)" == "${1:-master}" ]
}
function: git_have_remote ""
function git_have_remote() {
[ -n "$(git config --get remote.${1:-origin}.url)" ]
}
function: git_track_branch ""
function git_track_branch() {
local branch="$1" origin="${2:-origin}"
[ -n "$branch" ] || return
git_have_remote "$origin" || return
[ "$(git config --get branch.$branch.remote)" == "$origin" ] && return
if git_have_rbranch "$branch" "$origin"; then
if git_have_branch "$branch"; then
git branch -u "$origin/$branch" "$branch"
else
git branch -t "$branch" "$origin/$branch"
fi
elif git_have_branch "$branch"; then
git push -u "$origin" "$branch" || return
fi
}
function: git_ensure_branch "
@return 0 si la branche a été créée, 1 si elle existait déjà, 2 en cas d'erreur"
function git_ensure_branch() {
local branch="$1" source="${2:-master}" origin="${3:-origin}"
[ -n "$branch" ] || return 2
git_have_branch "$branch" && return 1
if git_have_rbranch "$branch" "$origin"; then
# une branche du même nom existe dans l'origine. faire une copie de cette branche
git branch -t "$branch" "$origin/$branch" || return 2
else
# créer une nouvelle branche du nom spécifié
git_have_branch "$source" || return 2
git branch "$branch" "$source" || return 2
if [ -z "$NUCORE_GIT_OFFLINE" ]; then
git_have_remote "$origin" && git_track_branch "$branch" "$origin"
fi
fi
return 0
}
function: git_check_cleancheckout "vérifier qu'il n'y a pas de modification locales dans le dépôt correspondant au répertoire courant."
function git_check_cleancheckout() {
[ -z "$(git status --porcelain 2>/dev/null)" ]
}
function: git_ensure_cleancheckout ""
function git_ensure_cleancheckout() {
git_check_cleancheckout ||
edie "Vous avez des modifications locales. Enregistrez ces modifications avant de continuer" || return
}
function git__init_ff() {
o="${3:-origin}"
b="$1" s="${2:-refs/remotes/$o/$1}"
b="$(git rev-parse --verify --quiet "$b")" || return 1
s="$(git rev-parse --verify --quiet "$s")" || return 1
return 0
}
function git__can_ff() {
[ "$1" == "$(git merge-base "$1" "$2")" ]
}
function: git_is_ancestor "vérifier que la branche \$1 est un ancêtre direct de la branche \$2, qui vaut par défaut refs/remotes/\${3:-origin}/\$1
note: cette fonction retourne vrai si \$1 et \$2 identifient le même commit"
function git_is_ancestor() {
local o b s; git__init_ff "$@" || return
git__can_ff "$b" "$s"
}
function: git_should_ff "vérifier si la branche \$1 devrait être fast-forwardée à partir de la branche d'origine \$2, qui vaut par défaut refs/remotes/\${3:-origin}/\$1
note: cette fonction est similaire à git_is_ancestor(), mais retourne false si \$1 et \$2 identifient le même commit"
function git_should_ff() {
local o b s; git__init_ff "$@" || return
[ "$b" != "$s" ] || return 1
git__can_ff "$b" "$s"
}
function: git_should_push "vérifier si la branche \$1 devrait être poussée vers la branche de même nom dans l'origine \$2(=origin), parce que l'origin peut-être fast-forwardée à partir de cette branche."
function git_should_push() {
git_should_ff "refs/remotes/${2:-origin}/$1" "$1"
}
function: git_fast_forward "vérifier que la branche courante est bien \$1, puis tester s'il faut la fast-forwarder à partir de la branche d'origine \$2, puis le faire si c'est nécessaire. la branche d'origine \$2 vaut par défaut refs/remotes/origin/\$1"
function git_fast_forward() {
local o b s; git__init_ff "$@" || return
[ "$b" != "$s" ] || return 1
local head="$(git rev-parse HEAD)"
[ "$head" == "$b" ] || return 1
git__can_ff "$b" "$s" || return 1
git merge --ff-only "$s"
}
function: git_is_merged "vérifier que les branches \$1 et \$2 ont un ancêtre commun, et que la branche \$1 a été complètement fusionnée dans la branche destination \$2"
function git_is_merged() {
local b="$1" d="$2"
b="$(git rev-parse --verify --quiet "$b")" || return 1
d="$(git rev-parse --verify --quiet "$d")" || return 1
[ -n "$(git merge-base "$b" "$d")" ] || return 1
[ -z "$(git rev-list "$d..$b")" ]
}
################################################################################
# git annex
NUCORE_GIT_SSH_WRAPPER=
function: git_annex_use_ssh_wrapper ""
function git_annex_use_ssh_wrapper() {
[ -n "$NUCORE_GIT_SSH_WRAPPER" ] && return
NUCORE_GIT_FORCE_PATH="$PATH"
NUCORE_GIT_FORCE_SSH="${GIT_SSH:-ssh}"
export NUCORE_GIT_FORCE_PATH NUCORE_GIT_FORCE_SSH
base_delpath "$NUCOREDIR/ssh-wrapper" NUCORE_GIT_FORCE_PATH
base_inspath "$NUCOREDIR/ssh-wrapper" PATH
NUCORE_GIT_SSH_WRAPPER=1
}
function: git_annex_initial "sur le dépôt \$1 fraichement cloné, vérifier s'il faut faire git annex init. Si oui, l'initialiser avec le nom d'hôte, et récupérer tous les fichiers annexés
@return 1 si une erreur s'est produite"
function git_annex_initial() {
local repodir="${1:-.}"
[ -d "$repodir" ] || return 1
repodir="$(abspath "$repodir")"
local GIT_DIR GIT_WORK_TREE
[ "$(cd "$repodir"; git rev-parse --is-bare-repository)" == false ] || return 0
[ -n "$(GIT_DIR="$repodir/.git" git config --get annex.uuid)" ] && return 0
# ici, on sait que git annex n'a pas encore été configuré
# vérifier s'il existe des fichiers annexés
local -a links
base_array_splitl links "$(find "$repodir" -type l)"
local link hasannex=
for link in "${links[@]}"; do
link="$(readlink "$link")"
if [ "${link#.git/annex/}" != "$link" ]; then
hasannex=1
break
elif [[ "$link" == */.git/annex/* ]]; then
hasannex=1
break
fi
done
if [ -n "$hasannex" ]; then
base_in_path git-annex || edie "Vous devez installer git-annex" || return
local cwd; base_push_cwd "$repodir" &&
git annex init "$MYHOSTNAME" &&
git annex get &&
git annex sync &&
base_pop_cwd || base_pop_cwd 1 || return
fi
}
################################################################################
# Outils de haut niveau
function: git_commit ""
function git_commit() {
local all=auto allnew push=auto nopush args
setyesval nopush "$NUCORE_GIT_OFFLINE"
[ -n "$nopush" ] && push=
parse_opts + "${PRETTYOPTS[@]}" \
-a,--all all=1 \
-A,--all-new allnew=1 \
-c,--cached all= \
-p,--push push=1 \
-l,--local push= \
@ args -- "$@" && set -- "${args[@]}" || {
eerror "$args"
return 1
}
if [ -n "$allnew" ]; then
git add -A
all=
fi
local message="$1"; shift
local -a cmd
cmd=(git commit)
[ -n "$message" ] && cmd=("${cmd[@]}" -m "$message")
if [ "$all" == "auto" ]; then
# Si des fichiers sont spécifiés, prendre ceux-là.
if [ -z "$*" ]; then
# Sinon, s'il y a des fichiers dans l'index, commiter uniquement ces
# fichiers
# Sinon, committer tous les fichiers modifiés
# le code suivant retourne vrai si l'index contient au moins fichier
git status --porcelain 2>/dev/null | lawk '
BEGIN { ec = 1 }
substr($0, 1, 1) ~ /[^ ?]/ { ec = 0; exit }
END { exit ec }' ||
cmd=("${cmd[@]}" -a)
fi
else
[ -n "$all" ] && cmd=("${cmd[@]}" -a)
fi
if ! "${cmd[@]}" "$@"; then
[ "$push" == auto ] && return 1
fi
if [ "$push" == auto ]; then
git_push --auto || return
elif [ -n "$push" ]; then
git_push --force || return
fi
return 0
}
function: git_update ""
function git_update() {
local args autoff=1
parse_opts + "${PRETTYOPTS[@]}" \
-n,--no-autoff autoff= \
@ args -- "$@" && set -- "${args[@]}" || {
eerror "$args"
return 1
}
if [ -z "$autoff" ]; then
git pull "$@"
return $?
fi
local branch orig_branch restore_branch remote rbranch pbranch
local -a branches prbranches crbranches dbranches
base_array_splitl prbranches "$(git_list_rbranches)"
git fetch -p "$@" || return
base_array_splitl crbranches "$(git_list_rbranches)"
# vérifier s'il n'y a pas des branches distantes qui ont été supprimées
for branch in "${prbranches[@]}"; do
if ! base_array_contains crbranches "$branch"; then
base_array_add dbranches "${branch#*/}"
fi
done
if [ ${#dbranches[*]} -gt 0 ]; then
eimportant "One or more distant branches where deleted"
for branch in "${dbranches[@]}"; do
if git_have_branch "$branch"; then
if ! ask_yesno "Do you want to delete local branch $branch?" X; then
base_array_del dbranches "$branch"
fi
fi
done
fi
if [ ${#dbranches[*]} -gt 0 ]; then
base_array_splitl branches "$(git_list_branches)"
branch="$(git_get_branch)"
if base_array_contains dbranches "$branch"; then
# si la branche courante est l'une des branches à supprimer, il faut
# basculer vers develop ou master
local swto
if [ -z "$swto" ] && base_array_contains branches develop && ! base_array_contains dbranches develop; then
swto=develop
fi
if [ -z "$swto" ] && base_array_contains branches master && ! base_array_contains dbranches master; then
swto=master
fi
if ! git_check_cleancheckout; then
echo "* There are uncommitted local changes. However current branch is slated for removal.
Make your verifications then delete the local branches:
${swto:+$(qvals git checkout "$swto")
}$(qvals git branch -D "${dbranches[@]}")"
return 1
fi
if [ -n "$swto" ]; then
git checkout -q "$swto"
else
echo "* Current branch is slated for removal but I don't know to which branch I should switch first.
Make your choice then delete the local branches:
$(qvals git branch -D "${dbranches[@]}")"
return 1
fi
fi
for branch in "${dbranches[@]}"; do
git branch -D "$branch"
done
fi
# intégrer les modifications dans les branches locales
if ! git_check_cleancheckout; then
branch="$(git_get_branch)"
remote="$(git_get_branch_remote "$branch")"
rbranch="$(git_get_branch_rbranch "$branch" "$remote")"
pbranch="${rbranch#refs/remotes/}"
if git merge -q --ff-only "$rbranch"; then
echo "* There are uncommitted local changes: only CURRENT branch were updated"
fi
return 0
fi
orig_branch="$(git_get_branch)"
base_array_splitl branches "$(git_list_branches)"
for branch in "${branches[@]}"; do
remote="$(git_get_branch_remote "$branch")"
rbranch="$(git_get_branch_rbranch "$branch" "$remote")"
pbranch="${rbranch#refs/remotes/}"
[ -n "$remote" -a -n "$rbranch" ] || continue
if git_is_ancestor "$branch" "$rbranch"; then
if git_should_ff "$branch" "$rbranch"; then
echo "* Fast-forwarding $branch -> $pbranch"
git checkout -q "$branch"
git merge -q --ff-only "$rbranch"
restore_branch=1
fi
else
if [ "$branch" == "$orig_branch" ]; then
echo "* Cannot fast-forward CURRENT branch $branch from $pbranch
Try to merge manually with: git merge $pbranch"
else
echo "* Cannot fast-forward local branch $branch from $pbranch
You can merge manually with: git checkout $branch; git merge $pbranch"
fi
fi
done
[ -n "$restore_branch" ] && git checkout -q "$orig_branch"
return 0
}
function: git_push ""
function git_push() {
local all all_branches all_tags auto force args no_annex
parse_opts + "${PRETTYOPTS[@]}" \
-a,--all all=1 \
-b,--branches,--all-branches all_branches=1 \
-t,--tags,--all-tags all_tags=1 \
--auto auto=1 \
-f,--force force=1 \
-n,--no-annex no_annex=1 \
@ args -- "$@" && set -- "${args[@]}" || {
eerror "$args"
return 1
}
if [ -n "$all" ]; then
# On a demandé à pusher toutes les branches et tous les tags
local r
git push --all "$@"; r=$?
if [ $r -eq 0 ]; then
git push --tags "$@"; r=$?
fi
return $r
elif [ -n "$all_branches" ]; then
# On a demandé à pusher toutes les branches
git push --all "$@"
return $?
elif [ -n "$all_tags" ]; then
# On a demandé à pusher tous les tags
git push --tags "$@"
return $?
elif [ $# -gt 0 ]; then
# Sinon, si des arguments sont spécifiés, les passer à git sans
# modification
git push "$@"
return $?
elif git_have_annex; then
# Si une annexe existe dans le dépôt, demander à git-annex de faire la
# synchronisation, sauf si --no-annex est spécifié ou si on est en mode
# automatique
if [ -z "$no_annex" -a -z "$auto" ]; then
git annex sync
return $?
fi
fi
# sinon on push vers origin. vérifier la présence du remote
[ -n "$(git config --get remote.origin.url)" ] || {
if [ -n "$auto" ]; then
# en mode automatique, ignorer l'absence de remote
return 0
else
eerror "Aucun remote origin n'est défini"
return 1
fi
}
# puis calculer la branche à pusher
local branch="$(git rev-parse --abbrev-ref HEAD 2>/dev/null)"
local origin="$(git config --get "branch.$branch.remote")"
if [ -n "$branch" -a "$origin" == origin ]; then
if [ -n "$auto" ]; then
# en mode automatique, ne pousser que la branche courante
git push "$origin" "$branch" || return
else
# utiliser la configuration par défaut, qui est sous debian squeeze
# de pousser toutes les branches
git push || return
fi
elif [ -n "$force" ]; then
# utiliser la configuration par défaut, qui est sous debian squeeze de
# pousser toutes les branches
git push || return
fi
return 0
}
function git__pclone() {
estep "$1 --> $(ppath "$2")"
mkdirof "$2" || return 1
git clone "$1" "$2" || return 1
if [ -z "$3" ]; then
(
cd "$2"
if git_have_rbranch develop; then
git checkout develop || exit 1
fi
) || return 1
fi
git_annex_initial "$2" || return 1
}
function git__gitolite_info() {
local mode="$1" urlbase="$2" pattern="$3"
case "$mode" in
http) curl -fs "$urlbase/info${pattern:+"?$pattern"}";;
ssh) ssh -q "$urlbase" info ${pattern:+"$pattern"} 2>/dev/null;;
esac
}
function git__filter_repos() {
lawk -v prefix="$1" '
NR <= 2 { next }
{
# filtrer les projets qui ne sont pas encore créés
if (substr($0, 5, 2) == " C") next
repo = substr($0, 6)
# filtrer les projets de type wildcard
if (repo ~ /[\[\]\*]/) next
# enlever le prefixe
if (prefix != "" && substr(repo, 1, length(prefix)) != prefix) next
print repo
}'
}
function: git_clone ""
function git_clone() {
no_clone=
update=
nodevelop=
recursive=
parse_opts "${PRETTYOPTS[@]}" \
-n,--no-clone no_clone=1 \
-u,--update update=1 \
-m,--master nodevelop=1 \
-r,--recursive recursive=1 \
@ args -- "$@" && set -- "${args[@]}" || edie "$args" || return
if [ -n "$recursive" ]; then
repobase="$1"
[ -n "$repobase" ] || edie "Vous devez spécifier l'url de base des dépôts à cloner" || return
if [ "${repobase#http://}" != "$repobase" -o "${repobase#https://}" != "$repobase" ]; then
# accès par http
mode=http
splitfsep "$repobase" :// scheme hostuserpath
splitfsep "$hostuserpath" / host userpath
splitfsep "$userpath" / user basepath
[ -n "$host" -a -n "$user" ] || edie "Vous devez spécifier l'hôte e.g http://host/git/basepath" || return
urlbase="$scheme://$host/$user"
else
# accès par ssh
mode=ssh
splitfsep "$repobase" : userhost basepath
splituserhost "$userhost" user host
[ -n "$user" ] || user=git
[ -n "$host" ] || edie "Vous devez spécifier l'hôte" || return
urlbase="$user@$host"
fi
basepath="${basepath%/}"
destbase="${2:-.}"
git_annex_use_ssh_wrapper
prefix="${basepath:+$basepath/}"
base_array_splitl repos "$(set -o pipefail; git__gitolite_info "$mode" "$urlbase" "$prefix" | git__filter_repos "$prefix")" || edie || return
for repo in "${repos[@]}"; do
case "$mode" in
http) repourl="$urlbase/$repo";;
ssh) repourl="$urlbase:$repo";;
esac
setx destdir=abspath "$destbase/${repo#$prefix}"
if [ -d "$destdir" ]; then
if [ -n "$update" ]; then
(
${no_clone:+qvals} cd "$destdir"
${no_clone:+qvals} git pull
) || edie || return
else
estepe "$(ppath2 "$destdir"): répertoire existant"
fi
elif [ -n "$no_clone" ]; then
qvals git clone "$repourl" "$destdir"
else
git__pclone "$repourl" "$destdir" "$nodevelop" || edie || return
fi
done
else
repourl="${1%.git}"
[ -n "$repourl" ] || edie "Vous devez spécifier l'url du dépôt git" || return
destdir="$2"
if [ -z "$destdir" ]; then
splitfsep "$repourl" : userhost path
setx destdir=basename -- "$path"
destdir="${destdir%.git}"
fi
setx destdir=abspath "$destdir"
git_annex_use_ssh_wrapper
if [ -d "$destdir" ]; then
if [ -n "$update" ]; then
(
${no_clone:+qvals} cd "$destdir"
${no_clone:+qvals} git pull
) || edie || return
else
estepe "$(ppath2 "$destdir"): répertoire existant"
fi
elif [ -n "$no_clone" ]; then
qvals git clone "$repourl" "$destdir"
else
git__pclone "$repourl" "$destdir" "$nodevelop" || edie || return
fi
fi
}
function: git_crone ""
function git_crone() {
repourl="${1%.git}"
[ -n "$repourl" ] || edie "Vous devez spécifier l'url du dépôt git" || return
if [ "${repourl#http://}" != "$repourl" -o "${repourl#https://}" != "$repourl" ]; then
# accès par http
mode=http
splitfsep "$repourl" :// scheme hostuserpath
splitfsep "$hostuserpath" / host userpath
splitfsep "$userpath" / user path
[ -n "$host" -a -n "$user" ] || edie "Vous devez spécifier l'hôte e.g http://host/git/repo" || return
hostuser="$scheme://$host/$user"
else
# accès par ssh
mode=ssh
splitfsep "$repourl" : userhost path
splituserhost "$userhost" user host
[ -n "$user" ] || user=git
[ -n "$host" ] || edie "Vous devez spécifier l'hôte" || return
userhost="$user@$host"
fi
[ -n "$path" ] || edie "Vous devez spécifier le chemin du dépôt git" || return
destdir="$2"
if [ -z "$destdir" ]; then
setx destdir=basename -- "$path"
destdir="${destdir%.git}"
fi
tmpdestdir=
if [ -d "$destdir" ]; then
[ -d "$destdir/.git" ] && edie "$(ppath2 "$destdir"): un dépôt existe déjà" || return
ac_set_tmpdir tmpdestdir
fi
if [ "$mode" == http ]; then
setx result=curl -fs "$hostuser/create?$path" || edie || return
echo "$result"
[[ "$result" == FATAL:* ]] && edie || return
if [ -n "$tmpdestdir" ]; then
setxx destname=abspath "$destdir" // basename
git clone "$hostuser/$path" "$tmpdestdir/$destname" || edie || return
mv "$tmpdestdir/$destname/.git" "$destdir" || edie || return
ac_clean "$tmpdestdir"
else
git clone "$hostuser/$path" "$destdir" || edie || return
fi
elif [ "$mode" == ssh ]; then
git_annex_use_ssh_wrapper
ssh "$userhost" create "$path" || edie || return
if [ -n "$tmpdestdir" ]; then
setxx destname=abspath "$destdir" // basename
git clone "$userhost:$path" "$tmpdestdir/$destname" || edie || return
mv "$tmpdestdir/$destname/.git" "$destdir" || edie || return
ac_clean "$tmpdestdir"
else
git clone "$userhost:$path" "$destdir" || edie || return
fi
else
edie "$mode: mode non supporté" || return
fi
git_annex_initial "$destdir" || edie || return
}

1
bash/nucore.sh Symbolic link
View File

@ -0,0 +1 @@
../load.sh

4
bash/pretty.sh Normal file
View File

@ -0,0 +1,4 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
##@cooked nocomments
module: pretty "Affichage en couleur"
require: base

4
bash/sysinfos.sh Normal file
View File

@ -0,0 +1,4 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
##@cooked nocomments
module: sysinfos "Informations sur le système courant"
require: base

2
lib/profile.d/nucore Normal file
View File

@ -0,0 +1,2 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
__uaddpath "@@dest@@/bin" PATH

9
lib/uinst/conf Normal file
View File

@ -0,0 +1,9 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
source "$@" || exit 1
source "$ULIBDIR/ulib" || exit 1
urequire DEFAULTS
cd "$scriptdir/../.."
# supprimer les fichiers de VCS
rm -rf .git

10
lib/uinst/rootconf Normal file
View File

@ -0,0 +1,10 @@
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
source "$@" || exit 1
source "$ULIBDIR/ulib" || exit 1
urequire DEFAULTS
cd "$scriptdir/../.."
sed "s|@@""dest""@@|$dest|g" load.sh >/etc/nucore.sh
exit 0

159
load.sh Normal file
View File

@ -0,0 +1,159 @@
##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
## Charger nucore et rendre disponible les modules bash, awk, php et python
##@cooked nocomments
# Ce fichier doit être sourcé en premier. Si ce fichier n'est pas sourcé, alors
# le répertoire nucore doit être disponible dans le répertoire du script qui
# inclue ce fichier.
# Une fois ce fichier sourcé, les autres modules peuvent être importés avec
# require:() e.g.
# source /etc/nucore.sh || exit 1
# require: other_modules
# ou pour une copie locale de nucore:
# source "$(dirname "$0")/nucore/load.sh" || exit 1
# require: other_modules
# vérifier version minimum de bash
if [ "x$BASH" = "x" ]; then
echo "ERROR: nucore: this script requires bash"
exit 1
fi
function eerror() { echo "ERROR: $*" 1>&2; }
function die() { [ $# -gt 0 ] && eerror "$*"; exit 1; }
function edie() { [ $# -gt 0 ] && eerror "$*"; return 1; }
function delpath() { local _qdir="${1//\//\\/}"; eval "export ${2:-PATH}; ${2:-PATH}"'="${'"${2:-PATH}"'#$1:}"; '"${2:-PATH}"'="${'"${2:-PATH}"'%:$1}"; '"${2:-PATH}"'="${'"${2:-PATH}"'//:$_qdir:/:}"; [ "$'"${2:-PATH}"'" == "$1" ] && '"${2:-PATH}"'='; }
function addpath() { local _qdir="${1//\//\\/}"; eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="${'"${2:-PATH}"':+$'"${2:-PATH}"':}$1"'; }
function inspathm() { local _qdir="${1//\//\\/}"; eval "export ${2:-PATH}; "'[ "${'"${2:-PATH}"'#$1:}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'%:$1}" == "$'"${2:-PATH}"'" -a "${'"${2:-PATH}"'//:$_qdir:/:}" == "$'"${2:-PATH}"'" -a "$'"${2:-PATH}"'" != "$1" ] && '"${2:-PATH}"'="$1${'"${2:-PATH}"':+:$'"${2:-PATH}"'}"'; }
function inspath() { delpath "$@"; inspathm "$@"; }
if [ ${BASH_VERSINFO[0]} -ge 5 -o \( ${BASH_VERSINFO[0]} -eq 4 -a ${BASH_VERSINFO[1]} -ge 1 \) ]; then :
elif [ -n "$NUCORE_IGNORE_BASH_VERSION" ]; then :
else die "nucore: bash 4.1+ is required"
fi
# Calculer emplacement de nucore
NUCOREDIR="@@dest@@"
if [ "$NUCOREDIR" = "@@""dest""@@" ]; then
# La valeur "@@"dest"@@" n'est remplacée que dans la copie de ce script
# faite dans /etc. Sinon, il faut toujours faire le calcul. Cela permet de
# déplacer la librairie n'importe où sur le disque, ce qui est
# particulièrement intéressant quand on fait du déploiement.
NUCOREDIR="${BASH_SOURCE[0]}"
if [ -f "$NUCOREDIR" -a "$(basename -- "$NUCOREDIR")" == load.sh ]; then
# Fichier sourcé depuis nucore/
NUCORE_SOURCED=1
NUCOREDIR="$(dirname -- "$NUCOREDIR")"
elif [ -f "$NUCOREDIR" -a "$(basename -- "$NUCOREDIR")" == nucore.sh ]; then
# Fichier sourcé depuis nucore/bash
NUCORE_SOURCED=1
NUCOREDIR="$(dirname -- "$NUCOREDIR")/.."
else
# Fichier non sourcé. Tout exprimer par rapport au script courant
NUCORE_SOURCED=
NUCOREDIR="$(dirname -- "$0")"
if [ -d "$NUCOREDIR/nucore" ]; then
NUCOREDIR="$NUCOREDIR/nucore"
elif [ -d "$NUCOREDIR/lib/nucore" ]; then
NUCOREDIR="$NUCOREDIR/lib/nucore"
fi
fi
elif [ "${BASH_SOURCE[0]}" = /etc/nucore.sh ]; then
# Fichier chargé depuis /etc/nucore.sh
NUCORE_SOURCED=1
fi
NUCOREDIR="$(cd "$NUCOREDIR" 2>/dev/null; pwd)"
NUCOREDIRS=("$NUCOREDIR/bash")
# marqueur pour vérifier que nucore a réellement été chargé. il faut avoir $NUCOREINIT == $NUCOREDIR
# utilisé par le module base qui doit pouvoir être inclus indépendamment
NUCOREINIT="$NUCOREDIR"
## Modules bash
NUCORE_LOADED_MODULES=(nucore)
NUCORE_DEFAULT_MODULES=(base pretty sysinfos)
# Si cette variable est non vide, require: recharge toujours le module, même
# s'il a déjà été chargé. Cette valeur n'est pas transitive: il faut toujours
# recharger explicitement tous les modules désirés
NUCORE_FORCE_RELOAD=
function nucore__define_functions() {
function nucore_check_loaded() {
local module
for module in "${NUCORE_LOADED_MODULES[@]}"; do
[ "$module" == "$1" ] && return 0
done
return 1
}
function module:() {
NUCORE_MODULE="$1"
if ! nucore_check_loaded "$1"; then
NUCORE_LOADED_MODULES+=("$1")
fi
}
function function:() {
:
}
}
function nucore__require:() {
local nr__module nr__nucoredir nr__found
[ $# -gt 0 ] || set DEFAULTS
# sauvegarder valeurs globales
local nr__orig_module="$NUCORE_MODULE"
NUCORE_MODULE=
# garder une copie de la valeur originale et casser la transitivité
local nr__force_reload="$NUCORE_FORCE_RELOAD"
local NUCORE_FORCE_RELOAD
for nr__module in "$@"; do
nr__found=
for nr__nucoredir in "${NUCOREDIRS[@]}"; do
if [ -f "$nr__nucoredir/$nr__module.sh" ]; then
nr__found=1
if [ -n "$nr__force_reload" ] || ! nucore_check_loaded "$nr__module"; then
NUCORE_LOADED_MODULES+=("$nr__module")
source "$nr__nucoredir/$nr__module.sh" || die
fi
break
fi
done
if [ -z "$nr__found" -a "$nr__module" == DEFAULTS ]; then
for nr__module in "${NUCORE_DEFAULT_MODULES[@]}"; do
if [ -f "$nr__nucoredir/$nr__module.sh" ]; then
nr__found=1
if [ -n "$nr__force_reload" ] || ! nucore_check_loaded "$nr__module"; then
NUCORE_LOADED_MODULES+=("$nr__module")
source "$nr__nucoredir/$nr__module.sh" || die
fi
else
break
fi
done
fi
[ -n "$nr__found" ] || die "nucore: unable to find module $nr__module in (${NUCOREDIRS[*]})"
done
# restaurer valeurs globales
NUCORE_MODULE="$nr__orig_module"
}
function require:() {
[ -z "$NUCORE_NO_DISABLE_SET_X" ] && [[ $- == *x* ]] && { set +x; local NUCORE_REQUIRE_SET_X=1; }; if [ -n "$NUCORE_REQUIRE_SET_X" ]; then [ -n "$NUCORE_REQUIRE_SET_X_RL1" ] || local NUCORE_REQUIRE_SET_X_RL1; local NUCORE_REQUIRE_SET_X_RL2=$RANDOM; [ -n "$NUCORE_REQUIRE_SET_X_RL1" ] || NUCORE_REQUIRE_SET_X_RL1=$NUCORE_REQUIRE_SET_X_RL2; fi # désactiver set -x de manière réentrante
nucore__define_functions
nucore__require: "$@"
[ -n "$NUCORE_REQUIRE_SET_X" -a "$NUCORE_REQUIRE_SET_X_RL1" == "$NUCORE_REQUIRE_SET_X_RL2" ] && set -x
return 0
}
## Autres modules
[ -d "$NUCOREDIR/awk" ] && inspath "$NUCOREDIR/awk" AWKPATH; export AWKPATH
[ -d "$NUCOREDIR/python3" ] && inspath "$NUCOREDIR/python3" PYTHONPATH; export PYTHONPATH
## Auto import DEFAULTS
nucore__define_functions
if [ -n "$NUCORE_SOURCED" -a -z "$NUCORE_NO_IMPORT_DEFAULTS" ]; then
require: DEFAULTS
fi