##@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 et # RUNSMOD_UPDATE peuvent être modifiés par rapport à la configuration # chargée avec les paramètres $2 et $3 respectivement. local config="$1" mode="$2" update="$3" 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" ] || 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 "$update" ] || 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/$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_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 "$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 #XXX implémenter all_hosts=1 local -a repolist reponames repourls local RUNSMOD_PROFILE baseurl repopath repolistfile local vprefix repospec 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 reponames=() if __runsmod_has_vhost "$repospec"; then if [ -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_addu REPODIRS "$repodir" case "$vprefix" in SCRIPTS) array_addu SCRIPTSDIRS "$repodir";; #MODULES) ;; HOSTS) array_addu HOSTSDIRS "$repodir";; esac 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 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 array_contains foundmodules "$module" && continue 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 reponames=() 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 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_addu foundmodules "$module" array_addu REPODIRS "$repodir" case "$vprefix" in SCRIPTS) array_addu SCRIPTSDIRS "$repodir";; MODULES) setx moduledir=dirname -- "$repodir" array_addu MODULESDIRS "$moduledir" ;; HOSTS) array_addu HOSTSDIRS "$repodir";; esac done done done done done for module in "${modules[@]}"; do 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 : }