##@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 vcs

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_mapdir() {
    # mapper le répertoire $1, avec $2 est le répertoire de base à partir
    # desquels les mappings sont définis
    # retourner vrai si un mapping a eu lieu
    local dir="$1" basedir="$2"
    local -a maps
    local map from to
    [ -n "$basedir" ] && dir="${dir#$basedir/}"
    __runsmod_get -a maps MAP
    for map in "${maps[@]}"; do
        splitpair "$map" from to
        if [ "$dir" == "$from" ]; then
            echo "$to"
            return 0
        elif [ "${dir#$from/}" != "$dir" ]; then
            echo "$to/${dir#$from/}"
            return 0
        fi
    done
    echo "$dir"
    return 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_autoconf() {
    if __runsmod_loadconf && runsmod_checkenv --check-only; then
        local host_mode="${1:-self}"; shift
        set -- "$host_mode" "$@"
        runsmod_setup_vars
        runsmod_update_vars "$@"
        runsmod_teardown_vars
        if show_debug; then
            etitle SCRIPTSDIRS array_each SCRIPTSDIRS ppath
            etitle MODULESDIRS array_each MODULESDIRS ppath
            etitle HOSTSDIRS array_each HOSTSDIRS ppath
        fi
    fi
}

function runsmod_checkenv() {
    # vérifier l'environement. créer les répertoires nécessaires.
    local check_only
    [ "$1" == --check-only ] && check_only=1
    if [ -z "$RUNSMOD_BASEDIR" ]; then
        [ -z "$check_only" ] && eerror "Vous devez définir RUNSMOD_BASEDIR"
        return 1
    fi
    if [ ! -d "$RUNSMOD_BASEDIR" -a -z "$check_only" ]; 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 have_repolistfile repolistfile mtime
    local -a baseurls
    setx now=date +%s
    for RUNSMOD_PROFILE in "${RUNSMOD_PROFILES[@]}"; do
        __runsmod_get -a baseurls BASEURL
        have_repolistfile=
        for baseurl in "${baseurls[@]}"; do
            setx repolistfile=__runsmod_get_repolistfile "$baseurl"
            if [ -f "$repolistfile" ]; then
                have_repolistfile=1
                # 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
            fi
        done
        # si aucun des fichiers n'existe, il faut mettre à jour
        [ -n "$have_repolistfile" ] || 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 error
    local -a baseurls
    setx now=date +%s
    for RUNSMOD_PROFILE in "${RUNSMOD_PROFILES[@]}"; do
        __runsmod_get -a baseurls BASEURL
        for baseurl in "${baseurls[@]}"; do
            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

            error=
            if [ -n "$update" ]; then
                local list
                ebegin "$baseurl"
                if setx list=__runsmod_getinfo "$baseurl"; then
                    echo "$list" | __runsmod_fixinfo >"$repolistfile"
                    edot 0
                else
                    error=1
                    edot 1
                fi
                eend
            fi
            [ -n "$error" ] && continue

            break
        done
    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"
    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]"
            mkdirof "$repodir"
            git clone ${RUNSMOD_SHALLOW:+--depth 1} "$repourl" "$repodir" || return $?
            if [ "$RUNSMOD_MODE" == devel ]; then
                (
                    cd "$repodir"
                    if git_have_rbranch develop; then
                        git checkout develop || exit 1
                    fi
                ) || return $?
            fi
            git_annex_initial "$repodir" || return $?
            return 0
        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 baseurls 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
        __runsmod_get -a baseurls BASEURL
        for baseurl in "${baseurls[@]}"; do
            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
                        reposuffixes=()
                        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
                        reposuffixes=("")
                    fi

                    reponames=()
                    if __runsmod_has_vhost "$repospec"; then
                        if [ -n "$all_hosts" ]; then
                            setx rs1=__runsmod_replace1 "$repospec" "*"
                            __runsmod_match_repo_add repolist "$rs1" reponames
                        elif [ -n "$host" ]; then
                            setx rs1=__runsmod_replace1 "$repospec" "$host"
                            array_contains repolist "$rs1" && array_add reponames "$rs1"
                            setx rs2=__runsmod_replace2 "$repospec" "$host"
                            array_contains repolist "$rs2" && array_add reponames "$rs2"
                        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"
                        setx repodir=__runsmod_mapdir "$repodir" "$RUNSMOD_BASEDIR/$repopath"
                        __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
    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
        __runsmod_get -a baseurls BASEURL
        for baseurl in "${baseurls[@]}"; do
            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
                            reposuffixes=()
                            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
                            reposuffixes=("")
                        fi

                        reponames=()
                        if [ -n "$all_modules" ]; then
                            if __runsmod_has_vhost "$repospec"; then
                                if [ -n "$all_hosts" ]; then
                                    setx rs1=__runsmod_replace1 "$repospec" "*" "*"
                                    __runsmod_match_repo_add repolist "$rs1" reponames
                                elif [ -n "$host" ]; then
                                    setx rs1=__runsmod_replace1 "$repospec" "$host" "*"
                                    __runsmod_match_repo_add repolist "$rs1" reponames
                                    setx rs2=__runsmod_replace2 "$repospec" "$host" "*"
                                    __runsmod_match_repo_add repolist "$rs2" reponames
                                fi
                            else
                                setx rs1=__runsmod_replace1 "$repospec" "" "*"
                                __runsmod_match_repo_add repolist "$rs1" reponames
                            fi
                        else
                            if __runsmod_has_vhost "$repospec"; then
                                if [ -n "$host" ]; then
                                    setx rs1=__runsmod_replace1 "$repospec" "$host" "$module"
                                    array_contains repolist "$rs1" && array_add reponames "$rs1"
                                    setx rs2=__runsmod_replace2 "$repospec" "$host" "$module"
                                    array_contains repolist "$rs2" && array_add reponames "$rs2"
                                fi
                            else
                                setx rs1=__runsmod_replace1 "$repospec" "" "$module"
                                array_contains repolist "$rs1" &&  array_add reponames "$rs1"
                            fi
                        fi

                        edebug "........ reponames=(${reponames[*]})"
                        for reponame in "${reponames[@]}"; do
                            repodir="$RUNSMOD_BASEDIR/$repopath/$reponame"

                            setx repourl=__runsmod_fixurl "$reponame" "$baseurl"
                            setx repodir=__runsmod_mapdir "$repodir" "$RUNSMOD_BASEDIR/$repopath"
                            __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
    done

    for module in "${modules[@]}"; do
        [ "$module" == "*" ] && continue
        array_contains foundmodules "$module" || ewarn "$module: module non trouvé"
    done

    return $r
}

