nutools/lib/ulib/runsmod

579 lines
21 KiB
Bash

##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
## Gestion des modules pour runs
##@cooked nocomments
##@require base
uprovide runsmod
urequire base
function __runsmod_loadconf() {
# Charger le fichier de configuration $1. Les paramètres RUNSMOD_MODE,
# RUNSMOD_SHALLOW et RUNSMOD_UPDATE peuvent être modifiés par rapport à la
# configuration chargée avec les paramètres $2, $3 et $4 respectivement.
local config="$1" mode="$2" shallow="$3" update="$4"
urequire runsmod.defaults
set_defaults runsmod
if [ -n "$config" ]; then
[ -f "$config" ] || {
eerror "$config: fichier introuvable"
return 1
}
source "$config" || {
eerror "Erreur de configuration"
return 1
}
fi
[ -n "$mode" -a "$mode" != --NOT-SET-- ] || mode="$RUNSMOD_MODE"
case "$mode" in
production|prod|p) mode=prod;;
development|devel|dev|d) mode=devel;;
*) die "$mode: mode invalide. Ce doit être prod ou devel";;
esac
RUNSMOD_MODE="$mode"
[ -n "$shallow" -a "$shallow" != --NOT-SET-- ] || shallow="$RUNSMOD_SHALLOW"
if [ "$shallow" == auto ]; then
case "$RUNSMOD_MODE" in
prod) shallow=1;;
devel) shallow=;;
esac
fi
normyesval shallow
RUNSMOD_SHALLOW="$shallow"
[ -n "$update" -a "$update" != --NOT-SET-- ] || update="$RUNSMOD_UPDATE"
if [ "$update" == auto ]; then
case "$RUNSMOD_MODE" in
prod) update=pull;;
devel) update=clone;;
esac
fi
RUNSMOD_UPDATE="$update"
case "$RUNSMOD_UPDATE" in
offline) RUNSMOD_CLONE=; RUNSMOD_PULL=;;
clone) RUNSMOD_CLONE=1; RUNSMOD_PULL=;;
pull) RUNSMOD_CLONE=1; RUNSMOD_PULL=1;;
esac
return 0
}
function __runsmod_get() {
# obtenir la valeur de la première variable définie dans une liste
# construite à partir des arguments de cette fonction.
# $1 étant le suffixe, pour chacun des préfixes $2..@, tester l'existence de
# la variable "RUNSMOD_${prefix}_${suffix}". Le cas particulier prefix==""
# teste l'existence de la variable RUNSMOD_${suffix}
# Si la liste des préfixes n'est pas spécifiée, prendre par défaut la liste
# suivante: ("${RUNSMOD_PROFILE}_${RUNSMOD_MODE}" "$RUNSMOD_PROFILE" "")
# Si $1=-a, alors copier un tableau plutôt qu'afficher une valeur
# scalaire. dans ce cas, $2 est le nom du tableau destination, et toutes les
# autres valeurs indiquées ci-dessus sont décalées de 2 vers la droite
local _array
if [ "$1" == -a ]; then
_array="$2"
shift; shift
fi
local _suffix="$1"; shift
[ -n "$_suffix" ] || return 1
if [ $# -eq 0 ]; then
# préfixes par défaut
local -a _args
if [ -n "$RUNSMOD_PROFILE" ]; then
if [ -n "$RUNSMOD_MODE" ]; then
_args=("${_args[@]}" "${RUNSMOD_PROFILE}_${RUNSMOD_MODE}")
fi
_args=("${_args[@]}" "$RUNSMOD_PROFILE")
fi
_args=("${_args[@]}" "")
set -- "${_args[@]}"
fi
local _prefix _var
local -a _values
for _prefix in "$@"; do
if [ -n "$_prefix" ]; then
_var="RUNSMOD_${_prefix}_${_suffix}"
else
_var="RUNSMOD_${_suffix}"
fi
if [ -n "$_array" ]; then
array_copy _values "$_var"
if [ ${#_values[*]} -gt 0 -a -n "${_values[0]}" ]; then
array_copy "$_array" "$_var"
return 0
fi
else
_var="${!_var}"
if [ -n "$_var" ]; then
echo "$_var"
return 0
fi
fi
done
return 1
}
function __runsmod_fixurl() {
# Ajouter la définition de dépôt $1 à l'url de base $2 pour en faire un url
# de dépot.
local url="$2"
case "$url" in
http:*|https:*)
[ "${url%/}" != "$url" ] || url="$url/"
;;
*)
if [[ "$url" == *: ]]; then
:
elif [[ "$url" == *:* ]]; then
[ "${url%/}" != "$url" ] || url="$url/"
else
url="$url:"
fi
;;
esac
echo "$url$1"
}
function __runsmod_getpath_from_baseurl() {
# obtenir le nom correspond à un url de base, utilisable dans un chemin
local url="$1" scheme path userhost user host dummy
case "$url" in
http:*|https:*)
scheme="${url%%:*}"
path="${url#*://}"
path="${path%/}"
path="${path/:\/\//_}"
path="${path//\//_}"
echo "${path}_${scheme}"
return
;;
*)
splitpair "$url" userhost dummy
splituserhost "$userhost" user host
echo "${host}_${user}_ssh"
;;
esac
}
__RUNSMOD_CONNECT_TIMEOUT=3
function __runsmod_dumpurl() {
if progexists curl; then
curl -fs --connect-timeout "$__RUNSMOD_CONNECT_TIMEOUT" "$@"
elif progexists wget; then
wget -q --connect-timeout "$__RUNSMOD_CONNECT_TIMEOUT" -O - "$@"
else
eerror "Nécessite curl ou wget"
return 1
fi
}
function __runsmod_getinfo() {
# interroger le serveur gitolite à l'url de base $1 avec la commande info
local url="$1"
case "$url" in
http:*|https:*)
__runsmod_dumpurl "${url%/}/info"
;;
*)
local userhost dummy
splitpair "$url" userhost dummy
local -a options
options=(
-o StrictHostKeyChecking=no
-o BatchMode=yes
-o ConnectTimeout="$__RUNSMOD_CONNECT_TIMEOUT"
)
"${GIT_SSH:-ssh}" -q "${options[@]}" "$userhost" info
;;
esac
}
function __runsmod_fixinfo() {
# traiter le résultat de __runsmod_getinfo() pour avoir la liste des dépôts
sed -n '3,$p' | sed 's/^.*\t//g'
}
function runsmod_checkenv() {
# vérifier l'environement. créer les répertoires nécessaires.
if [ -z "$RUNSMOD_BASEDIR" ]; then
eerror "Vous devez définir RUNSMOD_BASEDIR"
return 1
fi
if [ ! -d "$RUNSMOD_BASEDIR" ]; then
estep "Création de $(ppath "$RUNSMOD_BASEDIR")"
mkdir -p "$RUNSMOD_BASEDIR" || return 1
fi
}
function __runsmod_get_repolistfile() {
# obtenir le chemin absolu vers le fichier contenant la liste des dépôts
# correspondant à l'url de base $1
local repopath
setx repopath=__runsmod_getpath_from_baseurl "$1"
echo "$RUNSMOD_BASEDIR/info-$repopath.lst"
}
function runsmod_should_update_repolists() {
# tester s'il faut mettre à jour au moins un des fichiers contenant les
# listes des dépôts
local RUNSMOD_PROFILE
local now baseurl repobase repopath repolistfile mtime
local -a urls
setx now=date +%s
for RUNSMOD_PROFILE in "${RUNSMOD_PROFILES[@]}"; do
setx baseurl=__runsmod_get BASEURL || continue
setx repolistfile=__runsmod_get_repolistfile "$baseurl"
# si le fichier n'existe pas, il faut mettre à jour
[ -f "$repolistfile" ] || return 0
# si le fichier a été modifié depuis plus de 24 heures, mettre à jour
setx mtime=stat -c %Y "$repolistfile"
[ $(($now - $mtime)) -lt 86400 ] || return 0
done
return 1
}
function runsmod_update_repolists() {
# mettre à jour si nécessaire les fichiers contenant les listes des dépôts.
# Si $1 n'est pas vide, forcer la mise à jour de tous les fichiers
local force="$1"; shift
local RUNSMOD_PROFILE
local now baseurl repobase repopath repo mtime update
local -a urls
setx now=date +%s
for RUNSMOD_PROFILE in "${RUNSMOD_PROFILES[@]}"; do
setx baseurl=__runsmod_get BASEURL || continue
setx repolistfile=__runsmod_get_repolistfile "$baseurl"
update="$force"
if [ -z "$update" ]; then
# si le fichier n'existe pas, il faut mettre à jour
[ -f "$repolistfile" ] || update=1
fi
if [ -z "$update" ]; then
# si le fichier a été modifié depuis plus de 24 heures, mettre à jour
setx mtime=stat -c %Y "$repolistfile"
[ $(($now - $mtime)) -lt 86400 ] || update=1
fi
if [ -n "$update" ]; then
local list
ebegin "$baseurl"
if setx list=__runsmod_getinfo "$baseurl"; then
echo "$list" | __runsmod_fixinfo >"$repolistfile"
edot 0
else
edot 1
fi
eend
fi
done
}
function runsmod_setup_vars() {
# récupérer configuration statique pour la mettre à jour
array_new REPODIRS
array_split SCRIPTSDIRS "$RUNSSCRIPTSPATH" :
array_split MODULESDIRS "$RUNSMODULESPATH" :
array_split HOSTSDIRS "$RUNSHOSTSPATH" :
}
function __runsmod_has_vmodule() {
# tester si l'url $1 contient une variable de module %m
[ "${1//%m/}" != "$1" ]
}
function __runsmod_has_vhost() {
# tester si l'url $1 contient une variable d'hôte %h
[ "${1//%h/}" != "$1" ]
}
function __runsmod_replace1() {
# remplacer dans l'url $1 la variable %h par l'hôte complet $2 et
# éventuellement la variable %m par le module $3
local url="$1"
[ -n "$2" ] && url="${url//%h/$2}"
[ -n "$3" ] && url="${url//%m/$3}"
echo "$url"
}
function __runsmod_replace2() {
# remplacer dans l'url $1 la variable %h par le nom d'hôte correspondant à
# au nom d'hôte complet $2 et éventuellement la variable %m par le module $3
local url="$1"
local host="${2%%.*}"
[ -n "$host" ] && url="${url//%h/$host}"
[ -n "$3" ] && url="${url//%m/$3}"
echo "$url"
}
function __runsmod_match() {
# vérifier que $2 correspond au pattern $1
eval "[[ $(qval "$2") == $(qwc "$1") ]]"
}
function __runsmod_match_repo_add() {
# vérifier qu'un dépôt de pattern $2 se trouve dans la liste de dépôt $1
# si c'est le cas, rajouter le dépôt dans le tableau $3 le cas échéant
local __rs="$1[@]" __r __found
for __r in "${!__rs}"; do
if [[ "$__r" == *\** ]]; then
: # ignore les dépôts wildcard
elif __runsmod_match "$2" "$__r"; then
[ -n "$3" ] && array_add "$3" "$__r"
__found=1
fi
done
[ -n "$__found" ]
}
function __runsmod_clone_or_pull() {
local repourl="$1" repodir="$2"
mkdirof "$repodir"
if [ -d "$repodir" ]; then
if [ -n "$RUNSMOD_PULL" ]; then
estepi "pull $(ppath "$repodir") [$repourl]"
(cd "$repodir"; git pull)
return $?
else
estep "nopull $(ppath "$repodir")"
return 0
fi
else
if [ -n "$RUNSMOD_CLONE" ]; then
estepi "clone $(ppath "$repodir") [$repourl]"
git clone ${RUNSMOD_SHALLOW:+--depth 1} "$repourl" "$repodir"
return $?
else
estepe "noclone $(ppath "$repodir")"
return 1
fi
fi
}
function runsmod_clone_or_pull() {
# Chercher les modules $3..@, pour l'hôte $1 qui est le mode d'hôte: none,
# all, self ou one pour un hôte spécifique $2. Ajouter les chemins dans le
# tableau REPO_DIRS. Mettre à jour les tableaux SCRIPTS_DIRS, MODULES_DIRS
# et HOSTS_DIRS
local all_hosts host_mode="$1" host="$2"; shift; shift
case "$host_mode" in
none) host=;;
all) host=; all_hosts=1;;
self) host="${RUNSHOST:-$MYHOST}";;
esac
if [ -n "$host" -a "${host%%.*}" == "$host" -a -n "$RUNSDOMAIN" ]; then
# le nom d'hôte doit être avec un domaine
host="$host.$RUNSDOMAIN"
enote "Autocorrection du nom d'hôte en $host"
fi
local -a repolist reposuffixes reponames repourls
local RUNSMOD_PROFILE baseurl repopath repolistfile
local vprefix repospec reposuffix reponame repourl repodir module moduledir
local r=0
# Tout d'abord, traiter les dépôts sans variable %m
edebug "Traitement des dépôts sans vmodule"
for RUNSMOD_PROFILE in "${RUNSMOD_PROFILES[@]}"; do
setx baseurl=__runsmod_get BASEURL || continue
setx repopath=__runsmod_getpath_from_baseurl "$baseurl"
setx repolistfile=__runsmod_get_repolistfile "$baseurl"
[ -f "$repolistfile" ] || continue
array_from_lines repolist "$(<"$repolistfile")"
edebug ".. baseurl=$baseurl, repopath=$repopath"
for vprefix in SCRIPTS MODULES HOSTS; do
__runsmod_get -a repourls "${vprefix}_URLS"
edebug ".... vprefix=$vprefix, repourls=(${repourls[*]})"
for repospec in "${repourls[@]}"; do
edebug "...... repospec=$repospec"
__runsmod_has_vmodule "$repospec" && continue
if [[ "$repospec" == *//* ]]; then
reposuffix="${repospec#*//}"
[ -n "$reposuffix" ] && reposuffix="/$reposuffix"
repospec="${repospec%%//*}"
if __runsmod_has_vhost "$reposuffix"; then
if [ -n "$all_hosts" -o -z "$host" ]; then
reposuffix="${reposuffix//%h\//}"
reposuffix="${reposuffix//\/%h/}"
reposuffixes=("$reposuffix")
elif [ -n "$host" ]; then
local rs1 rs2
setx rs1=__runsmod_replace1 "$reposuffix" "$host"
setx rs2=__runsmod_replace2 "$reposuffix" "$host"
reposuffixes=("$rs1")
[ "$rs2" != "$rs1" ] && array_add reposuffixes "$rs2"
fi
else
reposuffixes=("$reposuffix")
fi
else
reposuffix=
fi
reponames=()
if __runsmod_has_vhost "$repospec"; then
if [ -n "$all_hosts" ]; then
setx repospec=__runsmod_replace1 "$repospec" "*"
__runsmod_match_repo_add repolist "$repospec" reponames
elif [ -n "$host" ]; then
setx reponame=__runsmod_replace1 "$repospec" "$host"
array_contains repolist "$reponame" && array_add reponames "$reponame"
setx reponame=__runsmod_replace2 "$repospec" "$host"
array_contains repolist "$reponame" && array_add reponames "$reponame"
fi
else
array_contains repolist "$repospec" && array_add reponames "$repospec"
fi
edebug "...... reponames=(${reponames[*]})"
for reponame in "${reponames[@]}"; do
repodir="$RUNSMOD_BASEDIR/$repopath/$reponame"
setx repourl=__runsmod_fixurl "$reponame" "$baseurl"
__runsmod_clone_or_pull "$repourl" "$repodir" || r=1
[ -d "$repodir" ] || continue
array_contains REPODIRS "$repodir" && continue
array_addu REPODIRS "$repodir"
for reposuffix in "${reposuffixes[@]}"; do
case "$vprefix" in
SCRIPTS) array_addu SCRIPTSDIRS "$repodir$reposuffix";;
MODULES) array_addu MODULESDIRS "$repodir$reposuffix";;
HOSTS) array_addu HOSTSDIRS "$repodir$reposuffix";;
esac
done
done
done
done
done
## Ensuite, traiter les dépôts de module
# modules contient la liste des modules qui ont été trouvés, pour ne pas les
# lister en double s'ils existent dans plusieurs sources
edebug "Traitement des dépôts de modules"
local -a modules foundmodules
local all_modules
modules=("$@")
for RUNSMOD_PROFILE in "${RUNSMOD_PROFILES[@]}"; do
setx baseurl=__runsmod_get BASEURL || continue
setx repopath=__runsmod_getpath_from_baseurl "$baseurl"
setx repolistfile=__runsmod_get_repolistfile "$baseurl"
[ -f "$repolistfile" ] || continue
array_from_lines repolist "$(<"$repolistfile")"
edebug ".. baseurl=$baseurl, repopath=$repopath"
for module in "${modules[@]}"; do
if [ "$module" == "*" ]; then
module=
all_modules=1
else
array_contains foundmodules "$module" && continue
all_modules=
fi
edebug ".... module=$module"
for vprefix in SCRIPTS MODULES HOSTS; do
__runsmod_get -a repourls "${vprefix}_URLS"
edebug "...... vprefix=$vprefix, repourls=(${repourls[*]})"
for repospec in "${repourls[@]}"; do
edebug "........ repospec=$repospec"
__runsmod_has_vmodule "$repospec" || continue
if [[ "$repospec" == *//* ]]; then
reposuffix="${repospec#*//}"
[ -n "$reposuffix" ] && reposuffix="/$reposuffix"
repospec="${repospec%%//*}"
if __runsmod_has_vhost "$reposuffix"; then
if [ -n "$all_hosts" -o -z "$host" ]; then
reposuffix="${reposuffix//%h\//}"
reposuffix="${reposuffix//\/%h/}"
reposuffixes=("$reposuffix")
elif [ -n "$host" ]; then
local rs1 rs2
setx rs1=__runsmod_replace1 "$reposuffix" "$host"
setx rs2=__runsmod_replace2 "$reposuffix" "$host"
reposuffixes=("$rs1")
[ "$rs2" != "$rs1" ] && array_add reposuffixes "$rs2"
fi
else
reposuffixes=("$reposuffix")
fi
else
reposuffix=
fi
reponames=()
if [ -n "$all_modules" ]; then
if __runsmod_has_vhost "$repospec"; then
if [ -n "$all_hosts" ]; then
setx repospec=__runsmod_replace1 "$repospec" "*" "*"
__runsmod_match_repo_add repolist "$repospec" reponames
elif [ -n "$host" ]; then
setx repospec=__runsmod_replace1 "$repospec" "$host" "*"
__runsmod_match_repo_add repolist "$repospec" reponames
setx repospec=__runsmod_replace2 "$repospec" "$host" "*"
__runsmod_match_repo_add repolist "$repospec" reponames
fi
else
setx repospec=__runsmod_replace1 "$repospec" "" "*"
__runsmod_match_repo_add repolist "$repospec" reponames
fi
else
if __runsmod_has_vhost "$repospec"; then
if [ -n "$host" ]; then
setx reponame=__runsmod_replace1 "$repospec" "$host" "$module"
array_contains repolist "$reponame" && array_add reponames "$reponame"
setx reponame=__runsmod_replace2 "$repospec" "$host" "$module"
array_contains repolist "$reponame" && array_add reponames "$reponame"
fi
else
setx reponame=__runsmod_replace1 "$repospec" "" "$module"
array_contains repolist "$reponame" && array_add reponames "$reponame"
fi
fi
edebug "........ reponames=(${reponames[*]})"
for reponame in "${reponames[@]}"; do
repodir="$RUNSMOD_BASEDIR/$repopath/$reponame"
setx repourl=__runsmod_fixurl "$reponame" "$baseurl"
__runsmod_clone_or_pull "$repourl" "$repodir" || r=1
[ -d "$repodir" ] || continue
array_contains REPODIRS "$repodir" && continue
array_addu REPODIRS "$repodir"
[ -z "$all_modules" ] && array_addu foundmodules "$module"
for reposuffix in "${reposuffixes[@]}"; do
case "$vprefix" in
SCRIPTS) array_addu SCRIPTSDIRS "$repodir$reposuffix";;
MODULES)
setx moduledir=dirname -- "$repodir$reposuffix"
array_addu MODULESDIRS "$moduledir"
;;
HOSTS) array_addu HOSTSDIRS "$repodir$reposuffix";;
esac
done
done
done
done
done
done
for module in "${modules[@]}"; do
[ "$module" == "*" ] && continue
array_contains foundmodules "$module" || ewarn "$module: module non trouvé"
done
return $r
}
function runsmod_teardown_vars() {
setx RUNSSCRIPTSPATH=array_join SCRIPTSDIRS :
setx RUNSMODULESPATH=array_join MODULESDIRS :
setx RUNSHOSTSPATH=array_join HOSTSDIRS :
}