#!/bin/bash
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
source "$(dirname "$0")/lib/ulib/auto" || exit 1

function display_help() {
    uecho "$scriptname: outil pour faciliter l'utilisation de docker

USAGE
    $scriptname CMDs...

COMMANDES
    b|build [SERVICE]
        Construire les images
    p|push
    p|push [SERVICES...]
        La première syntaxe est utilisable avec un projet docker. Elle permet de
        pousser l'image qui a été construite avec build vers le serveur
        La deuxième syntaxe est utilisée avec un projet docker-compose. Elle
        permet de pousser les images correspondant aux services qui ont été
        construit vers le serveur.
    s|start [SERVICE]
        Démarrer le(s) service(s)
    k|stop [SERVICE]
        Arrêter le(s) service(s)
    1|up
        Créer l'environnement, démarrer les services et suivre les logs de façon
        interactive.
        Vaguement équivalent à -- start -- logs
    l|logs [SERVICE]
        Afficher les logs
    0|down
        Arrêter les services et supprimer l'environnement
    r|run SERVICE [COMMAND]
        Démarrer le service en mode interactif avec la commande spécifiée
        Les options suivantes sont supportées, mais il faut les spécifier avant
        SERVICE:
        * pour docker et docker-compose: --volume
        * uniquement pour docker-compose: --detach, -e, --label, --no-deps,
          --service-ports, --use-aliases
        Par défaut, --rm est activé; utiliser --no-rm pour ne pas supprimer le
        container après utilisation.
    x|exec SERVICE COMMAND
        Lancer une commande dans le container correspondant au service spécifié,
        qui doit être en fonctionnement
    d|brd
        Construire les images (comme avec build), démarrer les services et
        suivre les logs de façon interactive (comme avec up). Dès que l'on
        arrête l'affichage des logs avec Ctrl+C, arrêter les services et
        supprimer l'environnement (comme avec down)
        Vaguement équivalent à -- build -- start [args] -- logs
                      suivi de -- down
    bs
        Construire les images (comme avec build) puis démarrer les services
        (comme avec start)
        Equivalent à -- build -- start [args]
    br SERVICE [COMMAND]
        Construire les images (comme avec build) puis démarrer le service avec
        la commande spécifiée (comme avec run)
        Equivalent à -- build -- run [args]
    y|deploy [args...]
        (Re)déployer un stack. Cette commande ne fonctionne qu'en mode swarm.
        Implique --stack
    by|bd [args...]
        Equivalent à --stack -- build -- deploy args...
        Utilisable notamment en développement
    bp [args...]
        Equivalent à --stack -- build -- push args...
    bpy|bpd [args...]
        Equivalent à --stack -- build -- push -- deploy args...
    service COMMAND SERVICE [args...]
        Frontend pour 'docker service COMMAND args... SERVICE'
        Cette commande ne fonctionne qu'en mode swarm. Il n'est pas nécessaire
        de préfixer le nom du service avec le nom du stack, pour être cohérent
        avec les autres commandes
        IMPORTANT: notez que les arguments sont placés avant le nom du service.
        Celà signifie qu'on ne peut spécifier que des options à la commande.
        Penser aussi à protéger ces options de l'analyse eg.
            $scriptname -- service logs web -f
        Pour des cas d'utilisation plus complexe, il faut lancer directement
        docker service
    u|update SERVICE [args...]
        Mettre à jour un service, équivalent à 'service update SERVICE'
    scale SERVICE=REPLICAS [args...]
        Mettre à jour le nom de réplicas d'un service, équivalent à la commande
        'service scale SERVICE=REPLICAS'
    ip|show-ip [SERVICE]
        Afficher l'adresse IP interne du service
    systemd|systemd-unit
        Générer une unité systemd qui démarre les services. A priori, ce n'est
        nécessaire que si aucune politique de redémarrage n'a été définie.
    ps
        Afficher les containers en cours d'exécution
    ls
        Lister les images actuellement présentes
    rm
        Supprimer une image
    X|prune
        Supprimer les containers et les images inutilisées

OPTIONS générales
    (ces options sont communes à toutes les commandes)
    -d, --chdir PROJDIR
        Spécifier le répertoire du projet
    -c, --config CONFIG[.yml]
        Spécifier le fichier de configuration à utiliser. le fichier de profil
        CONFIG.PROFILE.yml est chargé aussi s'il existe.
        NB: il n'est pas nécessaire d'ajouter l'extension .yml au nom, cela
        permet de faciliter l'utilisation avec l'auto-complétion quand il existe
        des fichiers de profil
        Si cette option n'est pas spécifiée, docker-compose.yml est utilisé par
        défaut (ou avec l'option --stack docker-stack.yml s'il existe)
    -p, --profile PROFILE
    -P, --prod
    -T, --test
        Spécifier le profil
    -m, --set-machine MACHINE
        Choisir l'environnement docker-machine spécifié avant de lancer les
        commandes
    -n, --fake
        Ne pas lancer les commandes, simplement les afficher
    -h, --host HOST
        Spécifier l'hôte pour la commande systemd-unit

OPTIONS build
    (ces options ne sont valides que pour les commandes build, brd, bs, bd, bpd)
    --stack
        Indiquer que le build est fait pour un déploiement avec deploy.
        S'il existe un fichier docker-stack.yml, il est utilisé de préférence à
        la place de docker-compose.yml. De même, les fichiers de profil de la
        forme docker-stack.PROFILE.yml sont utilisés de préférence aux fichiers
        docker-compose.PROFILE.yml
        Cette option n'est nécessaire qu'avec build puisque les commandes
        deploy, bd, bpd et update impliquent --stack
    -j, --no-cache
        Ne pas utiliser le cache lors du build
    -g, --ug, --no-update-apps
        ne pas mettre à jour les dépôts dépendants. ces dépôts sont définis dans
        le fichier update-apps.conf qui a le format suivant:
            DEFAULT_ORIGIN=
            DEFAULT_BRANCH=
            DEFAULT_DEVEL_SRCDIR=
            APPS=()             # liste d'applications à mettre à jour
            app_URL=            # url du dépôt
            app_DEVEL_SRCDIR=   # répertoire source en mode devel
            app_DEST=           # répertoire dans lequel faire le checkout
            app_PROFILE_ORIGIN= # origine spécifique à un profil
            app_PROFILE_BRANCH= # branche spécifique à un profil
            app_ORIGIN=         # ou... origine par défaut de la branche
            app_BRANCH=         # ou... branche par défaut
            app_TYPE=           # type de projet (composer par défaut)
            app_AFTER_UPDATE=() # liste de commandes à lancer après le checkout
    -u, --uu, --update-apps-only
        Ne faire que la mise à jour depuis les dépôts dépendants.
    -w, --ww, --update-apps-devel
        Faire la mise à jour en mode devel: le projet ainsi que ses fichiers des
        répertoires vendor/lib et vendor/ur sont synchronisés via rsync depuis
        \$DEFAULT_DEVEL_SRCDIR qui vaut par défaut \$HOME/wop/php
    --uo, --update-apps-origin ORIGIN
        Spécifier l'origine par défaut pour update-apps
    --ub, --update-apps-branch BRANCH
        Spécifier la branche par défaut pour update-apps

OPTIONS deploy
    -l, --without-registry-auth
        Ne pas transporter les informations d'autorisation aux agents swarm
        (c'est à dire ne pas utiliser l'option --with-registry-auth)

VARIABLES de update-apps.conf
    DEVEL_SRCDIR
        répertoire source pour le mode devel. attention, il s'agit du répertoire
        du projet, alors que DEFAULT_DEVEL_SRCDIR est le répertoire de base par
        défaut des projets
    ORIGIN
        vaut 'origin' par défaut
    BRANCH
        vaut 'develop' par défaut
    TYPE
        vaut 'composer' par défaut si le fichier composer.json existe à la
        racine du projet. sinon vaut 'inconnu' par défaut
    AFTER_UPDATE
        Cette variable est une liste de commandes à lancer après la maj du dépôt
        - si le chemin est absolu ou relatif, lancer la commande telle quelle
        - s'il n'y a pas de chemin, alors ce doit être le nom d'une fonction
          existante auquel on enlève le préfixe update_apps_func_
FONCTIONS de update-apps.conf
    sqlmig [DESTDIR [SRCDIR]]
        Copier les définitions des bases de données au format sqlmig de
        SRCDIR/config/sqlmig vers DESTDIR/config/mariadb/sqlmig"
}