function runsmod_update_vars() {
    local all_hosts host_mode="$1" host="$2"
    case "$host_mode" in
    none) host=;;
    all) host=; all_hosts=1;;
    self) host="${RUNSHOST:-$MYHOST}";;
    esac
    # le nom d'hôte doit être avec un domaine
    [ -n "$host" -a "${host%%.*}" == "$host" -a -n "$RUNSDOMAIN" ] && host="$host.$RUNSDOMAIN"

    # Calcul des répertoires d'hôte
    for RUNSMOD_PROFILE in "${RUNSMOD_PROFILES[@]}"; do
        __runsmod_get -a baseurls BASEURL
        for baseurl in "${baseurls[@]}"; do
            setx repopath=__runsmod_getpath_from_baseurl "$baseurl"
            setx repolistfile=__runsmod_get_repolistfile "$baseurl"
            [ -f "$repolistfile" ] || continue

            #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"
                    if [ "$vprefix" == HOSTS ]; then :
                    elif __runsmod_has_vhost "$repospec"; then
                        repospec="${repospec%%/%h*}"
                    else continue
                    fi
                    reposuffixes=("")
                    if [[ "$repospec" == *//* ]]; then
                        reposuffix="${repospec#*//}"
                        [ -n "$reposuffix" ] && reposuffix="/$reposuffix"
                        repospec="${repospec%%//*}"
                        reposuffixes=("$reposuffix")
                    fi

                    if setx repospec=__runsmod_mapdir "$repospec"; then
                        repodirs=("$repospec")
                    else
                        array_lsdirs repodirs "$RUNSMOD_BASEDIR/$repopath" "$repospec"
                    fi
                    for repodir in "${repodirs[@]}"; do
                        #edebug "........ repodir=$repodir"
                        [ -d "$repodir" ] || continue
                        for reposuffix in "${reposuffixes[@]}"; do
                            array_addu HOSTSDIRS "$repodir$reposuffix"
                        done
                    done
                done
            done
        done
    done

    # Calcul des répertoires de module
    for RUNSMOD_PROFILE in "${RUNSMOD_PROFILES[@]}"; do
        __runsmod_get -a baseurls BASEURL
        for baseurl in "${baseurls[@]}"; do
            setx repopath=__runsmod_getpath_from_baseurl "$baseurl"
            setx repolistfile=__runsmod_get_repolistfile "$baseurl"
            [ -f "$repolistfile" ] || continue

            #edebug ".. baseurl=$baseurl, repopath=$repopath"
            for vprefix in MODULES HOSTS; do
                if [ "$vprefix" == HOSTS ]; then
                    __runsmod_get -a tmprepourls "${vprefix}_URLS"
                    repourls=()
                    for repourl in "${tmprepourls[@]}"; do
                        if __runsmod_has_vmodule "$repourl"; then
                            array_add repourls "$repourl"
                        else
                            array_add repourls "$repourl/%h/modules"
                            array_add repourls "$repourl/%h"
                        fi
                    done
                else
                    __runsmod_get -a repourls "${vprefix}_URLS"
                fi
                #edebug ".... vprefix=$vprefix, repourls=(${repourls[*]})"

                for repospec in "${repourls[@]}"; do
                    #edebug "...... repospec=$repospec"
                    repospec="${repospec%%/%m*}"
                    reposuffixes=("")
                    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
                    fi

                    repospecs=()
                    if __runsmod_has_vhost "$repospec"; then
                        if [ -n "$all_hosts" ]; then
                            setx rs1=__runsmod_replace1 "$repospec" "*"
                            array_addu repospecs "$rs1"
                        elif [ -n "$host" ]; then
                            setx rs1=__runsmod_replace1 "$repospec" "$host"
                            array_addu repospecs "$rs1"
                            setx rs2=__runsmod_replace2 "$repospec" "$host"
                            array_addu repospecs "$rs2"
                        fi
                    else
                        array_addu repospecs "$repospec"
                    fi

                    #edebug "...... repospecs=(${repospecs[*]})"
                    for repospec in "${repospecs[@]}"; do
                        if setx repospec=__runsmod_mapdir "$repospec"; then
                            repodirs=("$repospec")
                        else
                            array_lsdirs repodirs "$RUNSMOD_BASEDIR/$repopath" "$repospec"
                        fi
                        for repodir in "${repodirs[@]}"; do
                            #edebug "........ repodir=$repodir"
                            [ -d "$repodir" ] || continue
                            for reposuffix in "${reposuffixes[@]}"; do
                                array_addu MODULESDIRS "$repodir$reposuffix"
                            done
                        done
                    done
                done
            done
        done
    done

    # Calcul des répertoires de script
    for RUNSMOD_PROFILE in "${RUNSMOD_PROFILES[@]}"; do
        __runsmod_get -a baseurls BASEURL
        for baseurl in "${baseurls[@]}"; do
            setx repopath=__runsmod_getpath_from_baseurl "$baseurl"
            setx repolistfile=__runsmod_get_repolistfile "$baseurl"
            [ -f "$repolistfile" ] || continue

            #edebug ".. baseurl=$baseurl, repopath=$repopath"
            for vprefix in SCRIPTS HOSTS; do
                __runsmod_get -a repourls "${vprefix}_URLS"
                #edebug ".... vprefix=$vprefix, repourls=(${repourls[*]})"

                for repospec in "${repourls[@]}"; do
                    #edebug "...... repospec=$repospec"
                    if [ "$vprefix" == HOSTS ]; then
                        __runsmod_has_vhost "$repospec" || repospec="$repospec/%h/runs"
                    fi
                    reposuffixes=("")
                    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
                    fi

                    repospecs=()
                    if __runsmod_has_vhost "$repospec"; then
                        if [ -n "$all_hosts" ]; then
                            setx rs1=__runsmod_replace1 "$repospec" "*"
                            array_addu repospecs "$rs1"
                        elif [ -n "$host" ]; then
                            setx rs1=__runsmod_replace1 "$repospec" "$host"
                            array_addu repospecs "$rs1"
                            setx rs2=__runsmod_replace2 "$repospec" "$host"
                            array_addu repospecs "$rs2"
                        fi
                    else
                        array_addu repospecs "$repospec"
                    fi

                    #edebug "...... repospecs=(${repospecs[*]})"
                    for repospec in "${repospecs[@]}"; do
                        if setx repospec=__runsmod_mapdir "$repospec"; then
                            repodirs=("$repospec")
                        else
                            array_lsdirs repodirs "$RUNSMOD_BASEDIR/$repopath" "$repospec"
                        fi
                        for repodir in "${repodirs[@]}"; do
                            #edebug "........ repodir=$repodir"
                            [ -d "$repodir" ] || continue
                            for reposuffix in "${reposuffixes[@]}"; do
                                array_addu SCRIPTSDIRS "$repodir$reposuffix"
                            done
                        done
                    done
                done
            done
        done
    done
}

function runsmod_teardown_vars() {
    setx RUNSSCRIPTSPATH=array_join SCRIPTSDIRS :
    setx RUNSMODULESPATH=array_join MODULESDIRS :
    setx RUNSHOSTSPATH=array_join HOSTSDIRS :
    [ -n "$RUNSSCRIPTSPATH" ] || RUNSSCRIPTSPATH=:
    [ -n "$RUNSMODULESPATH" ] || RUNSMODULESPATH=:
    [ -n "$RUNSHOSTSPATH" ] || RUNSHOSTSPATH=:
}