#!/bin/bash # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 source "$(dirname "$0")/lib/ulib/ulib" || exit 1 urequire DEFAULTS ptools xmlsupport SELF="$script" ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## Aide function display_help() { uecho "$scriptname: déployer/exécuter une application à base de containers USAGE $scriptname [PROJDIR] [OPTIONS] [ENVVARS...] OPTIONS -m, --machine MACHINE Sélectionner la machine spécifiée pour les opérations docker. Cette option est incompatible avec --context -M, --context CONTEXT Sélectionner le contexte spécifié pour les opérations docker et kubernetes. Cette option est incompatible avec --machine -n, --no-build Ne pas reconstruire l'image avant de déployer/exécuter l'application -b, --build (Re)construire les images avant de déployer/exécuter l'application -c, --config CONFIG Lire un fichier de configuration au format dkbuild. Si cette option n'est pas spécifiée, les fichiers ~/.dkbuild.env et /etc/dkbuild.env sont testés dans l'ordre et automatiquement sélectionnés s'ils existent. -e, --env VAR=VALUE Spécifier la valeur d'une variable d'environnement. note: les arguments ENVVARS de la forme VAR=VALUE décrits dans la section USAGE permettent de spécifier des variables d'environnement comme avec cette option --arg ARG=VALUE Spécifier la valeur d'un argument de build. --no-cache Ne pas utiliser le cache lors du build -u, --pull-image Essayer de récupérer une version plus récente de l'image source -p, --push-image Pousser les images construites vers la registry --profile PROFILE -P, --prod -T, --test -E, --dtest --devel Spécifier le profil dans lequel construire l'image et/ou déployer/exécuter l'application --start -k, --stop -r, --restart Démarrer/déployer, Arrêter, ou Redémarrer/forcer un redéploiement de l'application " } ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## shared declare -A PROTECTED_VARS=( [PROTECTED_VARS]=1 [SELF]=1 [SHARED_LOCALS1]=1 [SHARED_ARGS1]=1 [SHARED_LOCALS2]=1 [SHARED_ARGS2]=1 [TFUNCTIONS]=1 [FFUNCTIONS]=1 [PROJDIR]=1 [DKBUILD]=1 [CONFIG]=1 [MACHINE]=1 [SETDISTS_DONE]=1 [SETDISTS]=1 [SETPROFILES_DONE]=1 [SETPROFILES]=1 [SETVERSION_DONE]=1 [SETVERSION]=1 [AUTOBUILD]=1 [DISTS]=1 [PROFILES]=1 [_ENVIRON]=1 [ENVIRON]=1 [ARGS]=1 [DEFAULTS]=1 ) SHARED_LOCALS1="local PROJDIR DKBUILD CONFIG" SHARED_ARGS1=( -j:,--projdir: PROJDIR= -c:,--config: CONFIG= ) SHARED_LOCALS2="local DIST PROFILE; local -a TMPENVIRON TMPARGS" SHARED_ARGS2=( -d:,--dist: DIST= -9,--d9 DIST=d9 -0,--d10 DIST=d10 -1,--d11 DIST=d11 --r7,--rhel7 DIST=rhel7 --r8,--rhel8 DIST=rhel8 --ol7,--oracle7 DIST=ol7 --ol8,--oracle8 DIST=ol8 -p:,--profile: PROFILE= -P,--prod PROFILE=prod -T,--test PROFILE=test -E,--dtest PROFILE=dtest --devel PROFILE=devel -e:,--env: '$TMPENVIRON+=("$value_")' --arg: '$TMPARGS+=("$value_")' ) TFUNCTIONS=( # dkbuild section note info debug setdists dist setprofiles profile setversion version setenv resetenv setarg resetarg default resetdefault checkout copy genfile dockerfile build cbuild # dockerfile FROM RUN CMD LABEL MAINTAINER EXPOSE ENV ADD COPY ENTRYPOINT VOLUME USER WORKDIR ARG ONBUILD STOPSIGNAL HEALTHCHECK SHELL ) FFUNCTIONS=( # dkbuild composer mvn run call dkbuild ) function set_machine() { local machine="$1" if [ "$machine" == -u ]; then # déselectionner la machine courante local -x DOCKER_TLS_VERIFY= DOCKER_HOST= DOCKER_CERT_PATH= DOCKER_MACHINE_NAME= machine= fi if [ -n "$machine" ]; then if [ -f ~/etc/default/dk ]; then machine="$( CLUSTERDIRS=() DM_ALIASES=() source ~/etc/default/dk for alias_machine in "${DM_ALIASES[@]}"; do if [ "${alias_machine%%:*}" == "$machine" ]; then echo "${alias_machine#*:}" exit fi done for clusterdir in "${CLUSTERDIRS[@]}"; do if [ -f "$clusterdir/0config/configure.conf" ]; then DM_ALIASES=() source "$clusterdir/0config/configure.conf" for alias_machine in "${DM_ALIASES[@]}"; do if [ "${alias_machine%%:*}" == "$machine" ]; then echo "${alias_machine#*:}" exit fi done fi done echo "$machine" )" fi eval "$(docker-machine env "$machine" || echo false)" || die else machine="$DOCKER_MACHINE_NAME" [ -n "$machine" ] || machine="${HOSTNAME%%.*}" fi MACHINE="$machine" } function get_project_name() { local project_name setx project_name=basename -- "$(pwd)" if [ "${project_name%.service}" != "$project_name" ]; then project_name="${project_name%.service}" elif [ "${project_name%.stack}" != "$project_name" ]; then project_name="${project_name%.stack}" elif [ "${project_name%.network}" != "$project_name" ]; then project_name="${project_name%.network}" fi echo "$project_name" } function get_container_name() { local container_name="${1//[^a-zA-Z0-9_-]/}" [ -n "$PROFILE" ] && container_name="${container_name}_$PROFILE" echo "$container_name" } function reset_functions() { local func for func in "${TFUNCTIONS[@]}"; do eval "function $func() { : echo \"$func \$*\"; return 0; }" done for func in "${FFUNCTIONS[@]}"; do eval "function $func() { : echo \"$func \$*\"; return 1; }" done function include() { edebug "include $(qvals "$@")" local file="$1" [ -d "$file" ] && file="$file/dkbuild" [ -f "$file" ] || die "$file: fichier introuvable" setx file=abspath "$file" cd "$(dirname "$file")" source "$file" } function machine() { local machine version for machine in "$@"; do [ "$machine" == "$MACHINE" ] && return done return 1 } } function _runcmd() { edebug "\$ $(qvals "$@")" "$@" } function ensure_projdir() { if [ -z "$PROJDIR" ]; then local found= if [ ! -f dkbuild ]; then # NB: on teste $PROJDIR != $scriptdir parce qu'il ne faut pas qu'on # prenne le présent script comme un script de build... PROJDIR="$(pwd)" if [ "${PROJDIR#$HOME/}" != "$PROJDIR" ]; then while [ "$PROJDIR" != "$HOME" ]; do if [ -f "$PROJDIR/dkbuild" -a "$PROJDIR" != "$scriptdir" ]; then found=1 break fi setx PROJDIR=dirname "$PROJDIR" done else while [ "$PROJDIR" != / ]; do if [ -f "$PROJDIR/dkbuild" -a "$PROJDIR" != "$scriptdir" ]; then found=1 break fi setx PROJDIR=dirname "$PROJDIR" done fi fi if [ -n "$found" ]; then enote "Sélection du répertoire de projet $(relpath "$PROJDIR")" else PROJDIR=. fi fi if [ -f "$PROJDIR" ]; then DKBUILD="$PROJDIR" setx PROJDIR=dirname "$PROJDIR" else DKBUILD="$PROJDIR/dkbuild" fi [ -d "$PROJDIR" ] || die "$PROJDIR: répertoire de projet introuvable" setx PROJDIR=abspath "$PROJDIR" setx DKBUILD=abspath "$DKBUILD" cd "$PROJDIR" || die [ -f "$DKBUILD" ] || die "$(ppath "$DKBUILD"): fichier de build introuvable" if [ "$CONFIG" == none ]; then edebug "no default config used" elif [ -n "$CONFIG" ]; then setx CONFIG=abspath "$CONFIG" edebug "using config $CONFIG" else local config for config in ~/.dkbuild.env /etc/dkbuild.env; do if [ -f "$config" ]; then CONFIG="$config" edebug "using default config $CONFIG" break fi done fi } function load_dkbuild() { local dkbuildenv="$PROJDIR/$(basename "$DKBUILD").env" cd "$PROJDIR" if [ -n "$CONFIG" ]; then edebug "loading $CONFIG" source "$CONFIG" fi if [ -f "$dkbuildenv" ]; then edebug "loading $dkbuildenv" source "$dkbuildenv" fi edebug "loading $DKBUILD" source "$DKBUILD" } function load_environ() { declare -g -A _ENVIRON eval "$(declare -p -x | sed -r 's/^declare -x ([^=]+)=/_ENVIRON[\1]=/')" } function from_glob() { local var=value value [[ "$1" != *=* ]] && { var="$1"; shift; } local path extract add_prefix add_suffix while [ $# -gt 0 ]; do case "$1" in path=*) path="${1#path=}";; extract=*) extract="${1#extract=}";; add-prefix=*) add_prefix="${1#add-prefix=}";; add-suffix=*) add_suffix="${1#add-suffix=}";; *=*) ewarn "path: $1: argument ignoré";; *) break;; esac shift done value="$(list_all . "$path" | sort -rn | head -1)" [ -n "$extract" ] || extract="${path//\*/(.*)}" if [ -n "$extract" ]; then extract="${extract//\//\\/}" value="$add_prefix$(awk -v version="$value" "BEGIN { if (match(version, /$extract/, vs)) { print vs[1] } else { print version } }")$add_suffix" fi local "$var"; upvar "$var" "$value" } function define_functions_env() { function setversion() { [ -n "$SETVERSION_DONE" ] && return # sans argument, retourner 0 [ $# -eq 0 ] && return local from_file from_repo from_glob extract add_prefix add_suffix while [ $# -gt 0 ]; do case "$1" in from-file|file) from_file=.;; from-file=*|file=*) from_file="${1#from-}"; from_file="${from_file#file=}" ;; from-repo|repo) from_repo=.;; from-repo=*|repo=*) from_repo="${1#from-}"; from_repo="${from_repo#repo=}" ;; from-glob=*|glob=*) from_glob="${1#from-}"; from_glob="${from_glob#glob=}" ;; extract=*) extract="${1#extract=}";; add-prefix=*) add_prefix="${1#add-prefix=}";; add-suffix=*) add_suffix="${1#add-suffix=}";; *=*) ewarn "setversion: $1: argument ignoré";; *) break;; esac shift done if [ -n "$from_file" ]; then if [ -d "$from_file" ]; then setx SETVERSION=pver --sw "$from_file" || die elif [[ "$from_file" == *.xml ]]; then setx SETVERSION=pver -E "$from_file" || die else setx SETVERSION=pver -F "$from_file" || die fi elif [ -n "$from_repo" ]; then die "setversion from-repo: pas encore implémenté" #XXX elif [ -n "$from_glob" ]; then SETVERSION="$(list_all . "$from_glob" | sort -rn | head -1)" [ -n "$extract" ] || extract="${from_glob//\*/(.*)}" else SETVERSION="$1" fi if [ -n "$extract" ]; then extract="${extract//\//\\/}" SETVERSION="$add_prefix$(awk -v version="$SETVERSION" "BEGIN { if (match(version, /$extract/, vs)) { print vs[1] } else { print version } }")$add_suffix" fi SETVERSION_DONE=1 } function dist() { local dist version latest for dist in "$@"; do if [ "$dist" == LATEST ]; then latest=1 continue fi parse_dist "$dist" dist version [ "$dist" == "$DIST" ] || continue [ -z "$version" -o "$version" == "$DVERSION" ] || continue return 0 done if [ -n "$latest" ]; then # trouver la dernière occurence de la première distribution # mentionnée. en effet, les versions doivent être ordonnées de la # plus ancienne à la plus récente. local first_dist last_version for dist in "${SETDISTS[@]}"; do parse_dist "$dist" dist version if [ -z "$first_dist" ]; then first_dist="$dist" last_version="$version" elif [ "$dist" == "$first_dist" ]; then last_version="$version" fi done if [ "$first_dist" == "$DIST" ]; then if [ -z "$last_version" -o "$last_version" == "$DVERSION" ]; then return 0 fi fi fi return 1 } function version() { local version for version in "$@"; do [ "$version" == "$VERSION" ] && return 0 done return 1 } function profile() { local profile version for profile in "$@"; do [ "$profile" == DEFAULT ] && profile="${SETPROFILES[0]}" parse_profile "$profile" profile version [ "$profile" == "$PROFILE" ] || continue [ -z "$version" -o "$version" == "$PVERSION" ] || continue return 0 done return 1 } declare -g -A ENVIRON function setenv() { local name value for name in "$@"; do if [[ "$name" == *=* ]]; then value="${name#*=}" name="${name%%=*}" else value="${_ENVIRON[$name]-__UNDEFINED__}" [ "$value" == __UNDEFINED__ ] && die "la variable d'environnement $name doit être définie" fi if [ "${ENVIRON[$name]-__UNDEFINED__}" == __UNDEFINED__ ]; then # Ne spécifier la valeur que si elle n'a pas déjà été définie _ENVIRON["$name"]="$value" ENVIRON["$name"]="$value" [ -z "${PROTECTED_VARS[$name]}" ] && _setv "export $name" "$value" fi done } function resetenv() { local name value for name in "$@"; do if [[ "$name" == *=* ]]; then value="${name#*=}" name="${name%%=*}" else value="${_ENVIRON[$name]-__UNDEFINED__}" [ "$value" == __UNDEFINED__ ] && die "la variable d'environnement $name doit être définie" fi _ENVIRON["$name"]="$value" ENVIRON["$name"]="$value" [ -z "${PROTECTED_VARS[$name]}" ] && _setv "export $name" "$value" done } declare -g -A ARGS function setarg() { local name value for name in "$@"; do if [[ "$name" == *=* ]]; then value="${name#*=}" name="${name%%=*}" else value="${_ENVIRON[$name]-__UNDEFINED__}" [ "$value" == __UNDEFINED__ ] && die "la variable d'environnement $name doit être définie" fi if [ "${ARGS[$name]-__UNDEFINED__}" == __UNDEFINED__ ]; then # Ne spécifier la valeur que si elle n'a pas déjà été définie ARGS["$name"]="$value" fi done } function resetarg() { local name value for name in "$@"; do if [[ "$name" == *=* ]]; then value="${name#*=}" name="${name%%=*}" else value="${_ENVIRON[$name]-__UNDEFINED__}" [ "$value" == __UNDEFINED__ ] && die "la variable d'environnement $name doit être définie" fi ARGS["$name"]="$value" done } declare -g -A DEFAULTS function default() { local command="$1"; shift local name value for name in "$@"; do if [[ "$name" == *=* ]]; then value="${name#*=}" name="${name%%=*}" else value=1 fi name="${command}_$name" if [ "${DEFAULTS[$name]-__UNDEFINED__}" == __UNDEFINED__ ]; then # Ne spécifier la valeur que si elle n'a pas déjà été définie DEFAULTS["$name"]="$value" fi done } function resetdefault() { local command="$1"; shift local name value for name in "$@"; do if [[ "$name" == *=* ]]; then value="${name#*=}" name="${name%%=*}" else value=1 fi name="${command}_$name" DEFAULTS["$name"]="$value" done } } function parse_dist() { local dist="$1" version if [[ "$dist" == *-* ]]; then version="${dist%-*}" dist="${dist##*-}" fi local "${2:-dist}"; upvar "${2:-dist}" "$dist" local "${3:-version}"; upvar "${3:-version}" "$version" } function parse_profile() { local profile="$1" version if [[ "$profile" == *-* ]]; then version="${profile%-*}" profile="${profile##*-}" fi local "${2:-profile}"; upvar "${2:-profile}" "$profile" local "${3:-version}"; upvar "${3:-version}" "$version" } function resolve_dists_profiles() { ## construire d'abord la liste des distributions et profils edebug "Calcul de la liste des distributions et des profils" reset_functions SETDISTS_DONE= SETDISTS=() SETPROFILES_DONE= SETPROFILES=() SETVERSION_DONE= SETVERSION= AUTOBUILD=1 function setdists() { [ -n "$SETDISTS_DONE" ] && return SETDISTS=("$@") SETDISTS_DONE=1 } function setprofiles() { [ -n "$SETPROFILES_DONE" ] && return SETPROFILES=("$@") SETPROFILES_DONE=1 } function build() { AUTOBUILD= } function cbuild() { AUTOBUILD= } load_dkbuild ## ensuite vérifier si on est dans la bonne distribution edebug "Calcul de la distribution courante" reset_functions DISTS=() function setdists() { local dist version found # construire la liste des distributions à considérer if [ -n "$DIST" ]; then # on a spécifié une distribution en argument for dist in "${SETDISTS[@]}"; do if [ "$dist" == "$DIST" ]; then # matcher avec la version éventuellement found=1 break fi parse_dist "$dist" if [ "$dist" == "$DIST" ]; then # ou matcher uniquement la distribution found=1 break fi done # si aucune distribution ne correspond, arrêter le script [ -n "$found" ] || exit 0 # forcer à ne construire que cette distribution DISTS=("$DIST") else DISTS=("${SETDISTS[@]}") fi } load_dkbuild ## puis vérifier si on est dans le bon profil edebug "Calcul du profil courant" reset_functions PROFILES=() function setprofiles() { local profile version found # construire la liste des distributions à considérer if [ -n "$PROFILE" ]; then # on a spécifié une distribution en argument for profile in "${SETPROFILES[@]}"; do if [ "$profile" == "$PROFILE" ]; then # matcher avec la version éventuellement found=1 break fi parse_profile "$profile" if [ "$profile" == "$PROFILE" ]; then # ou matcher uniquement la distribution found=1 break fi done # si aucune distribution ne correspond, arrêter le script [ -n "$found" ] || die "$PROFILE: profil invalide" # forcer à ne construire que cette distribution PROFILES=("$PROFILE") else PROFILES=("${SETPROFILES[@]}") fi } load_dkbuild ## Si pas de distribution ou de profil, remplacer par valeur vide if [ ${#DISTS[*]} -eq 0 ]; then SETDISTS=("") DISTS=("") fi if [ ${#PROFILES[*]} -eq 0 ]; then SETPROFILES=("") PROFILES=("") fi ## puis calculer la version par défaut edebug "Calcul de la version par défaut" reset_functions define_functions_env load_dkbuild } function foreach_dists_profiles() { local each="$1" before="$2" after="$3" local version dist dversion profile pversion local VERSION DIST DVERSION PROFILE PVERSION local HAVE_VERSION LAST_VERSION declare -A dones if [ -n "$before" ]; then "$before" fi for dist in "${DISTS[@]}"; do parse_dist "$dist" dist dversion # y a-t-il une version dans cette distribution ou ce profil, et si oui, laquelle? HAVE_VERSION= LAST_VERSION= for DIST in "${SETDISTS[@]}"; do parse_dist "$DIST" DIST DVERSION [ "$DIST" == "$dist" ] || continue VERSION="$DVERSION" for profile in "${PROFILES[@]}"; do parse_profile "$profile" profile pversion for PROFILE in "${SETPROFILES[@]}"; do parse_profile "$PROFILE" PROFILE PVERSION [ "$PROFILE" == "$profile" ] || continue [ -n "$DVERSION" ] && PVERSION= || VERSION="$PVERSION" [ -z "$VERSION" -a -n "$SETVERSION" ] && VERSION="$SETVERSION" if [ -n "$VERSION" ]; then HAVE_VERSION=1 LAST_VERSION="$VERSION" fi done done done for DIST in "${SETDISTS[@]}"; do parse_dist "$DIST" DIST DVERSION [ "$DIST" == "$dist" ] || continue [ -z "$dversion" -o "$DVERSION" == "$dversion" ] || continue VERSION="$DVERSION" for profile in "${PROFILES[@]}"; do parse_profile "$profile" profile pversion for PROFILE in "${SETPROFILES[@]}"; do parse_profile "$PROFILE" PROFILE PVERSION [ "$PROFILE" == "$profile" ] || continue if [ -z "$DVERSION" ]; then [ -z "$pversion" -o "$PVERSION" == "$pversion" ] || continue VERSION="$PVERSION" else PVERSION= fi [ -n "${dones[$PVERSION-$PROFILE-$DVERSION-$DIST]}" ] && continue dones["$PVERSION-$PROFILE-$DVERSION-$DIST"]=1 [ -z "$VERSION" -a -n "$SETVERSION" ] && VERSION="$SETVERSION" "$each" done done done done if [ -n "$after" ]; then "$after" fi } function define_functions_cmd() { _IN_SECTION= function section() { [ -n "$_IN_SECTION" ] && eend etitle "$*" _IN_SECTION=1 } function note() { enote "$*" } function info() { estep "$*" } function debug() { edebug "$*" } function checkout() { edebug "checkout $(qvals "$@")" local url destdir [[ "$1" != *=* ]] && { url="$1"; shift; } [[ "$1" != *=* ]] && { destdir="$1"; shift; } local checkout="${DEFAULTS[checkout_checkout]-1}" local origin="${DEFAULTS[checkout_origin]}" local branch="${DEFAULTS[checkout_branch]}" local develdir="${DEFAULTS[checkout_develdir]}" local develtype="${DEFAULTS[checkout_develtype]}" while [ $# -gt 0 ]; do case "$1" in checkout) checkout=1;; checkout=*) checkout="${1#checkout=}";; origin=*) origin="${1#origin=}";; branch=*) branch="${1#branch=}";; develdir=*) develdir="${1#develdir=}";; develtype=*) develtype="${1#develtype=}";; *) ewarn "checkout: $1: argument ignoré";; esac shift done [ -n "$checkout" ] || return [ -n "$url" -a -n "$destdir" ] || die "checkout: Vous devez spécifier l'url du dépôt et la destination" [ -n "$origin" ] || origin=origin if [ -z "$branch" ]; then case "$PROFILE" in test|devel) branch=develop;; *) branch=master;; esac fi if [ "$checkout" == devel ]; then # synchronisation depuis le répertoire de développement [ -n "$develdir" ] || die "checkout: vous devez spécifier le répertoire de développement" [ -d "$develdir" ] || die "checkout: répertoire de développement introuvable" die "Pas encore implémenté" #XXX elif [ -d "$destdir" -a -d "$destdir/.git" ]; then # maj du dépôt local cwd="$(pwd)" estep "checkout: maj du dépôt $url --> $destdir (origin=$origin, branch=$branch)" cd "$destdir" git fetch --all -p -f || die if [ "${branch#^}" != "$branch" ]; then git reset --hard "${branch#^}" || die else git reset --hard "$origin/$branch" || die fi cd "$cwd" else # reliquat checkout=devel? [ -d "$destdir" ] && rm -rf "$destdir" # clone estep "checkout: clone du dépôt $url --> $destdir (origin=$origin, branch=$branch)" if [ "${BRANCH#^}" != "$BRANCH" ]; then local cwd="$(pwd)" git clone -o "$origin" "$url" "$destdir" || die cd "$destdir" git reset --hard "${branch#^}" || die cd "$cwd" else git clone -o "$origin" -b "$branch" "$url" "$destdir" || die fi fi } function copy() { edebug "copy $(qvals "$@")" local src dest [[ "$1" != *=* ]] && { src="$1"; shift; } [[ "$1" != *=* ]] && { dest="$1"; shift; } local copy="${DEFAULTS[copy_copy]-1}" local overwrite="${DEFAULTS[copy_overwrite]}" local gitignore="${DEFAULTS[copy_gitignore]}" while [ $# -gt 0 ]; do case "$1" in copy) copy=1;; copy=*) copy="${1#copy=}";; overwrite) overwrite=1;; overwrite=*) overwrite="${1#overwrite=}";; gitignore=*) gitignore="${1#gitignore=}";; *) ewarn "copy: $1: argument ignoré";; esac shift done [ -n "$copy" ] || return [ -n "$src" -a -n "$dest" ] || die "copy: Vous devez spécifier la source et la destination de la copie" [ -e "$src" ] || { ewarn "copy: $src: fichier ou répertoire introuvables" return 1 } local srcdir destdir if [ "${src%/}" != "$src" ]; then [ -d "$src" ] || die "copy: $src: doit être un répertoire" setx srcdir=abspath "$src" src= elif [ -d "$src" ]; then setx srcdir=abspath "$src" src= else setx src=abspath "$src" fi if [ "${dest%/}" != "$dest" ]; then [ -f "$dest" ] && die "copy: $dest: doit être un répertoire" setx destdir=abspath "$dest" dest= elif [ -d "$dest" ]; then setx destdir=abspath "$dest" dest= elif [ -f "$dest" ]; then [ -n "$srcdir" ] && die "copy: $dest: doit être un répertoire" setx dest=abspath "$dest" elif [ -n "$srcdir" ]; then setx destdir=abspath "$dest" dest= else setx dest=abspath "$dest" fi local -a srcs dests if [ -n "$srcdir" -a -n "$destdir" ]; then # copie de répertoire à répertoire local destpath="$(relpath "$destdir" "$PROJDIR")" [ -n "$destpath" ] || destpath=. estep "copy $(relpath "$srcdir" "$PROJDIR")/ --> $destpath/" array_from_lines srcs "$(find "$srcdir/" -type f -o -type l)" for src in "${srcs[@]}"; do dest="$destdir/${src#$srcdir/}" if [ -n "$overwrite" -o ! -f "$dest" ]; then mkdirof "$dest" || die cp -dfl "$src" "$dest" || die dests+=("$dest") fi done elif [ -n "$src" ]; then # transformer copie de fichier à répertoire en copie de fichier à fichier [ -n "$dest" ] || dest="$destdir/$(basename "$src")" if [ -n "$overwrite" -o ! -f "$dest" ]; then # copie de fichier à fichier estep "copy $(relpath "$src" "$PROJDIR") --> $(relpath "$dest" "$PROJDIR")" mkdirof "$dest" || die cp -fl "$src" "$dest" || die setx destdir=dirname "$dest" dests+=("$dest") fi else # en réalité, on ne devrait jamais arriver ici die "copy: impossible de copier un répertoire dans un fichier" fi if [ -n "$gitignore" ]; then setx gitignore=abspath "$gitignore" [ -d "$gitignore" ] && gitignore="$gitignore/.gitignore" local basedir setx basedir=dirname "$gitignore" if [ "${destdir#$basedir/}" == "$destdir" -a "$destdir" != "$basedir" ]; then ewarn "copy: gitignore ignoré parce que le répertoire n'est pas un parent de destdir" else [ -f "$gitignore" ] || { mkdir -p "$basedir"; touch "$gitignore"; } declare -A ignored_dirs local ignored_dir for dest in "${dests[@]}"; do dest="/${dest#$basedir/}" if grep -q "^$dest\$" "$gitignore"; then ignored=1 else ignored= setx ignored_dir=dirname "$dest" while [ "$ignored_dir" != / ]; do ignored="${ignored_dirs[$ignored_dir/]-compute}" if [ "$ignored" == compute ]; then grep -q "^$ignored_dir/\$" "$gitignore" && ignored=1 || ignored= ignored_dirs["$ignored_dir/"]="$ignored" fi if [ -n "$ignored" ]; then # un répertoire parent est déjà ignoré, on peut # passer au fichier suivant break fi setx ignored_dir=dirname "$ignored_dir" done fi if [ -z "$ignored" ]; then # le fichier n'est pas ignoré, ni directement, ni via un # répertoire parent. il faut donc l'ajouter à .gitignore echo "$dest" >>"$gitignore" fi done fi fi } function genfile() { edebug "genfile $(qvals "$@")" local output input [[ "$1" != *=* ]] && { output="$1"; shift; } [[ "$1" != *=* ]] && { input="$1"; shift; } local context="${DEFAULTS[genfile_context]}" local sed="${DEFAULTS[genfile_sed]}" while [ $# -gt 0 ]; do case "$1" in context=*) context="${1#context=}";; sed=*) sed="${1#sed=}";; *) ewarn "genfile: $1: argument ignoré";; esac shift done [ -n "$output" ] || die "genfile: Vous devez spécifier le fichier en sortie" if [ -n "$context" ]; then mkdir -p "$context" || die output="$context/$output" fi if [ -n "$input" ]; then cat "$input" >"$output" || die elif ! tty -s; then cat >"$output" else die "genfile: Vous devez spécifier une source pour le fichier $output" fi if [ -n "$sed" ]; then sed -i "$sed" "$output" fi } function dockerfile() { edebug "dockerfile $(qvals "$@")" local input [[ "$1" != *=* ]] && { DOCKERFILE="$1"; shift; } [[ "$1" != *=* ]] && { input="$1"; shift; } local context="${DEFAULTS[dockerfile_context]}" local sed="${DEFAULTS[dockerfile_sed]}" while [ $# -gt 0 ]; do case "$1" in context=*) context="${1#context=}";; sed=*) sed="${1#sed=}";; *) ewarn "dockerfile: $1: argument ignoré";; esac shift done [ -n "$DOCKERFILE" ] || DOCKERFILE=Dockerfile DOCKERCONTEXT=. if [ -n "$context" ]; then mkdir -p "$context" || die DOCKERCONTEXT="$context" DOCKERFILE="$context/$DOCKERFILE" fi setx DOCKERFILE=abspath "$DOCKERFILE" if [ -n "$input" ]; then cat "$input" >"$DOCKERFILE" || die elif ! tty -s; then cat >"$DOCKERFILE" || die else echo "# -*- coding: utf-8 mode: dockerfile -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8" >"$DOCKERFILE" fi if [ -n "$sed" ]; then sed -i "$sed" "$DOCKERFILE" fi } function add2dockerfile() { edebug "$(qvals "$@")" [ -n "$DOCKERFILE" ] || return echo "$*" >>"$DOCKERFILE" } function FROM() { add2dockerfile FROM "$@"; } function RUN() { add2dockerfile RUN "$@"; } function CMD() { add2dockerfile CMD "$@"; } function LABEL() { add2dockerfile LABEL "$@"; } function MAINTAINER() { add2dockerfile MAINTAINER "$@"; } function EXPOSE() { add2dockerfile EXPOSE "$@"; } function ENV() { add2dockerfile ENV "$@"; } function ADD() { add2dockerfile ADD "$@"; } function COPY() { add2dockerfile COPY "$@"; } function ENTRYPOINT() { add2dockerfile ENTRYPOINT "$@"; } function VOLUME() { add2dockerfile VOLUME "$@"; } function USER() { add2dockerfile USER "$@"; } function WORKDIR() { add2dockerfile WORKDIR "$@"; } function ARG() { add2dockerfile ARG "$@"; } function ONBUILD() { add2dockerfile ONBUILD "$@"; } function STOPSIGNAL() { add2dockerfile STOPSIGNAL "$@"; } function HEALTHCHECK() { add2dockerfile HEALTHCHECK "$@"; } function SHELL() { add2dockerfile SHELL "$@"; } function build() { edebug "build $(qvals "$@")" local build="${DEFAULTS[build_build]-1}" local no_cache="${DEFAULTS[build_no-cache]}" local pull="${DEFAULTS[build_pull]}" local host_mappings="${DEFAULTS[build_host-mappings]-__UNDEFINED__}" [ "$host_mappings" == __UNDEFINED__ ] && host_mappings="${DEFAULTS[docker_host-mappings]}" local set_tags="${DEFAULTS[build_set-tags]}" local add_tags="${DEFAULTS[build_add-tags]}" local images="${DEFAULTS[build_images]}" local push="${DEFAULTS[build_push]}" while [ $# -gt 0 ]; do case "$1" in build) build=1;; build=*) build="${1#build=}";; context=*) DOCKERCONTEXT="${1#context=}";; dockerfile=*) DOCKERFILE="${1#dockerfile=}";; no-cache) no_cache=1;; no-cache=*) no_cache="${1#no-cache=}";; pull) pull=1;; pull=*) pull="${1#pull=}";; host-mappings=*) host_mappings="${1#host-mappings=}";; set-tag=*) set_tags="${1#set-tag=}";; set-tags=*) set_tags="${1#set-tags=}";; add-tag=*) add_tags="${1#add-tag=}";; add-tags=*) add_tags="${1#add-tags=}";; image=*) images="${1#image=}";; images=*) images="${1#images=}";; push) push=1;; push=*) push="${1#push=}";; *) ewarn "build: $1: argument ignoré";; esac shift done estep "build options:" ${build:+build} ${no_cache:+no-cache} ${pull:+pull} ${push:+push} [ -n "$images" ] || images="$IMAGE" eval "set_tags=($set_tags)" eval "add_tags=($add_tags)" eval "images=($images)" local tag imagetag autotag=1 local -a imagetags if [ ${#set_tags[*]} -gt 0 ]; then autotag= for imagetag in "${images[@]}"; do if [[ "$imagetag" == *:* ]]; then # le tag est déjà spécifié imagetags+=("$imagetag") else for tag in "${set_tags[@]}" "${add_tags[@]}"; do imagetags+=("$imagetag:$tag") done fi done else for imagetag in "${images[@]}"; do if [[ "$imagetag" == *:* ]]; then # le tag est déjà spécifié autotag= imagetags+=("$imagetag") else for tag in "${add_tags[@]}"; do imagetags+=("$imagetag:$tag") done [ -n "$VERSION" ] && imagetags+=("$imagetag:$VERSION-$DIST") [ -n "$DIST" -a -z "$HAVE_VERSION" ] && imagetags+=("$imagetag:$DIST") fi done fi if [ -n "$autotag" ]; then if [ -n "$DIST" ]; then if [ -z "$HAVE_VERSION" ]; then dist LATEST && imagetags+=("$imagetag:latest") elif [ "$VERSION" == "$LAST_VERSION" ]; then imagetags+=("$imagetag:$DIST") dist LATEST && imagetags+=("$imagetag:latest") fi elif [ -n "$PROFILE" ]; then profile DEFAULT && imagetags+=("$imagetag:latest") else imagetags+=("$imagetag:latest") fi fi local avar local -a args; args=( ${no_cache:+--no-cache} ${pull:+--pull} ) eval "host_mappings=($host_mappings)" for host_mapping in "${host_mappings[@]}"; do args+=(--add-host "$host_mapping") done for avar in "${!ARGS[@]}"; do args+=(--build-arg "$avar=${ARGS[$avar]}") done for imagetag in "${imagetags[@]}"; do args+=(-t "$imagetag") estep "tag $imagetag" done [ -n "$DOCKERCONTEXT" ] || DOCKERCONTEXT="${DEFAULTS[build_context]:-.}" [ -n "$DOCKERFILE" ] || DOCKERFILE="${DEFAULTS[build_dockerfile]:-Dockerfile}" if [ -n "$build" ]; then etitle build _runcmd docker build "${args[@]}" -f "$DOCKERFILE" "$DOCKERCONTEXT" || die eend fi if [ -n "$push" ]; then etitle push for imagetag in "${imagetags[@]}"; do _runcmd docker push "$imagetag" || die done eend fi DOCKERCONTEXT= DOCKERFILE= [ -n "$build" -o -n "$push" ] } function cbuild() { edebug "cbuild $(qvals "$@")" local files="${DEFAULTS[cbuild_files]}" local project_name="${DEFAULTS[cbuild_project-name]}" local no_cache="${DEFAULTS[cbuild_no-cache]}" local pull="${DEFAULTS[cbuild_pull]}" while [ $# -gt 0 ]; do case "$1" in files=*) files="${1#files=}";; project-name=*) project_name="${1#project-name=}";; no-cache) no_cache=1;; no-cache=*) no_cache="${1#no-cache=}";; pull) pull=1;; pull=*) pull="${1#pull=}";; *=*) ewarn "cbuild: $1: argument ignoré";; *) break;; esac shift done if [ -n "$files" ]; then eval "files=($files)" else files=(docker-compose.yml) if [ -f "docker-compose.override.yml" ]; then files+=("docker-compose.override.yml") fi if [ -n "$PROFILE" -a -f "docker-compose.$PROFILE.yml" ]; then files+=("docker-compose.$PROFILE.yml") fi fi [ -n "$project_name" ] || setx project_name=get_project_name estep "cbuild files:" ${files[@]} estep "cbuild options:" project_name="$project_name" ${no_cache:+no-cache} ${pull:+pull} local file; local -a args args=( -p "$project_name" ) for file in "${files[@]}"; do args+=(-f "$file") done local avar evar; local -a bargs bargs=( ${no_cache:+--no-cache} ${pull:+--pull} ) for avar in "${!ARGS[@]}"; do bargs+=(--build-arg "$avar=${ARGS[$avar]}") done if [ -f .shared_env -o -f ".${MACHINE}_env" -o ${#ENVIRON[*]} -gt 0 ]; then echo >.env "## fichier auto-généré. ne pas modifier ##" fi [ -f .shared_env ] && cat .shared_env >>.env [ -f ".${MACHINE}_env" ] && cat ".${MACHINE}_env" >>.env for evar in "${!ENVIRON[@]}"; do echo_setv "$evar=${ENVIRON[$evar]}" >>.env done _runcmd docker-compose "${args[@]}" build "${bargs[@]}" "$@" || die } function _local_composer() { case "$action" in rootshell|rshell|rootbash|rbash) shift estep "Lancement d'un shell root" sudo bash "$@" return $? ;; usershell|shell|userbash|bash) shift estep "Lancement d'un shell utilisateur" bash "$@" return $? ;; *) estep "composer $action" if [ -n "$composer" ]; then : elif [ -x composer.phar ]; then composer=./composer.phar elif [ -x /usr/bin/composer ]; then composer=/usr/bin/composer else die "Impossible de trouver composer" fi "$composer" "$action" $args "$@" esac } function _docker_composer() { local user group projdir actualcmd setx user=id -un; setx user=getent passwd "$user" setx group=id -gn; setx group=getent group "$group" setx projdir=pwd case "$action" in rootshell|rshell|rootbash|rbash) action=rshell shift actualcmd='eval "bash $args"' ;; usershell|shell|userbash|bash) action=shell shift actualcmd='eval "su-exec \"$user\" bash $args"' ;; *) actualcmd='eval "su-exec \"$user\" \"$composer\" $args"' args="$action${args:+ $args}" ;; esac setx args=qvals $args "$@" local -a basecmd setupscript runscript cmd basecmd=( -e user="$user" -e group="$group" -e projdir="$projdir" -e setup="$setup" -e composer="$composer" -e args="$args" ) eval "host_mappings=($host_mappings)" for host_mapping in "${host_mappings[@]}"; do basecmd+=(--add-host "$host_mapping") done basecmd+=(-v "$HOME:$HOME") if [ "${projdir#$HOME/}" == "$projdir" ]; then # si le répertoire de projet ne se trouve pas dans $HOME, le monter aussi cmd+=(-v "$projdir:$projdir") fi setupscript='eval "$setup"' runscript=' echo "$user" >>/etc/passwd; user="${user%%:*}" echo "$group" >>/etc/group; group="${group%%:*}" cd "$projdir" if [ -n "$composer" ]; then : elif [ -x composer.phar ]; then composer=./composer.phar elif [ -x /usr/bin/composer ]; then composer=/usr/bin/composer else echo "ERROR: Impossible de trouver composer" exit 1 fi '"$actualcmd" if [ -n "$setup" ]; then local project_name container_name ctid # lancement dans un container docker à préparer [ -n "$project_name" ] || setx project_name=get_project_name setx container_name=get_container_name "$project_name" container_name="dkbuild_composer_${container_name}" # vérifier l'existence de l'image setx ctid=docker image ls --format '{{.ID}}' "${container_name}_image" # créer le container le cas échéant if [ -z "$ctid" ]; then estep "Création du container $container_name à partir de l'image $image" cmd=( docker create -it --name "${container_name}_ct" "${basecmd[@]}" "$image" bash -c "$setupscript" ) setx ctid="${cmd[@]}" && docker container start -ai "$ctid" && docker container commit "$ctid" "${container_name}_image" && docker container rm "$ctid" || die fi # prendre comme image le container créé image="${container_name}_image" fi case "$action" in rshell) estep "Lancement d'un shell root (avec l'image $image)";; shell) estep "Lancement d'un shell utilisateur (avec l'image $image)";; *) estep "composer $action (avec l'image $image)";; esac cmd=( docker run -it --rm "${basecmd[@]}" "$image" bash -c "$runscript" ) "${cmd[@]}" } function composer() { edebug "composer $(qvals "$@")" [ $# -eq 0 ] && return 0 local action destdir [[ "$1" != *=* ]] && { destdir="$1"; shift; } [[ "$1" != *=* ]] && { action="$1"; shift; } [ -n "$destdir" ] || destdir=. [ -d "$destdir" ] || die "composer: $destdir: répertoire introuvable" local cwd="$(pwd)" cd "$destdir" || die [ -n "$action" ] || action=install [ "$action" == none ] && return local args case "$PROFILE" in prod|test) args="${DEFAULTS[composer_args]---no-dev -o}";; *) args="${DEFAULTS[composer_args]}";; esac local php="${DEFAULTS[composer_php]}" local php_max="${DEFAULTS[composer_php-max]}" local image="${DEFAULTS[composer_image]}" local machine="${DEFAULTS[composer_machine]}" local host_mappings="${DEFAULTS[composer_host-mappings]-__UNDEFINED__}" [ "$host_mappings" == __UNDEFINED__ ] && host_mappings="${DEFAULTS[docker_host-mappings]}" local composer="${DEFAULTS[composer_composer]}" local setup="${DEFAULTS[composer_setup]}" local project_name="${DEFAULTS[composer_project-name]}" if [ -f "$destdir/.composer.conf" ]; then eval "$( COMPOSER_PHP= COMPOSER_PHP_MAX= COMPOSER_IMAGE="$COMPOSER_IMAGE" COMPOSER_MACHINE=-u COMPOSER_CMD= COMPOSER_SETUP= source "$destdir/.composer.conf" [ -z "$php" ] && echo_setv php="$COMPOSER_PHP" [ -z "$php_max" ] && echo_setv php_max="$COMPOSER_PHP_MAX" [ -z "$image" ] && echo_setv image="$COMPOSER_IMAGE" [ -z "$machine" ] && echo_setv machine="$COMPOSER_MACHINE" [ -z "$composer" ] && echo_setv composer="$COMPOSER_CMD" [ -z "$setup" ] && echo_setv setup="$COMPOSER_SETUP" )" fi while [ $# -gt 0 ]; do case "$1" in args=*) args="${1#args=}";; php=*) php="${1#php=}";; php-max=*) php_max="${1#php-max=}";; image=*) image="${1#image=}";; machine=*) machine="${1#machine=}";; host-mappings=*) host_mappings="${1#host-mappings=}";; composer=*) composer="${1#composer=}";; setup=*) setup="${1#setup=}";; project-name=*) project_name="${1#project-name=}";; *=*) ewarn "composer: $1: argument ignoré";; *) break;; esac shift done local use_image if [ "$php" == force -o "$php" == any ]; then use_image=1 elif [ "$php" == none -o "$php" == system ]; then php=none use_image= elif [ -n "$php_max" -a "$php_max" != none ]; then # Vérifier la version de PHP php -r ' $version = $argv[1]; if (strpos($version, ".") !== false) { $version = explode(".", $version); $version = $version[0] * 10000 + $version[1] * 100 + (isset($version[2])? $version[2]: 0); } exit((PHP_VERSION_ID > $version)? 0: 1); ' -- "$php_max" case $? in 0) use_image=1;; 1) use_image=;; *) ewarn "Erreur lors du lancement de PHP: est-il installé? Sinon, utilisez php=any";; esac fi if [ -n "$use_image" -o "$php" == none ]; then : # ok, on a déjà décidé elif [ -z "$php" ]; then # pas de version minimum, tester simplement la valeur de image [ "$image" != none ] && use_image=1 else # Vérifier la version de PHP php -r ' $version = $argv[1]; if (strpos($version, ".") !== false) { $version = explode(".", $version); $version = $version[0] * 10000 + $version[1] * 100 + (isset($version[2])? $version[2]: 0); } exit((PHP_VERSION_ID < $version)? 0: 1); ' -- "$php" case $? in 0) use_image=1;; 1) use_image=;; *) ewarn "Erreur lors du lancement de PHP: est-il installé? Sinon, utilisez php=any";; esac fi if [ -n "$use_image" ]; then local orig_machine [ "$image" != none ] || die "Vous devez spécifier l'image à utiliser pour composer" if [ -n "$machine" -a "$machine" != current -a "$DOCKER_MACHINE_NAME" != "$machine" ]; then orig_machine="$DOCKER_MACHINE_NAME" set_machine "$machine" fi _docker_composer "$@" if [ -n "$_orig_machine" ]; then set_machine "$orig_machine" fi else _local_composer "$@" fi # restaurer le répertoire courant cd "$cwd" } function _local_mvn() { if [ -n "$java" ]; then urequire java select_java_exact "$java" || die export MVN_JAVA_VERSION="$java" fi case "$action" in rootshell|rshell|rootbash|rbash) shift estep "Lancement d'un shell root" sudo bash "$@" return $? ;; usershell|shell|userbash|bash) shift estep "Lancement d'un shell utilisateur" bash "$@" return $? ;; java) shift estep "java" java "$@" ;; *) estep "mvn $action" [ -n "$mvn" ] || setx mvn=which mvn 2>/dev/null [ -n "$mvn" ] || die "mvn: commande introuvable" set -- "$action" $args "$@" case "$1" in install) set clean package install "${@:2}";; package) set clean package "${@:2}";; package_only) set package "${@:2}";; esac "$mvn" "$@" esac } function _docker_mvn() { local user group projdir actualcmd setx user=id -un; setx user=getent passwd "$user" setx group=id -gn; setx group=getent group "$group" setx projdir=pwd case "$action" in rootshell|rshell|rootbash|rbash) action=rshell shift actualcmd='eval "bash $args"' ;; usershell|shell|userbash|bash) action=shell shift actualcmd='eval "su-exec \"$user\" bash $args"' ;; java) shift actualcmd='eval "su-exec \"$user\" java $args"' ;; *) actualcmd='eval "su-exec \"$user\" \"$mvn\" $args"' set -- "$action" $args "$@" case "$1" in install) set clean package install "${@:2}";; package) set clean package "${@:2}";; package_only) set package "${@:2}";; esac args= ;; esac setx args=qvals $args "$@" local -a basecmd setupscript runscript cmd basecmd=( -e user="$user" -e group="$group" -e projdir="$projdir" -e setup="$setup" -e mvn="$mvn" -e args="$args" ${java:+-e JAVA="$java"} ) eval "host_mappings=($host_mappings)" for host_mapping in "${host_mappings[@]}"; do basecmd+=(--add-host "$host_mapping") done basecmd+=(-v "$HOME:$HOME") if [ "${projdir#$HOME/}" == "$projdir" ]; then # si le répertoire de projet ne se trouve pas dans $HOME, le monter aussi cmd+=(-v "$projdir:$projdir") fi setupscript='eval "$setup"' runscript=' echo "$user" >>/etc/passwd; user="${user%%:*}" echo "$group" >>/etc/group; group="${group%%:*}" [ -n "$mvn" ] || mvn=mvn cd "$projdir" '"$actualcmd" if [ -n "$setup" ]; then local project_name container_name ctid # lancement dans un container docker à préparer [ -n "$project_name" ] || setx project_name=get_project_name setx container_name=get_container_name "$project_name" container_name="dkbuild_maven_${container_name}" # vérifier l'existence de l'image setx ctid=docker image ls --format '{{.ID}}' "${container_name}_image" # créer le container le cas échéant if [ -z "$ctid" ]; then estep "Création du container $container_name à partir de l'image $image" cmd=( docker create -it --name "${container_name}_ct" "${basecmd[@]}" "$image" bash -c "$setupscript" ) setx ctid="${cmd[@]}" && docker container start -ai "$ctid" && docker container commit "$ctid" "${container_name}_image" && docker container rm "$ctid" || die fi # prendre comme image le container créé image="${container_name}_image" fi case "$action" in rshell) estep "Lancement d'un shell root (avec l'image $image)";; shell) estep "Lancement d'un shell utilisateur (avec l'image $image)";; java) estep "java (avec l'image $image)";; *) estep "mvn $action (avec l'image $image)";; esac cmd=( docker run -it --rm "${basecmd[@]}" "$image" bash -c "$runscript" ) "${cmd[@]}" } function mvn() { edebug "mvn $(qvals "$@")" [ $# -eq 0 ] && return 0 local action destdir [[ "$1" != *=* ]] && { destdir="$1"; shift; } [[ "$1" != *=* ]] && { action="$1"; shift; } [ -n "$destdir" ] || destdir=. [ -d "$destdir" ] || die "mvn: $destdir: répertoire introuvable" local cwd="$(pwd)" cd "$destdir" || die [ -n "$action" ] || action=package [ "$action" == none ] && return local args="${DEFAULTS[mvn_args]}" local java="${DEFAULTS[mvn_java]}" local image="${DEFAULTS[mvn_image]}" local machine="${DEFAULTS[mvn_machine]}" local host_mappings="${DEFAULTS[mvn_host-mappings]-__UNDEFINED__}" [ "$host_mappings" == __UNDEFINED__ ] && host_mappings="${DEFAULTS[docker_host-mappings]}" local mvn="${DEFAULTS[mvn_mvn]}" local setup="${DEFAULTS[mvn_setup]}" local project_name="${DEFAULTS[mvn_project-name]}" if [ -f "$destdir/.maven.conf" ]; then eval "$( MAVEN_JAVA= MAVEN_IMAGE="$MAVEN_IMAGE" MAVEN_MACHINE=-u MAVEN_CMD= MAVEN_SETUP= source "$destdir/.maven.conf" [ -z "$java" ] && echo_setv java="$MAVEN_JAVA" [ -z "$image" ] && echo_setv image="$MAVEN_IMAGE" [ -z "$machine" ] && echo_setv machine="$MAVEN_MACHINE" [ -z "$mvn" ] && echo_setv mvn="$MAVEN_CMD" [ -z "$setup" ] && echo_setv setup="$MAVEN_SETUP" )" fi while [ $# -gt 0 ]; do case "$1" in args=*) args="${1#args=}";; java=*) java="${1#java=}";; image=*) image="${1#image=}";; machine=*) machine="${1#machine=}";; host-mappings=*) host_mappings="${1#host-mappings=}";; mvn=*) mvn="${1#mvn=}";; setup=*) setup="${1#setup=}";; project-name=*) project_name="${1#project-name=}";; *=*) ewarn "mvn: $1: argument ignoré";; *) break;; esac shift done local version case "$action" in java*) version="${action#java}" [ -n "$version" ] && java="$version" set java "${@:2}" ;; esac local use_image if [ "$java" == force -o "$java" == any ]; then java= use_image=1 elif [ "$java" == none -o "$java" == system ]; then java= use_image= elif [ -n "$image" -a "$image" != none ]; then use_image=1 fi if [ -n "$use_image" ]; then local orig_machine [ "$image" != none ] || die "Vous devez spécifier l'image à utiliser pour mvn" if [ -n "$machine" -a "$machine" != current -a "$DOCKER_MACHINE_NAME" != "$machine" ]; then orig_machine="$DOCKER_MACHINE_NAME" set_machine "$machine" fi _docker_mvn "$@" if [ -n "$_orig_machine" ]; then set_machine "$orig_machine" fi else _local_mvn "$@" fi # restaurer le répertoire courant cd "$cwd" } function run() { edebug "run $(qvals "$@")" [ $# -eq 0 ] && return 0 local cmd="$1"; shift if [ "${cmd#/}" != "$cmd" ]; then : elif [ "${cmd#./}" != "$cmd" ]; then : elif [ "${cmd#../}" != "$cmd" ]; then : else local abscmd setx abscmd=which "$cmd" 2>/dev/null [ -n "$abscmd" ] || die "run: $cmd: commande introuvable" edebug "'$cmd' resolved as '$abscmd'" cmd="$abscmd" fi "$cmd" "$@" || die } function call() { edebug "call $(qvals "$@")" [ $# -eq 0 ] && return 0 "$@" } function dkbuild() { edebug "dkbuild $(qvals "$@")" "$SELF" "$@" || die } } ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## init function templates_action() { declare -A TEMPLATES [ -f "$TEMPLATEDIR/templates.conf" ] && source "$TEMPLATEDIR/templates.conf" etitle "Templates valides" local -a templates setx -a templates=list_dirs "$TEMPLATEDIR" for template in "${templates[@]}"; do [ "$template" == default ] && continue desc="${TEMPLATES[$template]}" estep "$template${desc:+ - "$desc"}" done eend } ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## init function init_action() { eval "$SHARED_LOCALS1" local template; local -a defaultvars addvars local -a args; args=( "${SHARED_ARGS1[@]}" -t:,--template: template= -v:,--var: '$addvars+=("$value_")' -n:,--name: '$addvars+=(name="$value_")' -g:,--group: '$addvars+=(group="$value_")' ) parse_args "$@"; set -- "${args[@]}" defaultvars=(name=name group=group) [ $# -gt 0 ] && { [ -n "$1" ] && PROJDIR="$1"; shift; } [ $# -gt 0 ] && { [ -n "$1" ] && addvars+=(name="$1"); shift; } [ $# -gt 0 ] && { [ -n "$1" ] && addvars+=(group="$1"); shift; } declare -A vars local name value for name in "${defaultvars[@]}" "${addvars[@]}"; do if [[ "$name" == *=* ]]; then value="${name#*=}" name="${name%%=*}" else value= fi name="${name^^}" vars[$name]="$value" done [ -n "$template" ] || template=default [ -d "$TEMPLATEDIR/$template" ] || die "$template: template introuvable" [ -n "$PROJDIR" ] || PROJDIR=. setx PROJDIR=abspath "$PROJDIR" if [ ! -d "$PROJDIR" ]; then ask_yesno "Voulez-vous créer le nouveau projet $(ppath "$PROJDIR")?" O || die fi mkdir -p "$PROJDIR" local sedscript for name in "${!vars[@]}"; do value="${vars[$name]}" [ -n "$sedscript" ] && sedscript="$sedscript; " sedscript="${sedscript}s/${name//\//\\\/}/${value//\//\\\/}/g" done local src mode dest link template="$TEMPLATEDIR/$template" enote "Initialisation de $(ppath "$PROJDIR")" find "$template/" -type f -o -type l | while read src; do dest="$PROJDIR/${src#$template/}" if [ -L "$src" ]; then setx link=readlink "$src" if [ -L "$dest" ]; then if [ "$(readlink "$dest")" != "$link" ]; then estep "${src#$template/} [link, updated]" ln -sf "$link" "$dest" else edebug "${src#$template/} [exists, ignored]" fi elif [ -e "$dest" ]; then estepe "${src#$template/} [destination is not a link]" else estep "${src#$template/} [link]" ln -s "$link" "$dest" fi elif [ -f "$dest" ]; then edebug "${src#$template/} [exists, ignored]" else estep "${src#$template/}" mkdirof "$dest" sed <"$src" >"$dest" "$sedscript" setx mode=stat -c %a "$src" chmod "$mode" "$dest" fi done } ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## build function build_action() { eval "$SHARED_LOCALS1; $SHARED_LOCALS2" local action=build local machine local clone_src_only update_src_only update_src sync_src local build no_cache pull_image local push_image local -a args; args=( "${SHARED_ARGS1[@]}" "${SHARED_ARGS2[@]}" -m:,--machine: machine= --clone-src-only clone_src_only=1 --update-src-only update_src_only=1 --update-src update_src=1 --no-update-src update_src=no -w,--update-devel-src update_src=devel -s,--sync-src sync_src=1 --no-sync-src sync_src=no -b,--build build=1 --no-cache no_cache=1 -u,--pull-image pull_image=1 -p,--push-image push_image=1 ) parse_args "$@"; set -- "${args[@]}" if [ -n "$clone_src_only" ]; then action=clone_src elif [ -n "$update_src_only" ]; then action=update_src else action=build [ -n "$update_src" ] || update_src=1 [ "$update_src" == no ] && update_src= if [ -z "$sync_src" -a -z "$build" -a -z "$push_image" ]; then sync_src=1 build=1 fi [ "$sync_src" == no ] && sync_src= fi edebug "build_action" set_machine "$machine" ensure_projdir resolve_dists_profiles setenv "${TMPENVIRON[@]}" setarg "${TMPARGS[@]}" setarg "$@" case "$action" in clone_src) die "Pas encore implémenté" #XXX ;; update_src) die "Pas encore implémenté" #XXX ;; build) default checkout checkout="$update_src" default copy copy="$sync_src" default build build="$build" ${no_cache:+no-cache} ${pull_image:+pull} ${push_image:+push} [ $# -gt 0 ] && default build "$@" define_functions_cmd foreach_dists_profiles _build_each _build_before _build_after ;; esac } function _build_before() { PREV_DIST= PREV_PROFILE= } function _build_each() { if [ "$PROFILE-$PVERSION" != "$PREV_PROFILE" ]; then [ -n "$PREV_PROFILE" ] && eend fi if [ -n "$DIST" -a "$DIST-$DVERSION" != "$PREV_DIST" ]; then [ -n "$PREV_DIST" ] && eend PREV_DIST="$DIST-$DVERSION" etitle "Distribution ${DVERSION:+$DVERSION-}$DIST" fi if [ -n "$PROFILE" -a "$PROFILE-$PVERSION" != "$PREV_PROFILE" ]; then PREV_PROFILE="$PROFILE-$PVERSION" etitle "Profil ${PVERSION:+$PVERSION-}$PROFILE" fi load_dkbuild if [ -n "$AUTOBUILD" ]; then if [ -f docker-compose.yml ]; then cbuild else build fi fi } function _build_after() { if [ -n "$PREV_PROFILE" ]; then eend; fi if [ -n "$PREV_DIST" ]; then eend; fi } ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## clean function _clean_git_clean() { LANG=C git clean -d $opt "$@" | grep -vE '^(Would skip|Skipping) ' | sed -r 's/^Would remove //' } function _clean_git_status() { git status --porcelain --ignored | grep '^!! ' | sed 's/^...//' } function clean_action() { eval "$SHARED_LOCALS1" local opt=-X all= local -a args; args=( "${SHARED_ARGS1[@]}" -X,--ignored opt=-X -x,--untracked opt=-x -a,--all all=1 ) parse_args "$@"; set -- "${args[@]}" [ -n "$all" ] && opt=-x edebug "clean_action" ensure_projdir local cleans setx cleans=_clean_git_clean -n "$@" if [ -n "$cleans" ]; then if check_interaction -c; then einfo "via git clean" eecho "$cleans" ask_yesno "Voulez-vous supprimer ces fichiers?" O || die fi _clean_git_clean -f "$@" || die fi if [ -n "$all" ]; then setx cleans=_clean_git_status if [ -n "$cleans" ]; then if check_interaction -c; then einfo "via git status" eecho "$cleans" ask_yesno "Voulez-vous supprimer ces fichiers supplémentaires?" O || die fi sed 's/^/Removing /' <<<"$cleans" eval "cleans=($cleans);"' rm -rf "${cleans[@]}"' || die fi fi } ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## composer function composer_action() { local -a args; args=( ) parse_args "$@"; set -- "${args[@]}" [ $# -gt 0 ] || set . edebug "composer_action" define_functions_cmd composer "$@" } ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## mvn function mvn_action() { local -a args; args=( ) parse_args "$@"; set -- "${args[@]}" [ $# -gt 0 ] || set . edebug "mvn_action" define_functions_cmd mvn "$@" } ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## dump function dump_action() { eval "$SHARED_LOCALS1; $SHARED_LOCALS2" local machine local -a args; args=( "${SHARED_ARGS1[@]}" "${SHARED_ARGS2[@]}" -m:,--machine: machine= ) parse_args "$@"; set -- "${args[@]}" edebug "dump_action" set_machine "$machine" ensure_projdir resolve_dists_profiles setenv "${TMPENVIRON[@]}" setarg "${TMPARGS[@]}" setarg "$@" foreach_dists_profiles _dump_each _dump_before _dump_after } function _dump_before() { PREV_DIST= PREV_PROFILE= } function _dump_each() { if [ "$PROFILE-$PVERSION" != "$PREV_PROFILE" ]; then [ -n "$PREV_PROFILE" ] && eend fi if [ -n "$DIST" -a "$DIST-$DVERSION" != "$PREV_DIST" ]; then [ -n "$PREV_DIST" ] && eend PREV_DIST="$DIST-$DVERSION" etitle "Distribution ${DVERSION:+$DVERSION-}$DIST" fi if [ -n "$PROFILE" -a "$PROFILE-$PVERSION" != "$PREV_PROFILE" ]; then PREV_PROFILE="$PROFILE-$PVERSION" etitle "Profil ${PVERSION:+$PVERSION-}$PROFILE" fi load_dkbuild etitle "Variables d'environnement" for name in "${!ENVIRON[@]}"; do estep "$name=${ENVIRON[$name]}" done eend etitle "Variables de build" for name in "${!ARGS[@]}"; do estep "$name=${ARGS[$name]}" done eend etitle "Valeurs par défaut" for name in "${!DEFAULTS[@]}"; do estep "$name=${DEFAULTS[$name]}" done eend } function _dump_after() { if [ -n "$PREV_PROFILE" ]; then eend; fi if [ -n "$PREV_DIST" ]; then eend; fi } ##~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ## # faire une copie de l'environnement original load_environ # si aucune action n'est spécifiée, il faut inférer build pour que ses options # soient reconnues args=() while [ $# -gt 0 ]; do case "$1" in --help) args+=("$1"); shift; continue;; --hdk|--help-dkbuild) args+=("$1"); shift; continue;; --href|--help-reference) args+=("$1"); shift; continue;; -*|*=*) # option quelconque: inférer build args+=(build) break ;; *) # argument quelconque: on s'arrête ici break ;; esac done set -- "${args[@]}" "$@" args=(+ --help '$exit_with display_help' --hdk,--help-dkbuild '$exit_with display_help_dkbuild' --href,--help-reference '$exit_with display_help_reference' ) parse_args "$@"; set -- "${args[@]}" # aliases case "$1" in ci) set composer "$2" install "${@:3}";; cu) set composer "$2" update "${@:3}";; cr) set composer "$2" rshell "${@:3}";; cs) set composer "$2" shell "${@:3}";; mvr) set mvn "$2" rshell "${@:3}";; mvs) set mvn "$2" shell "${@:3}";; java) set mvn "$2" java "${@:3}";; esac # actions action="${1:-build}"; shift case "$action" in templates|t) templates_action "$@";; init|i|0) init_action "$@";; build|b) build_action "$@";; clean|k) clean_action "$@";; composer|c) composer_action "$@";; maven|mvn|m) mvn_action "$@";; dump|d) dump_action "$@";; *) die "$action: action invalide";; esac