function get_version() {
    local GIT_DIR; unset GIT_DIR
    if git rev-parse --git-dir >/dev/null 2>&1; then
        local head commit tag
        commit="$(git rev-list --tags --max-count=1 2>/dev/null)"
        if [ -n "$commit" ]; then
            tag="$(git describe --tags "$commit" 2>/dev/null)"
            if [ -n "$tag" ]; then
                head="$(git rev-parse HEAD)"
                if [ "$commit" != "$head" ]; then
                    echo "$tag-develop"
                else
                    echo "$tag"
                fi
                return
            fi
        fi
    elif [ -f VERSION.txt ]; then
        cat VERSION.txt
    fi
    echo develop
}

function docker_add_build_arg() {
    eval "replace_build_args+=(--build-arg $1=\"$2\"); $1=\"$2\""
}
function docker_parse_build_args() {
    cat "$1" |
    grep -v '^#' |
    grep -v '^$' |
    sed -r 's/([^=]+)=(.*)/replace_build_args+=(--build-arg \1="\2"); \1="\2"/'
}
function docker_parse_env_args() {
    [ -f .build.env ] && eval "$(docker_parse_build_args .build.env)"
    [ -f build.env ] && eval "$(docker_parse_build_args build.env)"
    [ -n "$PROFILE" -a -f ".build.$PROFILE.env" ] && eval "$(docker_parse_build_args ".build.$PROFILE.env")"
}
function docker_set_env_args() {
    [ -f .build.env ] && source ./.build.env
    [ -f build.env ] && source ./build.env
    [ -n "$PROFILE" -a -f ".build.$PROFILE.env" ] && source "./.build.$PROFILE.env"
}
function docker_set_run_args() {
    replace_run_args+=(--env-file "$1")
    source "$1"
}
function docker_check_name() {
    [ -n "$NAME" ] || die "Vous devez définir NAME dans .build.env"

    if [ "$1" == set_container_name ]; then
        project_name="$NAME"
        container_name="${project_name//[^a-zA-Z0-9_-]/}"
        [ -n "$PROFILE" ] && container_name="${container_name}_$PROFILE"
    fi
}

function compose_set_project_name() {
    local PROJECT_NAME= PROJECT_NAME_REMOVE_SUFFIX=.service PROJECT_NAME_ADD_PROFILE=
    [ -f .compose.env ] && source ./.compose.env

    [ -n "$PROJECT_NAME" ] || PROJECT_NAME="$(basename -- "$(pwd)")"
    PROJECT_NAME="${PROJECT_NAME%$PROJECT_NAME_REMOVE_SUFFIX}"

    if [ -n "$PROFILE" ]; then
        [ -n "$COMPOSE_PROJECT_NAME" ] || COMPOSE_PROJECT_NAME="$PROJECT_NAME${PROJECT_NAME_ADD_PROFILE:+_${PROFILE}}"
    else
        [ -n "$COMPOSE_PROJECT_NAME" ] || COMPOSE_PROJECT_NAME="$PROJECT_NAME"
    fi
    export COMPOSE_PROJECT_NAME

    if [ "$1" == set_container_name ]; then
        project_name="$PROJECT_NAME"
        container_name="${project_name//[^a-zA-Z0-9_-]/}"
        [ -n "$PROFILE" -a -n "$PROJECT_NAME_ADD_PROFILE" ] && container_name="${container_name}_$PROFILE"
    fi
}
function compose_set_env_args() {
    if [ -n "$CONFIG" ]; then
        # autocomplétion friendly
        [ ! -f "$CONFIG" -a -f "${CONFIG}yml" ] && CONFIG="${CONFIG}yml"
        [ ! -f "$CONFIG" -a -f "$CONFIG.yml" ] && CONFIG="$CONFIG.yml"
        ##
        replace_env_args+=(-f "$CONFIG")
        if [ -n "$PROFILE" -a -f "${CONFIG%.yml}.$PROFILE.yml" ]; then
            replace_env_args+=(-f "${CONFIG%.yml}.$PROFILE.yml")
        fi
    else
        if [ -n "$USE_STACK" -a -f docker-stack.yml ]; then
            replace_env_args+=(-f docker-stack.yml)
        else
            replace_env_args+=(-f docker-compose.yml)
        fi
        if [ -n "$USE_STACK" -a -f docker-stack.override.yml ]; then
            replace_env_args+=(-f docker-stack.override.yml)
        elif [ -f docker-compose.override.yml ]; then
            replace_env_args+=(-f docker-compose.override.yml)
        fi
        if [ -n "$PROFILE" ]; then
            if [ -n "$USE_STACK" -a -f "docker-stack.$PROFILE.yml" ]; then
                replace_env_args+=(-f "docker-stack.$PROFILE.yml")
            elif [ -f "docker-compose.$PROFILE.yml" ]; then
                replace_env_args+=(-f "docker-compose.$PROFILE.yml")
            fi
        fi
    fi

    compose_set_project_name "$@"
}
function docker_set_deploy_args() {
    if [ -n "$CONFIG" ]; then
        # autocomplétion friendly
        [ ! -f "$CONFIG" -a -f "${CONFIG}yml" ] && CONFIG="${CONFIG}yml"
        [ ! -f "$CONFIG" -a -f "$CONFIG.yml" ] && CONFIG="$CONFIG.yml"
        ##
        replace_deploy_args+=(-c "$CONFIG")
        if [ -n "$PROFILE" -a -f "${CONFIG%.yml}.$PROFILE.yml" ]; then
            replace_deploy_args+=(-c "${CONFIG%.yml}.$PROFILE.yml")
        fi
    else
        if [ -n "$USE_STACK" -a -f docker-stack.yml ]; then
            replace_deploy_args+=(-c docker-stack.yml)
        else
            replace_deploy_args+=(-c docker-compose.yml)
        fi
        if [ -n "$USE_STACK" -a -f docker-stack.override.yml ]; then
            replace_deploy_args+=(-c docker-stack.override.yml)
        elif [ -f docker-compose.override.yml ]; then
            replace_deploy_args+=(-c docker-compose.override.yml)
        fi
        if [ -n "$PROFILE" ]; then
            if [ -n "$USE_STACK" -a -f "docker-stack.$PROFILE.yml" ]; then
                replace_deploy_args+=(-c "docker-stack.$PROFILE.yml")
            elif [ -f "docker-compose.$PROFILE.yml" ]; then
                replace_deploy_args+=(-c "docker-compose.$PROFILE.yml")
            fi
        fi
    fi

    compose_set_project_name "$@"
}

function host_run() {
    # lancer le script $2..@ sur l'hôte $1
    # si $1 n'est pas défini ou est le nom de l'hôte local ou vaut 'localhost',
    # lancer le script en local avec les droits root
    # sinon, si docker-machine existe, l'hôte doit correspondre à la machine active
    # sinon, lancer inconditionnellement le script sur l'hôte distant
    local host="$1" script="$2"; shift; shift
    if [ -n "$host" -a "$host" != localhost ]; then
        if check_hostname "$host"; then
            estep "Lancement de $script localement"
            runscript_as_root "$script" "$@"
        elif progexists docker-machine; then
            if [ "${host%%.*}" == "$DOCKER_MACHINE_NAME" ]; then
                estep "Copie du script vers root@$host"
                scp "$script" "root@$host:/tmp/tmp-dk-service-script" || die
                estep "Lancement du script à distance"
                local -a args; args=(/tmp/tmp-dk-service-script "$@")
                ssh -qt "root@$host" "$(qvals "${args[@]}"); rm -f /tmp/tmp-dk-service-script"
            else
                ewarn "La machine active ($DOCKER_MACHINE_NAME) n'est pas la destination ($host)"
            fi
        else
            estep "Copie du script vers root@$host"
            scp "$script" "root@$host:/tmp/tmp-dk-service-script" || die
            estep "Lancement du script à distance"
            local -a args; args=(/tmp/tmp-dk-service-script "$@")
            ssh -qt "root@$host" "$(qvals "${args[@]}"); rm -f /tmp/tmp-dk-service-script"
        fi
    else
        estep "Lancement de $script localement"
        runscript_as_root "$script" "$@"
    fi
}
function local_run() {
    # lancer le script $2..@ sur l'hôte $1 uniquement si c'est l'hôte courant
    local host="$1" script="$2"; shift; shift
    if [ -n "$host" ]; then
        if ! check_hostname "$host"; then
            eerror "Cette commande doit obligatoirement être lancée depuis l'hôte $host"
            return 1
        fi
    fi
    estep "Lancement de $script localement"
    runscript_as_root "$script" "$@"
}

BUILD_UPDATE_APPS=
BUILD_BUILD=
UPDATE_APPS_ORIGIN=
UPDATE_APPS_BRANCH=
function build_set_options() {
    BUILD_BUILD=
    BUILD_UPDATE_APPS=
    BUILD_UPDATE_DEVEL=
    [[ "$1" == *b* ]] && BUILD_BUILD=1
    [[ "$1" == *u* ]] && BUILD_UPDATE_APPS=1
    [[ "$1" == *w* ]] && BUILD_UPDATE_DEVEL=1
    UPDATE_APPS_ORIGIN="$2"
    UPDATE_APPS_BRANCH="$3"
}

function update_apps_func_sqlmig() {
    local destdir="$1" srcdir="$2"
    [ -n "$destdir" ] || destdir=db
    [ "${destdir%/config/mariadb/sqlmig}" != "$destdir" ] || destdir="$destdir/config/mariadb/sqlmig"

    [ -n "$srcdir" ] || srcdir="$dest"
    [ "${srcdir%/config/sqlmig}" != "$srcdir" ] || srcdir="$srcdir/config/sqlmig"

    if [ ! -d "$srcdir" ]; then
        eerror "$srcdir: répertoire introuvable"
        return 1
    fi

    local -a sqlmigs; local sqlmig name
    array_lsall sqlmigs "$srcdir"
    mkdir -p "$destdir" || return 1
    for sqlmig in "${sqlmigs[@]}"; do
        if [ -d "$sqlmig" ]; then
            setx name=basename -- "$sqlmig"
            rsync -av --delete-after "$sqlmig/" "$destdir/$name"
        else
            rsync -av "$sqlmig" "$destdir"
        fi
    done
    return 0
}

function build_update_apps() {
    [ -n "$BUILD_UPDATE_APPS" ] || return 0
    [ -f update-apps.conf ] || return 0

    # charger le fichier de configuration
    local DEFAULT_ORIGIN DEFAULT_BRANCH APPS
    DEFAULT_ORIGIN="$UPDATE_APPS_ORIGIN"
    [ -z "$DEFAULT_ORIGIN" ] && DEFAULT_ORIGIN=origin
    DEFAULT_BRANCH="$UPDATE_APPS_BRANCH"
    #XXX à terme, on déploiera la branche master en prod
    [ -z "$DEFAULT_BRANCH" -a "$PROFILE" == prod ] && DEFAULT_BRANCH=develop #master
    [ -z "$DEFAULT_BRANCH" ] && DEFAULT_BRANCH=develop
    DEFAULT_DEVEL_SRCDIR="$HOME/wop/php"
    APPS=()
    [ -f update-apps.conf ] && source ./update-apps.conf
    [ ${#APPS[*]} -gt 0 ] || return 0

    local PRODUCTION DEVELOPMENT
    case "$PROFILE" in
    prod) PRODUCTION=1; DEVELOPMENT=;;
    test) PRODUCTION=1; DEVELOPMENT=1;;
    devel) PRODUCTION=; DEVELOPMENT=;;
    esac

    etitle "Mise à jour des dépendances"
    local app var type url devel_srcdir dest branch after_update after_updates
    for app in "${APPS[@]}"; do
        etitle "$app"

        var="${app//-/_}"

        url="${var}_URL"; url="${!url}"
        [ -n "$url" ] || {
            ewarn "$app: vous devez définir l'url"
            eend; return 1
        }

        devel_srcdir="${var}_DEVEL_SRCDIR"; devel_srcdir="${!devel_srcdir}"
        [ -n "$devel_srcdir" ] || devel_srcdir="$DEFAULT_DEVEL_SRCDIR/${url##*/}"

        dest="${var}_DEST"; dest="${!dest}"
        [ -n "$dest" ] || dest="$app/b"
        mkdir -p "$dest" || { eend; return 1; }

        origin="${var}_${PROFILE}_ORIGIN"; origin="${!origin}"
        [ -n "$origin" ] || { origin="${var}_ORIGIN"; origin="${!origin}"; }
        [ -n "$origin" ] || origin="$DEFAULT_ORIGIN"

        branch="${var}_${PROFILE}_BRANCH"; branch="${!branch}"
        [ -n "$branch" ] || { branch="${var}_BRANCH"; branch="${!branch}"; }
        [ -n "$branch" ] || branch="$DEFAULT_BRANCH"

        # calculer le type maintenant, on en a besoin pour le mode devel
        type="${var}_TYPE"; type="${!type}"

        dest="$dest/$app"
        if [ -n "$BUILD_UPDATE_DEVEL" ]; then
            # synchronisation en mode devel
            local -a rsync_opts; rsync_opts=(-a --delete --exclude .git/ --delete-excluded)
            estep "Synchro $devel_srcdir --> $dest"
            rsync "${rsync_opts[@]}" "$devel_srcdir/" "$dest" || { eend; return 1; }

            if [ -z "$type" ]; then
                # possible de détecter le type quand on a le projet
                # en cas de maj ici, mettre à jour aussi le code ci-dessous
                if [ -f "$dest/composer.json" ]; then type=composer
                else type=inconnu
                fi
            fi

            if [ "$type" == composer ]; then
                # Synchronisation des dépendances
                local -a depdirs; local depdir pname
                setx -a depdirs=ls -d "$dest/vendor/"{lib,ur}/* 2>/dev/null
                for depdir in "${depdirs[@]}"; do
                    [ -L "$depdir" ] && rm "$depdir"
                    pname="${depdir#$dest/vendor/}"; pname="${pname/\//-}"
                    estep "Synchro $DEFAULT_DEVEL_SRCDIR/$pname --> $depdir"
                    rsync "${rsync_opts[@]}" --exclude /vendor/ "$DEFAULT_DEVEL_SRCDIR/$pname/" "$depdir"
                done
            fi
        else
            if [ -d "$dest" -a -d "$dest/.git" ]; then
                # mise à jour
                estep "Maj dépôt $url:$branch --> $dest"
                setx cwd=pwd
                cd "$dest"
                git fetch --all -p -f || { eend; return 1; }
                git reset --hard "$origin/$branch" || { eend; return 1; }
                cd "$cwd"
            else
                # reliquat mode devel?
                [ -d "$dest" ] && rm -rf "$dest"
                # clonage initial
                estep "Clonage $url:$branch --> $dest"
                git clone -o "$origin" -b "$branch" "$url" "$dest" || { eend; return 1; }
            fi

            if [ -z "$type" ]; then
                # possible de détecter le type quand on a le projet
                # en cas de maj ici, mettre à jour aussi le code ci-dessus
                if [ -f "$dest/composer.json" ]; then type=composer
                else type=inconnu
                fi
            fi
        fi

        after_updates="${var}_AFTER_UPDATE"
        if is_defined "$after_updates"; then
            after_updates="$after_updates[@]"; after_updates=("${!after_updates}")
        elif [ "$type" == composer ]; then
            after_updates=(sqlmig)
        else
            after_updates=()
        fi

        estep "Type de dépôt: $type"
        if [ "$type" == composer ]; then
            composer=/usr/bin/composer
            [ -x "$dest/composer.phar" ] && composer="$dest/composer.phar"

            if [ -z "$BUILD_UPDATE_DEVEL" ]; then
                estep "Installation des dépendances composer"
                "$composer" -d"$dest" install ${PRODUCTION:+--no-dev -o} || { eend; return 1; }
            fi
        fi

        for after_update in "${after_updates[@]}"; do
            if [ "${after_update#/}" != "$after_update" ]; then
                # commande absolue, la lancer telle quelle
                estep "$after_update"
                eval "$after_update" || { eend; return 1; }
            elif [ "${after_update#./}" != "$after_update" ]; then
                # commande relative, la lancer telle quelle
                estep "$after_update"
                eval "$after_update" || { eend; return 1; }
            else
                # c'est une fonction update_apps_func_*
                estep "$after_update"
                eval "update_apps_func_$after_update" || { eend; return 1; }
            fi
        done

        eend
    done
    eend
}

function initialize_build_env() {
    CTXDIR=.
    NAME=
    TAGS=(latest)
    VERSION=
    DIST=
}
function default_update_build_env() {
    if [ -n "$DIST" ]; then
        [ -n "$VERSION" ] && VERSION="$VERSION-"
        VERSION="$VERSION$DIST"
        TAGS+=("$DIST")
    fi
    [ -n "$VERSION" ] || docker_add_build_arg VERSION "$(get_version)"
    [ -n "$VERSION" ] && TAGS+=("$VERSION")
}
function update_build_env() { default_update_build_env; }

function default_compose_build() {
    ${FAKE:+qvals} docker-compose \
        "${replace_env_args[@]}" "${env_args[@]}" \
        build \
        ${NO_CACHE:+--no-cache} \
        "${replace_build_args[@]}" "${build_args[@]}" \
        "$@"
}
function default_docker_build() {
    local tag
    for tag in "${TAGS[@]}"; do
        replace_build_args+=(-t "$NAME:$tag")
    done
    ${FAKE:+qvals} docker build \
        ${NO_CACHE:+--no-cache} \
        "${replace_env_args[@]}" "${env_args[@]}" \
        "${replace_build_args[@]}" "${build_args[@]}" \
        "$@" "$CTXDIR"
}
function compose_build() {
    [ -n "$BUILD_BUILD" ] || return 0
    default_compose_build "$@"
}
function docker_build() {
    [ -n "$BUILD_BUILD" ] || return 0
    default_docker_build "$@"
}
function auto_build() {
    local -a replace_env_args env_args
    local -a replace_build_args build_args
    initialize_build_env
    if [ -f docker-compose.yml ]; then
        compose_set_env_args
        update_build_env
        build_update_apps || return 1
        compose_build "$@"
    else
        docker_parse_env_args
        docker_check_name
        docker_add_build_arg build_date "$(date +%y%m%d)"
        update_build_env
        build_update_apps || return 1
        docker_build "$@"
    fi
}

function default_compose_push() {
    ${FAKE:+qvals} docker-compose \
        "${replace_env_args[@]}" "${env_args[@]}" \
        push \
        "$@"
}
function default_docker_push() {
    ${FAKE:+qvals} docker push \
        "${replace_env_args[@]}" "${env_args[@]}" \
        "$@"
}
function compose_push() {
    default_compose_push "$@"
}
function docker_push() {
    local tag
    for tag in "${TAGS[@]}"; do
        default_docker_push "$NAME:$tag" "$@"
    done
}
function auto_push() {
    local -a replace_env_args env_args
    local -a replace_build_args build_args
    initialize_build_env
    if [ -f docker-compose.yml ]; then
        compose_set_env_args
        update_build_env
        compose_push "$@"
    else
        docker_parse_env_args
        docker_check_name
        update_build_env
        docker_push "$@"
    fi
}

function default_compose_up() {
    ${FAKE:+qvals} docker-compose \
        "${replace_env_args[@]}" "${env_args[@]}" \
        up "${replace_run_args[@]}" "${run_args[@]}" \
        "${replace_user_args[@]}" "${user_args[@]}" "$@"
}
function default_docker_up() {
    ${FAKE:+qvals} docker run \
           "${replace_env_args[@]}" "${env_args[@]}" \
           "${replace_run_args[@]}" "${run_args[@]}" \
           "$NAME" \
           "${replace_user_args[@]}" "${user_args[@]}" "$@"
}
function compose_up() { default_compose_up "$@"; }
function docker_up() { default_docker_up "$@"; }
function auto_up() {
    local -a replace_env_args env_args
    local -a replace_run_args run_args
    local -a replace_user_args user_args
    local project_name container_name
    if [ -f docker-compose.yml ]; then
        compose_set_env_args
        replace_run_args=(-d)
        compose_up "$@"
    else
        docker_set_env_args
        docker_check_name set_container_name
        replace_run_args=(-d --name "$container_name")
        docker_up "$@"
    fi
}

function default_compose_stop() {
    ${FAKE:+qvals} docker-compose \
        "${replace_env_args[@]}" "${env_args[@]}" \
        stop "${replace_stop_args[@]}" "${stop_args[@]}" \
        "$@"
}
function default_docker_stop() {
    ${FAKE:+qvals} docker container stop \
           "${replace_stop_args[@]}" "${stop_args[@]}" \
           "$container_name" "$@"
}
function compose_stop() { default_compose_stop "$@"; }
function docker_stop() { default_docker_stop "$@"; }
function auto_stop() {
    local -a replace_env_args env_args
    local -a replace_stop_args stop_args
    local project_name container_name
    if [ -f docker-compose.yml ]; then
        compose_set_env_args
        compose_stop "$@"
    else
        docker_set_env_args
        docker_check_name set_container_name
        docker_stop "$@"
    fi
}

function default_compose_logs() {
    ${FAKE:+qvals} docker-compose \
        "${replace_env_args[@]}" "${env_args[@]}" \
        logs "${replace_logs_args[@]}" "${logs_args[@]}" \
        "$@"
}
function default_docker_logs() {
    ${FAKE:+qvals} docker logs \
           "${replace_logs_args[@]}" "${logs_args[@]}" \
           "$container_name" "$@"
}
function compose_logs() { default_compose_logs "$@"; }
function docker_logs() { default_docker_logs "$@"; }
function auto_logs() {
    local -a replace_env_args env_args
    local -a replace_logs_args logs_args
    local project_name container_name
    if [ -f docker-compose.yml ]; then
        compose_set_env_args
        replace_logs_args=(-f)
        compose_logs "$@"
    else
        docker_set_env_args
        docker_check_name set_container_name
        replace_logs_args=(-f)
        docker_logs "$@"
    fi
}

function default_compose_down() {
    ${FAKE:+qvals} docker-compose \
        "${replace_env_args[@]}" "${env_args[@]}" \
        down "${replace_down_args[@]}" "${down_args[@]}" \
        "$@"
}
function default_docker_down() {
    estep "stop"
    ${FAKE:+qvals} docker container stop \
           "${replace_down_args[@]}" "${down_args[@]}" \
           "$container_name" "$@"
    estep "rm"
    ${FAKE:+qvals} docker container rm \
           "${replace_rm_args[@]}" "${rm_args[@]}" \
           "$container_name"
}
function compose_down() { default_compose_down "$@"; }
function docker_down() { default_docker_down "$@"; }
function auto_down() {
    local -a replace_env_args env_args
    local -a replace_down_args down_args
    local -a replace_rm_args rm_args
    local project_name container_name
    if [ -f docker-compose.yml ]; then
        compose_set_env_args
        compose_down "$@"
    else
        docker_set_env_args
        docker_check_name set_container_name
        docker_down "$@"
    fi
}

function default_compose_run() {
    ${FAKE:+qvals} docker-compose \
        "${replace_env_args[@]}" "${env_args[@]}" \
        run "${replace_run_args[@]}" "${run_args[@]}" \
        "${replace_user_args[@]}" "${user_args[@]}" "$@"
}
function default_docker_run() {
    ${FAKE:+qvals} docker run \
           "${replace_env_args[@]}" "${env_args[@]}" \
           "${replace_run_args[@]}" "${run_args[@]}" \
           "$NAME" \
           "${replace_user_args[@]}" "${user_args[@]}" "$@"
}
function compose_run() { default_compose_run "$@"; }
function docker_run() { default_docker_run "$@"; }
function auto_run() {
    eval "$(utools_local parse_opts)"
    local detach no_deps rm=1 service_ports use_aliases volume
    local -a envs labels
    args=(
        +
        -d,--detach detach=1
        -e: '$add@ envs -e; add@ envs'
        -l:,--label: '$add@ labels -l; add@ labels'
        --no-deps no_deps=1
        --no-rm rm=
        --rm rm=1
        --service-ports service_ports=1
        --use-aliases use_aliases=1
        -v:,--volume: volume=
        @ args -- "$@"
    )
    parse_opts "${args[@]}" && set -- "${args[@]}" || { eerror "$args"; return 1; }

    local -a replace_env_args env_args
    local -a replace_run_args run_args
    local -a replace_user_args user_args
    local project_name container_name
    if [ -f docker-compose.yml ]; then
        compose_set_env_args
        replace_run_args=(
            ${detach:+-d}
            "${envs[@]}" "${labels[@]}"
            ${no_deps:+--no-deps}
            ${rm:+--rm}
            ${service_ports:+--service-ports}
            ${use_aliases:+--use-aliases}
            ${volume:+-v "$volume"}
        )
        compose_run "$@"
    else
        docker_set_env_args
        docker_check_name set_container_name
        replace_run_args=(
            --name "$container_name"
            ${rm:+--rm}
            ${volume:+-v "$volume"}
        )
        docker_run "$@"
    fi
}

function default_compose_exec() {
    ${FAKE:+qvals} docker-compose \
        "${replace_env_args[@]}" "${env_args[@]}" \
        exec "${replace_exec_args[@]}" "${exec_args[@]}" \
        "$@"
}
function default_docker_exec() {
    ${FAKE:+qvals} docker container exec \
           "${replace_exec_args[@]}" "${exec_args[@]}" \
           "$container_name" "$@"
}
function compose_exec() { default_compose_exec "$@"; }
function docker_exec() { default_docker_exec "$@"; }
function auto_exec() {
    local -a replace_env_args env_args
    local -a replace_exec_args exec_args
    local project_name container_name
    if [ -f docker-compose.yml ]; then
        compose_set_env_args
        compose_exec "$@"
    else
        docker_set_env_args
        docker_check_name set_container_name
        docker_exec "$@"
    fi
}

function default_docker_deploy() {
    ${FAKE:+qvals} docker \
        stack deploy \
        "${replace_deploy_args[@]}" "${deploy_args[@]}" \
        "$container_name" "$@"
}
function docker_deploy() { default_docker_deploy "$@"; }
function auto_deploy() {
    local -a replace_env_args env_args
    local -a replace_deploy_args deploy_args
    local project_name container_name
    if [ -f docker-compose.yml -o -f docker-stack.yml ]; then
        docker_set_deploy_args set_container_name
        [ -n "$WITH_REGISTRY_AUTH" ] && replace_deploy_args+=(--with-registry-auth)
        docker_deploy "$@"
    else
        die "Impossible de trouver ni docker-compose.yml ni docker-stack.yml"
    fi
}

function default_docker_service() {
    ${FAKE:+qvals} docker service "$@"
}
function docker_service() { default_docker_service "$@"; }
function auto_service() {
    if [ -f docker-compose.yml -o -f docker-stack.yml ]; then
        local command="$1"; shift
        [ -n "$command" ] || {
            eerror "Vous devez spécifier la commande"
            return 1
        }
        local -a command_args
        [ "$command" == update -a -n "$WITH_REGISTRY_AUTH" ] && command_args+=(--with-registry-auth)
        case "$command" in
        ls) # ces commandes n'ont pas besoin du nom de service
            docker_service "$command" "$@"
            ;;
        *) # ces commandes ont besoin du nom du service
            local service="$1"; shift
            [ -n "$service" ] || {
                eerror "Vous devez spécifier le nom du service"
                return 1
            }
            local -a replace_env_args env_args
            local -a replace_deploy_args deploy_args
            local project_name container_name
            docker_set_deploy_args set_container_name
            service="${container_name}_${service#${container_name}_}"
            docker_service "$command" "${command_args[@]}" "$@" "$service"
            ;;
        esac
    else
        die "Impossible de trouver ni docker-compose.yml ni docker-stack.yml"
    fi
}

function default_compose_show_ip() {
    local -a cmd cids; local cid
    cmd=(
        docker-compose
        "${replace_env_args[@]}" "${env_args[@]}"
        ps -q "${replace_show_ip_args[@]}" "${show_ip_args[@]}"
        "$@"
    )
    if [ -n "$FAKE" ]; then
        echo "docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' \"\$($(qvals "${cmd[@]}"))\""
    else
        setx -a cids="${cmd[@]}" 2>/dev/null
        for cid in "${cids[@]}"; do
            docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$cid"
        done
    fi
}
function default_docker_show_ip() {
    ${FAKE:+qvals} docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' \
           "${replace_show_ip_args[@]}" "${show_ip_args[@]}" \
           "$container_name" "$@"
}
function compose_show_ip() { default_compose_show_ip "$@"; }
function docker_show_ip() { default_docker_show_ip "$@"; }
function auto_show_ip() {
    local -a replace_env_args env_args
    local -a replace_show_ip_args show_ip_args
    local project_name container_name
    if [ -f docker-compose.yml ]; then
        compose_set_env_args
        compose_show_ip "$@"
    else
        docker_set_env_args
        docker_check_name set_container_name
        docker_show_ip "$@"
    fi
}

function default_compose_systemd_unit() {
    local docker_compose="$(which docker-compose 2>/dev/null)"
    if [ -z "$docker_compose" ]; then
        if [ -x /usr/bin/docker-compose ]; then
            docker_compose=/usr/bin/docker-compose
        elif [ -x /usr/local/bin/docker-compose ]; then
            docker_compose=/usr/local/bin/docker-compose
        else
            die "Impossible de trouver docker-compose"
        fi
    fi
    setx startcmd=qvals "$docker_compose" \
        "${replace_env_args[@]}" "${env_args[@]}" \
        up "${replace_run_args[@]}" "${run_args[@]}" \
        "${replace_user_args[@]}" "${user_args[@]}" "$@"
    setx stopcmd=qvals "$docker_compose" down
}
function default_docker_systemd_unit() {
    local docker="$(which docker 2>/dev/null)"
    if [ -z "$docker" ]; then
        if [ -x /usr/bin/docker ]; then
            docker=/usr/bin/docker
        elif [ -x /usr/local/bin/docker ]; then
            docker=/usr/local/bin/docker
        else
            die "Impossible de trouver docker"
        fi
    fi
    setx startcmd=qvals "$docker" run \
           "${replace_env_args[@]}" "${env_args[@]}" \
           "${replace_run_args[@]}" "${run_args[@]}" \
           "$NAME" \
           "${replace_user_args[@]}" "${user_args[@]}" "$@"
    setx stopcmd=qvals "$docker" stop "$container_name"
}
function compose_systemd_unit() { default_compose_systemd_unit "$@"; }
function docker_systemd_unit() { default_docker_systemd_unit "$@"; }
function auto_systemd_unit() {
    local -a replace_env_args env_args
    local -a replace_run_args run_args
    local -a replace_user_args user_args
    local project_name container_name startcmd stopcmd
    local tmpscript; ac_set_tmpfile tmpscript

    estep "Génération de l'unité systemd"
    export COMPOSE_PROJECT_NAME=
    if [ -f docker-compose.yml ]; then
        compose_set_env_args set_container_name
        replace_run_args=(-d --no-color)
        compose_systemd_unit "$@"
        if [ -z "$HOST" -a -f .env ]; then
            source ./.env
            if [ -n "$PROFILE" ]; then
                HOST="${PROFILE^^}_HOST"; HOST="${!HOST}"
            fi
        fi
    else
        docker_set_env_args
        docker_check_name set_container_name
        replace_run_args=(-d --name "$container_name")
        docker_systemd_unit "$@"
    fi
    [ -n "$COMPOSE_PROJECT_NAME" ] || COMPOSE_PROJECT_NAME="$project_name"
    chmod 755 "$tmpscript"
    cat >"$tmpscript" <<EOF
#!/bin/bash
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
cat >/etc/systemd/system/$container_name.service <<EOD
[Unit]
Description=$project_name stack ($PROFILE)
Requires=docker.service
After=docker.service

[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=$(pwd)
Environment=$(qval "COMPOSE_PROJECT_NAME=$COMPOSE_PROJECT_NAME")
ExecStart=$startcmd
ExecStop=$stopcmd
TimeoutStopSec=300

[Install]
WantedBy=multi-user.target
EOD
systemctl daemon-reload
systemctl enable $container_name.service
EOF

    estep "Installation de l'unité systemd"
    local_run "$HOST" "$tmpscript"
}

DEFAULT_PROFILE=devel
PROFILE=
DM_PROFILES=()
set_defaults dk
export PROFILE

chdir=
CONFIG=
DM_SET_MACHINE=
USE_STACK=
FAKE=
NO_CACHE=
HOST=
WITH_REGISTRY_AUTH=1
update_apps_mode=ub
update_apps_devel=
update_apps_origin=
update_apps_branch=
args=(
    --help '$exit_with display_help'
    -d:,--chdir: chdir=
    -c:,--config: CONFIG=
    -p:,--profile: PROFILE=
    -P,--prod PROFILE=prod
    -T,--test PROFILE=test
    -m:,--set-machine: DM_SET_MACHINE=
    --stack USE_STACK=1
    -n,--fake FAKE=1
    -j,--no-cache NO_CACHE=1
    -h:,--host: HOST=
    -g,--ug,--no-update-apps update_apps_mode=b
    -u,--uu,--update-apps-only update_apps_mode=u
    -w,--uw,--update-apps-devel update_apps_devel=1
    --uo:,--update-apps-origin: update_apps_origin=
    --ub:,--update-apps-branch: update_apps_branch=
    -l,--without-registry-auth WITH_REGISTRY_AUTH=
)
parse_args "$@"; set -- "${args[@]}"

progexists docker-machine && DM_AVAILABLE=1 || DM_AVAILABLE=
if [ -n "$DM_SET_MACHINE" ]; then
    [ -n "$DM_AVAILABLE" ] || die "docker-machine n'est pas disponible"
    setx dm_env=docker-machine env "$DM_SET_MACHINE" || die
    eval "$dm_env"
fi
if [ -n "$DM_AVAILABLE" ]; then
    for dm_profile in "${DM_PROFILES[@]}"; do
        splitpair "$dm_profile" dm profile
        if [ "$dm" == "$DOCKER_MACHINE_NAME" ]; then
            DEFAULT_PROFILE="$profile"
            break
        fi
    done
fi

# construire par défaut
[ $# -eq 0 ] && set -- build
[ -n "$PROFILE" ] || PROFILE="$DEFAULT_PROFILE"

[ -n "$chdir" ] && { cd "$chdir" || die; }
update_apps_mode="${update_apps_mode}${update_apps_devel:+w}"

while [ $# -gt 0 ]; do
    [ "$1" == -- ] && { shift; continue; }
    cmd="$1"; shift
    case "$cmd" in
    b|build)
        build_set_options "$update_apps_mode" "$update_apps_origin"  "$update_apps_branch"
        [ -f .build.scripts.sh ] && source ./.build.scripts.sh
        [ -f build.scripts.sh ] && source ./build.scripts.sh
        args=()
        while [ $# -gt 0 -a "$1" != -- ]; do
            args+=("$1"); shift
        done
        enote "Profil $PROFILE"
        auto_build "${args[@]}" || die
        ;;
    p|push)
        [ -f .build.scripts.sh ] && source ./.build.scripts.sh
        [ -f build.scripts.sh ] && source ./build.scripts.sh
        args=()
        while [ $# -gt 0 -a "$1" != -- ]; do
            args+=("$1"); shift
        done
        enote "Profil $PROFILE"
        auto_push "${args[@]}" || die
        ;;
    s|start)
        args=()
        while [ $# -gt 0 -a "$1" != -- ]; do
            args+=("$1"); shift
        done
        enote "Profil $PROFILE"
        auto_up "${args[@]}" || die
        ;;
    k|stop)
        args=()
        while [ $# -gt 0 -a "$1" != -- ]; do
            args+=("$1"); shift
        done
        enote "Profil $PROFILE"
        auto_stop "${args[@]}" || die
        ;;
    1|up)
        args=()
        while [ $# -gt 0 -a "$1" != -- ]; do
            args+=("$1"); shift
        done
        enote "Profil $PROFILE"
        auto_up "${args[@]}" && auto_logs || die
        ;;
    l|logs)
        args=()
        while [ $# -gt 0 -a "$1" != -- ]; do
            args+=("$1"); shift
        done
        enote "Profil $PROFILE"
        auto_logs "${args[@]}" || die
        ;;
    0|down)
        args=()
        while [ $# -gt 0 -a "$1" != -- ]; do
            args+=("$1"); shift
        done
        enote "Profil $PROFILE"
        auto_down "${args[@]}" || die
        ;;
    r|run)
        args=()
        while [ $# -gt 0 -a "$1" != -- ]; do
            args+=("$1"); shift
        done
        enote "Profil $PROFILE"
        auto_run "${args[@]}" || die
        ;;
    x|exec)
        args=()
        while [ $# -gt 0 -a "$1" != -- ]; do
            args+=("$1"); shift
        done
        enote "Profil $PROFILE"
        auto_exec "${args[@]}" || die
        ;;
    d|brd)
        do_auto_down=1
        function auto_down_trap() {
            [ -n "$do_auto_down" ] && auto_down
        }
        trap auto_down_trap 1 3 15 EXIT

        build_set_options "$update_apps_mode" "$update_apps_origin"  "$update_apps_branch"
        [ -f .build.scripts.sh ] && source ./.build.scripts.sh
        [ -f build.scripts.sh ] && source ./build.scripts.sh
        args=()
        while [ $# -gt 0 -a "$1" != -- ]; do
            args+=("$1"); shift
        done
        enote "Profil $PROFILE"
        if auto_build; then
            auto_up "${args[@]}" && auto_logs || die
        else
            do_auto_down=
        fi
        ;;
    bs)
        build_set_options "$update_apps_mode" "$update_apps_origin"  "$update_apps_branch"
        [ -f .build.scripts.sh ] && source ./.build.scripts.sh
        [ -f build.scripts.sh ] && source ./build.scripts.sh
        USE_STACK=1
        args=()
        while [ $# -gt 0 -a "$1" != -- ]; do
            args+=("$1"); shift
        done
        enote "Profil $PROFILE"
        auto_build && auto_up "${args[@]}"
        ;;
    br)
        build_set_options "$update_apps_mode" "$update_apps_origin"  "$update_apps_branch"
        [ -f .build.scripts.sh ] && source ./.build.scripts.sh
        [ -f build.scripts.sh ] && source ./build.scripts.sh
        USE_STACK=1
        args=()
        while [ $# -gt 0 -a "$1" != -- ]; do
            args+=("$1"); shift
        done
        enote "Profil $PROFILE"
        auto_build && auto_run "${args[@]}"
        ;;
    y|deploy)
        USE_STACK=1
        args=()
        while [ $# -gt 0 -a "$1" != -- ]; do
            args+=("$1"); shift
        done
        enote "Profil $PROFILE"
        auto_deploy "${args[@]}" || die
        ;;
    by|bd)
        build_set_options "$update_apps_mode" "$update_apps_origin"  "$update_apps_branch"
        [ -f .build.scripts.sh ] && source ./.build.scripts.sh
        [ -f build.scripts.sh ] && source ./build.scripts.sh
        USE_STACK=1
        args=()
        while [ $# -gt 0 -a "$1" != -- ]; do
            args+=("$1"); shift
        done
        enote "Profil $PROFILE"
        auto_build && auto_deploy "${args[@]}"
        ;;
    bp)
        build_set_options "$update_apps_mode" "$update_apps_origin"  "$update_apps_branch"
        [ -f .build.scripts.sh ] && source ./.build.scripts.sh
        [ -f build.scripts.sh ] && source ./build.scripts.sh
        args=()
        while [ $# -gt 0 -a "$1" != -- ]; do
            args+=("$1"); shift
        done
        enote "Profil $PROFILE"
        auto_build && auto_push "${args[@]}"
        ;;
    bpy|bpd)
        build_set_options "$update_apps_mode" "$update_apps_origin"  "$update_apps_branch"
        [ -f .build.scripts.sh ] && source ./.build.scripts.sh
        [ -f build.scripts.sh ] && source ./build.scripts.sh
        args=()
        while [ $# -gt 0 -a "$1" != -- ]; do
            args+=("$1"); shift
        done
        enote "Profil $PROFILE"
        auto_build && auto_push && auto_deploy "${args[@]}"
        ;;
    service)
        args=()
        while [ $# -gt 0 -a "$1" != -- ]; do
            args+=("$1"); shift
        done
        enote "Profil $PROFILE"
        auto_service "${args[@]}" || die
        ;;
    u|update)
        args=()
        while [ $# -gt 0 -a "$1" != -- ]; do
            args+=("$1"); shift
        done
        enote "Profil $PROFILE"
        auto_service update "${args[@]}" || die
        ;;
    scale)
        args=()
        while [ $# -gt 0 -a "$1" != -- ]; do
            args+=("$1"); shift
        done
        enote "Profil $PROFILE"
        auto_service scale "${args[@]}" || die
        ;;
    ip|show-ip)
        args=()
        while [ $# -gt 0 -a "$1" != -- ]; do
            args+=("$1"); shift
        done
        enote "Profil $PROFILE"
        auto_show_ip "${args[@]}" || die
        ;;
    systemd-unit|systemd)
        args=()
        while [ $# -gt 0 -a "$1" != -- ]; do
            args+=("$1"); shift
        done
        enote "Profil $PROFILE"
        auto_systemd_unit "${args[@]}" || die
        ;;
    ps) docker container ps -a || die;;
    ls) docker image ls || die;;
    rm)
        args=()
        while [ $# -gt 0 -a "$1" != -- ]; do
            args+=("$1"); shift
        done
        docker image rm "${args[@]}" || die
        ;;
    X|prune)
        docker container prune -f || die
        docker image prune -f || die
        ;;
    *) die "$cmd: commande inconnue";;
    esac
done