Intégration de la branche release-9.4.0

This commit is contained in:
Jephté Clain 2019-06-05 10:15:32 +04:00
commit eb3979de4d
11 changed files with 1064 additions and 183 deletions

View File

@ -1,3 +1,33 @@
## Version 9.4.0 du 05/06/2019-10:15
* `fb96852` Intégration de la branche dk-deploy
* `386fc0d` implémenter service, update, scale
* `c2f43e6` optimiser l'utilisation de docker-machine
* `8cb3b2f` ajouter la commande deploy
* `5967541` cx-updatedev: ajouter l'option -j
* `d79e218` dk: support de push pour docker-compose
* `ccbfff4` dk: simplifier la gestion du nommage des services
* `50dee34` dk: support de build d'un service en particulier
* `99d5069` bug
* `a825f3b` bug
* `8c143e1` foreach: ajout de --cc
* `7e26ae1` foreach: ajout des raccourcis -G et -C
* `cbb34ec` cx-conndev: afficher les erreurs
* `7524a28` cosmetic
* `9b03dcd` cx-updatedev: ajout de -i et -u
* `c7eca6a` cx-updatedev: ajout des options -l et -c
* `8b4067a` bug
* `3971dca` scripts pour gérer projets composer
* `c66eee1` scripts pour gérer projets composer
* `7c135fa` fconv, fnconv: support de sed
* `72c3512` dk: bug dans la détection du type de projet
* `0891e89` sqlmig: corriger la lecture des paramètres
* `d197fc0` sqlmig: support de l'importation directe des fichiers csv
* `d028c47` dk: maj doc et support d'origine de profil
* `b068a12` dk: maj doc et support de branche de profil
* `d7c981d` dk: afficher l'adresse ip
* `7ec5381` dk: renommer service en systemd-unit
## Version 9.3.0 du 02/04/2019-16:03
* `6a03853` ajout de update-apps en natif

14
TODO.md
View File

@ -1,3 +1,17 @@
# TODO
## dk
Ajouter le support du déploiement de services dans un swarm
Les nouvelles actions suivantes sont disponibles:
* deploy -- déployer un service
* bpd -- équivalent à build, push, deploy
* update -- mettre à jour un service déployé
* bpu -- équivalent à build, push, update
* rollback -- annuler la mise à jour d'un service
Pour toutes ces actions, utiliser par défaut docker-stack.yml s'il existe,
sinon utiliser docker-compose.yml (en tenant compte des paramètres des profils)
-*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary

View File

@ -1 +1 @@
9.3.0
9.4.0

60
cx-conndev Executable file
View File

@ -0,0 +1,60 @@
#!/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
function display_help() {
uecho "$scriptname: se connecter à la base MySQL
USAGE
$scriptname [DATABASE]
OPTIONS
-h, -s, --service SERVICE
Spécifier le nom du service. La valeur par défaut est db"
}
service=db
args=(
--help '$exit_with display_help'
-h:,-s:,--service: service=
)
parse_args "$@"; set -- "${args[@]}"
[ -n "$service" ] || die "Vous devez spécifier le nom du service"
found=
first=1
while true; do
if [ -f composer.json ]; then
found=1
break
fi
first=
cd ..
if [ "$(pwd)" == "$HOME" ]; then
die "Cette commande ne peut être lancée que depuis un projet Composer"
fi
done
if [ -z "$first" ]; then
enote "Le répertoire du projet est $(ppath . ~)"
fi
[ -f bin/conndev.php ] || die "Impossible de trouver le script compagnon conndev.php"
###
function die_not_found() { die "$service: service introuvable"; }
setx cid=docker-compose ps -q "$service" 2>/dev/null || die_not_found
[ -n "$cid" ] || die_not_found
edebug "$service id: $cid"
function die_not_found() { die "$service: $cid: ip introuvable"; }
setx ip=docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$cid" || die_not_found
[ -n "$ip" ] || die_not_found
edebug "$service ip: $ip"
mysqlcmd="$(php bin/conndev.php "$ip" "$@")"
edebug "mysqlcmd: $mysqlcmd"
eval "$mysqlcmd"

56
cx-shelldev Executable file
View File

@ -0,0 +1,56 @@
#!/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
function display_help() {
uecho "$scriptname: ouvrir un shell dans le container
USAGE
$scriptname [SHELL]
OPTIONS
-h, -s, --service SERVICE
Spécifier le nom du service sur lequel ouvrir le shell
-d
équivalent à -s db
-w
équivalent à -s web (c'est la valeur par défaut)"
}
service=web
args=(
--help '$exit_with display_help'
-h:,-s:,--service: service=
-d service=db
-w service=web
)
parse_args "$@"; set -- "${args[@]}"
[ -n "$service" ] || die "Vous devez spécifier le nom du service"
found=
first=1
while true; do
if [ -f composer.json ]; then
found=1
break
fi
first=
cd ..
if [ "$(pwd)" == "$HOME" ]; then
die "Cette commande ne peut être lancée que depuis un projet Composer"
fi
done
if [ -z "$first" ]; then
enote "Le répertoire du projet est $(ppath . ~)"
fi
###
setx cid=docker-compose ps -q "$service" 2>/dev/null || die "$service: service introuvable"
cmd=("$@")
[ ${#cmd[*]} -gt 0 ] || cmd=(bash)
docker-compose exec "$service" "${cmd[@]}"

190
cx-updatedev Executable file
View File

@ -0,0 +1,190 @@
#!/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
function display_help() {
uecho "$scriptname: mettre à jour un module ur/* ou lib/* sans utiliser composer
ça permet de faire du développement plus rapidement sans utiliser les dépôts de
type path
USAGE
$scriptname modules...
OPTIONS
-n, --fake
Afficher simplement ce qui serait fait
-q, --quiet
Ne pas lancer rsync en mode verbose
-l, --link
Transformer les clones de dépôts en liens directs vers les projets
-k, --copy
Transformer les liens directs vers les projets en copies des projets
-i, --install
Supprimer les répertoires et les faire recréer par composer i
-j, --reinstall-link
Supprimer les répertoires et les faire recréer par composer i,
uniquement s'il s'agit de liens
-u, --update
Supprimer les répertoires et les faire recréer par composer u"
}
fake=
verbose=1
action=
args=(
--help '$exit_with display_help'
-n,--fake fake=1
-q,--quiet verbose=
-l,--link action=link
-k,--copy action=copy
-i,--install action=install
-j,--reinstall-link action=reinstall-link
-u,--update action=update
)
parse_args "$@"; set -- "${args[@]}"
found=
first=1
while true; do
if [ -f composer.json ]; then
found=1
break
fi
first=
cd ..
if [ "$(pwd)" == "$HOME" ]; then
die "Cette commande ne peut être lancée que depuis un projet Composer"
fi
done
if [ -z "$first" ]; then
enote "Le répertoire du projet est $(ppath . ~)"
fi
case "$action" in
install|update)
[ -x ./composer.phar ] || die "Impossible de trouver composer.phar"
;;
esac
###
if [ $# -eq 0 ]; then
setx -a ms=list_dirs vendor "ur/*" "lib/*"
set -- "${ms[@]}"
fi
function check_module() {
[ -d "../$m" ] || die "$m: module introuvable"
}
function update_with_rsync() {
local -a rsync_args
rsync_args=(
-a ${fake:+-n} ${verbose:+-v}
--delete
-f "- /.git/"
-f "- /vendor/"
"../$m/" "vendor/$p"
)
rsync "${rsync_args[@]}"
}
deps=()
for m in "$@"; do
m="${m#vendor/}" # pour permettre de spécifier le chemin directement
m="${m//\//-}"
case "$m" in
ur-*|lib-*) ;;
*) m="ur-$m";;
esac
p="${m//-/\/}"
check_module
case "$action" in
link)
# Ignorer les liens et transformer les copies en liens
if [ ! -L "vendor/$p" ]; then
link="$m"
path="/project/vendor/$p"
path="${path%/*}"
while [ -n "$path" ]; do
link="../$link"
path="${path%/*}"
done
etitle "$m"
estep "suppr. vendor/$p"
rm -rf "vendor/$p"
mkdirof "vendor/$p"
estep "vendor/$p --> $link"
ln -s "$link" "vendor/$p"
eend
fi
;;
copy)
# Transformer les liens en copie et les synchroniser
etitle "$m"
if [ -L "vendor/$p" ]; then
estep "suppr. vendor/$p"
rm -f "vendor/$p"
fi
update_with_rsync
eend
;;
install)
# Supprimer les liens et répertoires...
etitle "$m"
if [ -e "vendor/$p" ]; then
estep "suppr. vendor/$p"
rm -rf "vendor/$p"
fi
array_add deps "$p"
eend
;;
reinstall-link)
# Supprimer les liens uniquement...
etitle "$m"
if [ -L "vendor/$p" ]; then
estep "suppr. vendor/$p"
rm -f "vendor/$p"
fi
array_add deps "$p"
eend
;;
update)
# Supprimer les liens et répertoires...
etitle "$m"
if [ -e "vendor/$p" ]; then
estep "suppr. vendor/$p"
rm -rf "vendor/$p"
fi
array_add deps "$p"
eend
;;
*)
# Action par défaut: ignorer les liens et synchroniser les copies
if [ ! -L "vendor/$p" ]; then
etitle "$m"
update_with_rsync
eend
fi
;;
esac
done
case "$action" in
install|reinstall-link)
# ... puis installer les dépendances
etitle "Installation des dépendances"
./composer.phar i
eend
;;
update)
# ... puis mettre à jour les dépendances
etitle "Mise à jour des dépendances"
./composer.phar u "${deps[@]}"
eend
;;
esac

513
dk
View File

@ -9,72 +9,150 @@ USAGE
$scriptname CMDs...
COMMANDES
build
b|build [SERVICE]
Construire les images
push
Pousser les images vers le serveur
start, run [SERVICE]
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|run [SERVICE]
Démarrer le(s) service(s)
stop [SERVICE]
k|stop [SERVICE]
Arrêter le(s) service(s)
up
1|up
Créer l'environnement, démarrer les services et suivre les logs de façon
interactive.
logs [SERVICE]
Vaguement équivalent à -- start -- logs
l|logs [SERVICE]
Afficher les logs
down
0|down
Arrêter les services et supprimer l'environnement
brd
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)
exec SERVICE COMMAND
Equivalent à -- build -- start [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
x|exec SERVICE COMMAND
Lancer la commande dans le container spécifié
service
Générer une unité systemd qui démarre les services
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
prune
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
-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
-j, --no-cache
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)
(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:
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_BRANCH=
APPS=()
app_URL=
app_DEST=
app_ORIGIN=
app_BRANCH=
app_TYPE=
app_AFTER_UPDATE=()
APPS=() # liste d'applications à mettre à jour
app_URL= # url du dépôt
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.
--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"
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
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() {
@ -125,6 +203,7 @@ function docker_set_run_args() {
}
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_-]/}"
@ -132,57 +211,89 @@ function docker_check_name() {
fi
}
function compose_set_project_name() {
local PROJECT_NAME= PROJECT_NAME_REMOVE_SUFFIX=.service PROJECT_NAME_ADD_PROFILE=1
[ -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() {
replace_env_args+=(-f docker-compose.yml)
if [ -f docker-compose.override.yml ]; then
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
local PROJECT_NAME=--none--
[ -f .compose.env ] && source ./.compose.env
if [ -n "$PROFILE" ]; then
if [ -f "docker-compose.$PROFILE.yml" ]; 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
if [ "$PROJECT_NAME" != --none-- ]; then
if [ -z "$COMPOSE_PROJECT_NAME" ]; then
[ -n "$PROJECT_NAME" ] || PROJECT_NAME="$(basename -- "$(pwd)")"
COMPOSE_PROJECT_NAME="${PROJECT_NAME}_${PROFILE}"
fi
export COMPOSE_PROJECT_NAME
fi
compose_set_project_name "$@"
}
function docker_set_deploy_args() {
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_env_args+=(-c "docker-stack.$PROFILE.yml")
elif [ -f "docker-compose.$PROFILE.yml" ]; then
replace_env_args+=(-c "docker-compose.$PROFILE.yml")
fi
fi
if [ "$1" == set_container_name ]; then
if [ "$PROJECT_NAME" == --none-- ]; then
project_name="$(basename -- "$(pwd)")"
else
project_name="$PROJECT_NAME"
fi
container_name="${project_name//[^a-zA-Z0-9_-]/}"
[ -n "$PROFILE" ] && container_name="${container_name}_$PROFILE"
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 l'hôte local, lancer le script en
# local avec les droits root
# 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" ]; then
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
local dm; setx dm=docker-machine active 2>/dev/null
if [ "${host%%.*}" == "$dm" ]; 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 ($dm) n'est pas la destination ($host)"
ewarn "La machine active ($DOCKER_MACHINE_NAME) n'est pas la destination ($host)"
fi
else
estep "Copie du script vers root@$host"
@ -231,7 +342,10 @@ function update_apps_func_sqlmig() {
[ -n "$srcdir" ] || srcdir="$dest"
[ "${srcdir%/config/sqlmig}" != "$srcdir" ] || srcdir="$srcdir/config/sqlmig"
[ -d "$srcdir" ] || return 0
if [ ! -d "$srcdir" ]; then
eerror "$srcdir: répertoire introuvable"
return 1
fi
local -a sqlmigs; local sqlmig name
array_lsall sqlmigs "$srcdir"
@ -271,29 +385,28 @@ function build_update_apps() {
esac
etitle "Mise à jour des dépendances"
local app type url dest branch after_update after_updates
local app var type url dest branch after_update after_updates
for app in "${APPS[@]}"; do
etitle "$app"
url="${app}_URL"; url="${!url}"
dest="${app}_DEST"; dest="${!dest}"
origin="${app}_ORIGIN"; origin="${!origin}"
branch="${app}_BRANCH"; branch="${!branch}"
type="${app}_TYPE"; type="${!type}"
after_updates="${app}_AFTER_UPDATE"
if is_defined "$after_updates"; then
after_updates="$after_updates[@]"; after_updates="${!after_updates}"
else
# script par défaut après update-apps
after_updates=(sqlmig)
fi
var="${app//-/_}"
url="${var}_URL"; url="${!url}"
[ -n "$url" ] || {
ewarn "$app: vous devez définir l'url"
eend; return 1
}
[ -n "$dest" ] || dest="$app"
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"
dest="$dest/$app"
@ -311,6 +424,7 @@ function build_update_apps() {
cd "$cwd"
fi
type="${var}_TYPE"; type="${!type}"
if [ -z "$type" ]; then
if [ -f "$dest/composer.json" ]; then
type=composer
@ -318,6 +432,16 @@ function build_update_apps() {
type=inconnu
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
@ -395,33 +519,51 @@ function auto_build() {
compose_set_env_args
update_build_env
build_update_apps || return 1
compose_build
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
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
local tag
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
for tag in "${TAGS[@]}"; do
${FAKE:+qvals} docker push "$NAME:$tag"
done
}
function default_compose_up() {
@ -545,6 +687,98 @@ function auto_down() {
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() {
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
local command="$1"; shift
[ -n "$command" ] || {
eerror "Vous devez spécifier la commande"
return 1
}
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
}
docker_set_deploy_args set_container_name
service="${container_name}_${service#${container_name}_}"
docker_service "$command" "$@" "$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_exec() {
${FAKE:+qvals} docker-compose \
"${replace_env_args[@]}" "${env_args[@]}" \
@ -572,7 +806,7 @@ function auto_exec() {
fi
}
function default_compose_service() {
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
@ -589,7 +823,7 @@ function default_compose_service() {
"${replace_user_args[@]}" "${user_args[@]}" "$@"
setx stopcmd=qvals "$docker_compose" down
}
function default_docker_service() {
function default_docker_systemd_unit() {
local docker="$(which docker 2>/dev/null)"
if [ -z "$docker" ]; then
if [ -x /usr/bin/docker ]; then
@ -607,21 +841,21 @@ function default_docker_service() {
"${replace_user_args[@]}" "${user_args[@]}" "$@"
setx stopcmd=qvals "$docker" stop "$container_name"
}
function compose_service() { default_compose_service "$@"; }
function docker_service() { default_docker_service "$@"; }
function auto_service() {
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 du service"
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_service "$@"
compose_systemd_unit "$@"
if [ -z "$HOST" -a -f .env ]; then
source ./.env
if [ -n "$PROFILE" ]; then
@ -632,7 +866,7 @@ function auto_service() {
docker_set_env_args
docker_check_name set_container_name
replace_run_args=(-d --name "$container_name")
docker_service "$@"
docker_systemd_unit "$@"
fi
[ -n "$COMPOSE_PROJECT_NAME" ] || COMPOSE_PROJECT_NAME="$project_name"
chmod 755 "$tmpscript"
@ -661,7 +895,7 @@ systemctl daemon-reload
systemctl enable $container_name.service
EOF
estep "Installation du service"
estep "Installation de l'unité systemd"
local_run "$HOST" "$tmpscript"
}
@ -671,21 +905,13 @@ DM_PROFILES=()
set_defaults dk
export PROFILE
if progexists docker-machine; then
setx active_dm=docker-machine active 2>/dev/null
for dm_profile in "${DM_PROFILES[@]}"; do
splitpair "$dm_profile" dm profile
if [ "$dm" == "$active_dm" ]; then
DEFAULT_PROFILE="$profile"
break
fi
done
fi
chdir=
DM_SET_MACHINE=
USE_STACK=
FAKE=
NO_CACHE=
HOST=
WITH_REGISTRY_AUTH=1
update_apps_mode=ub
update_apps_origin=
update_apps_branch=
@ -695,6 +921,8 @@ args=(
-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=
@ -702,9 +930,26 @@ args=(
-u,--uu,--update-apps-only update_apps_mode=u
--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"
@ -726,7 +971,7 @@ while [ $# -gt 0 ]; do
enote "Profil $PROFILE"
auto_build "${args[@]}" || die
;;
push)
p|push)
[ -f .build.scripts.sh ] && source ./.build.scripts.sh
[ -f build.scripts.sh ] && source ./build.scripts.sh
args=()
@ -801,6 +1046,7 @@ while [ $# -gt 0 ]; do
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
@ -808,6 +1054,81 @@ while [ $# -gt 0 ]; do
enote "Profil $PROFILE"
auto_build && auto_up "${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
;;
x|exec)
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
@ -816,13 +1137,13 @@ while [ $# -gt 0 ]; do
enote "Profil $PROFILE"
auto_exec "${args[@]}" || die
;;
service)
systemd-unit|systemd)
args=()
while [ $# -gt 0 -a "$1" != -- ]; do
args+=("$1"); shift
done
enote "Profil $PROFILE"
auto_service "${args[@]}" || die
auto_systemd_unit "${args[@]}" || die
;;
ps) docker container ps -a || die;;
ls) docker image ls || die;;

4
fconv
View File

@ -54,6 +54,8 @@ COMMANDES
Transformer certains caratères UTF-8 en équivalents qui existent en Latin1
na, noaccents
Transformer les caractères accentués en caractères non accentués
[sed] s/from/to/opts
Filtrer avec l'expression régulière de sed 's/from/to/opts'
sort [-u]
Trier le fichier avec la commande sort. Attention! Il ne faut utiliser
que les options de sort qui agissent sur un flux e.g. -u pour trier les
@ -151,6 +153,8 @@ function parse_cmd() {
cr) echo _nl2cr;;
latin1compat|lc) echo _latin1compat;;
noaccents|na|fixchars|fc) echo _noaccents;;
s/*) qvals sed "$cmd" "$@";;
sed) qvals sed "$@";;
sort) qvals sort "$@";;
*)
echo "$cmd: commande invalide"

6
fnconv
View File

@ -51,7 +51,9 @@ COMMANDES
u, uppercase
Transformer le nom en majuscule
f, fixcase
Transformer le nom en minuscule s'il est entièrement en majuscule"
Transformer le nom en minuscule s'il est entièrement en majuscule
[sed] s/from/to/opts
Renommer le fichier avec l'expression régulière de sed 's/from/to/opts'"
}
function _lowercase() {
@ -163,6 +165,8 @@ function parse_cmd() {
lowercase|lower|l) echo _lowercase;;
uppercase|upper|u) echo _uppercase;;
fixcase|fix|f) echo _fixcase;;
s/*) qvals sed "$cmd" "$@";;
sed) qvals sed "$@";;
*)
echo "$cmd: commande invalide"
return 1

58
foreach
View File

@ -74,10 +74,20 @@ OPTIONS
Si l'expansion est désactivée, il faut protéger le caractère \$ pour
qu'il soit traité, e.g, avec les examples ci-dessus:
$scriptname -n '*.c' 'cp \"\$item\" dest/dir'
-t, --title
--no-title
--title
--pt, --parent-title
--nt, --no-title
Afficher (resp. ne pas afficher) chaque correspondance avant de lancer
la commande. Par défaut, l'affichage est effectué."
la commande. Par défaut, l'affichage est effectué.
Avec --parent-title, pour chaque correspondance afficher plutôt le
répertoire parent (valide uniquement avec l'option -p)
-G, --git-projects
Equivalent à '--ptitle -p */.git --' e.g '$scriptname -G git pull' pour
mettre à jour les dépôts situés dans un répertoire
-C, --composer-projects
Equivalent à '--ptitle -p */composer.json --'
--cc, --composer-cmd
Equivalent à '--ptitle -p */composer.phar -- ./composer.phar'"
}
basedir=
@ -85,7 +95,8 @@ match=auto
changedir=
parentdir=
expand=1
title=1
title=auto
shortcut=
args=(+
--help '$exit_with display_help'
-b:,--basedir: basedir=
@ -97,18 +108,37 @@ args=(+
-s,--string match=string
-x,--expand expand=1
-n,--no-expand expand=
-t,--title title=1
--no-title title=
--title title=1
--pt,--parent-title title=p
--nt,--no-title title=
-G,--git-projects shortcut=git
-C,--composer-projects shortcut=composer
--cc,--composer-cmd shortcut=composer-cmd
)
parse_args "$@"; set -- "${args[@]}"
case "$shortcut" in
git)
set -- */.git -- "$@"
parentdir=1
[ "$title" == auto ] && title=p
;;
composer)
set -- */composer.json -- "$@"
parentdir=1
[ "$title" == auto ] && title=p
;;
composer-cmd)
set -- */composer.phar -- ./composer.phar "$@"
parentdir=1
[ "$title" == auto ] && title=p
;;
esac
if [ "$match" == auto ]; then
if [ -n "$changedir" ]; then
match=dir
else
match=all
fi
[ -n "$changedir" ] && match=dir || match=all
fi
[ "$title" == auto ] && title=1
alt_syntax=
for sep in "$@"; do
@ -175,7 +205,11 @@ fi
[ -n "$title" ] && einfo "${#items[@]} correspondance(s) trouvée(s)"
let index=0
for item in "${items[@]}"; do
[ -n "$title" ] && etitle "$item"
if [ -n "$parentdir" -a "$title" == p ]; then
etitle "$(dirname -- "$item")"
elif [ -n "$title" ]; then
etitle "$item"
fi
i="$item"
setx file=abspath "$item"
setx dir=dirname -- "$file"

314
sqlmig
View File

@ -80,13 +80,53 @@ OPTIONS
spécifié au nom de la base de données. Cette valeur peut être spécifiée
dans la section [sqlmig] du fichier my.cnf ou avec la variable SUFFIX
pour ora.conf
--csv2sql
Convertir les fichiers CSV en SQL. C'est la valeur par défaut. Ce
paramètre peut être spécifié dans my.cnf sous la forme
[sqlmig]
csv2sql=1
ou dans ora.conf
CSV2SQL=1
Pour le moment, cette conversion n'est supportée que pour MySQL. Tous
les fichiers de la forme [NUM]TABLE[-data].csv sont transformés en une
suite d'insertion dans la table TABLE. Une variante insère les données
dans la table après l'avoir vidée avec 'truncate table'. Les fichiers
doivent être de la forme [NUM]TABLE-data_truncate.csv
--csv-null VALUE
Lors de la conversion des fichiers .csv en .sql, considérer que VALUE
représente la valeur NULL. Par défaut, utiliser la chaine vide
--csv-null-empty
--csv-null-mysql
--csv-null-upper
Aliases pour --csv-null '\\N' et --csv-null NULL respectivement
Aliases pour --csv-null '', --csv-null '\\N' et --csv-null NULL respectivement
--no-csv2sql
Ne pas convertir les fichiers CSV en SQL. Ce paramètre peut être
spécifié dans my.cnf sous la forme
[sqlmig]
csv2sql=0
ou dans ora.conf
CSV2SQL=0
--load-data DEFAULT|LOCAL|SERVER
Si l'option --no-csv2sql est activée, spécifier le type de chargement
effectué pour les fichiers CSV.
* Avec LOCAL (la valeur par défaut), la directive 'load data local' est
utilisée. Cependant les erreurs éventuelles sont ignorées parce que le
serveur n'a pas de moyen pour arrêter la transmission des informations
par le client.
* Avec SERVER, la directive 'load data' est utilisée. Les erreurs
éventuelles sont affichées et arrêtent l'importation des données. Par
contre, le fichier doit être accessible par le serveur MySQL puisque
les données sont chargées directement par le serveur.
NB: avec MariaDB sur systemd, l'accès à /home, /root et /run/user est
désactivé par défaut. Pour pouvoir utiliser ce mode avec des fichiers
de l'utilisateur, il faut lancer ces commandes:
[ \$(id -u) == 0 ] && sudo= || sudo=sudo
\$sudo mkdir -p /etc/systemd/system/mariadb.service.d
\$sudo tee /etc/systemd/system/mariadb.service.d/dontprotecthome.conf <<<\$'[Service]\nProtectHome=false'
\$sudo systemctl daemon-reload
* Avec DEFAULT, utiliser SERVER si on communique avec le serveur MySQL
local (c'est à dire si host n'est pas spécifié ou vaut 127.*, ::1 ou
localhost). Sinon, utiliser LOCAL
--profile PROFILE
-P, --prod
-T, --test
@ -156,14 +196,9 @@ OPTIONS
--force, --continue-on-error
Ne pas s'arrêter en cas d'erreur de mise à jour
--no-data-csv
Ne pas convertir les fichiers *-data.csv en fichier .sql
correspondant. Cette conversion n'est supportée que pour MySQL pour le
moment, et un fichier de la forme NUMTABLE-data.csv où NUM est une valeur
numérique est transformé en une suite d'insertions dans la table TABLE.
La variante NUMTABLE-data_truncate.csv ajoute les données dans la table
après l'avoir vidée avec truncate.
Ne pas procéder à la conversion des fichiers CSV en SQL
--force-data-csv
Forcer la conversion des fichiers *-data.csv. Par défaut, la conversion
Forcer la conversion des fichiers CSV en SQL. Par défaut, la conversion
n'est faite que si le fichier csv est plus récent que le fichier sql
correspondant.
--devel-mode
@ -326,12 +361,60 @@ function set_dbdirs() {
fi
}
function fix_csv2sql() {
if [ -z "$csv2sql" ]; then
# valeur par défaut
csv2sql=1
elif is_yes "$csv2sql"; then
csv2sql=1
elif is_no "$csv2sql"; then
csv2sql=0
fi
}
function fix_csv_null() {
# si csv_null a une valeur vide, c'est déjà la valeur par défaut
case "$csv_null" in
empty) csv_null=;;
mysql) csv_null='\N';;
upper) csv_null=NULL;;
esac
}
function fix_load_data() {
if [ -z "$load_data" ]; then
# valeur par défaut
load_data=local
else
case "${load_data,,}" in
default|d*) load_data=default;;
local|l*) load_data=local;;
server|s*) load_data=server;;
esac
fi
if [ "$load_data" == default ]; then
case "$host" in
""|localhost|127.*|::1) load_data=server;;
*) load_data=local;;
esac
fi
}
function get_csvinfo() {
# afficher les informations sur un fichier csv: nom de la table, et s'il
# faut faire un truncate
local csvname="$(basename -- "$1")"
local script='{
truncate = ($0 ~ /-data_truncate(.devel)?.csv$/)? "1": ""
sub(/^.*\//, "")
sub(/^(([A-Z][-.A-Z0-9]*[0-9]-?)|([0-9][-.0-9]*-?))/, "")
sub(/\.csv$/, "")
sub(/\.devel$/, "")
sub(/-data(_[a-z]+*)?$/, "")
print "truncate=" truncate
gsub(/'\''/, "'\'\\\\\'\''")
print "table='\''" $0 "'\''"
}'
awk "$script" <<<"$csvname"
}
################################################################################
# MySQL
@ -476,6 +559,13 @@ function mysql__mconf_get() {
setx tmp=mconf_get "$defaults" sqlmig suffix
[ -n "$tmp" ] && suffix="$tmp"
fi
if [ -n "$set_csv2sql" ]; then
setx tmp=mconf_get "$defaults" sqlmig csv2sql
[ -n "$tmp" ] && {
csv2sql="$tmp"
fix_csv2sql
}
fi
if [ -n "$set_csv_null" ]; then
setx tmp=mconf_get "$defaults" sqlmig csv_null
[ -n "$tmp" ] && {
@ -483,14 +573,27 @@ function mysql__mconf_get() {
fix_csv_null
}
fi
if [ -n "$set_load_data" ]; then
if [ -z "$host" ]; then
# load_data==default requière host
setx host=mconf_get "$defaults" client host
fi
setx tmp=mconf_get "$defaults" sqlmig load-data
[ -n "$tmp" ] && {
load_data="$tmp"
fix_load_data
}
fi
}
function mysql_set_userargs() {
local dir="$1" dbname="$2" defaults
local set_suffix set_csv_null
local set_suffix set_csv2sql set_csv_null set_load_data
userargs=()
setx defaults=mysql_get_defaults "$dir"
[ -z "$suffix" ] && set_suffix=1
[ -z "$csv2sql" ] && set_csv2sql=1
[ -z "$csv_null" ] && set_csv_null=1
[ -z "$load_data" ] && set_load_data=1
if [ -f "$defaults" ]; then
array_add userargs --defaults-file="$defaults"
mysql__mconf_get "$defaults"
@ -509,6 +612,10 @@ function mysql_set_userargs() {
mysql__mconf_get "$dir/my-${dbname}.cnf"
fi
[ ${#userargs[*]} -gt 0 ] || array_add userargs --default-character-set utf8
# initialiser les valeurs par défaut
fix_csv2sql
fix_csv_null
fix_load_data
}
function mysql_set_mysqlargs() {
mysqlargs=()
@ -561,7 +668,26 @@ function mysql_user_update() {
if [ -z "$updateone" ]; then
mysql_before_update "$dbname" || die
fi
cat "$update" | mysql_user_ve || abort_on_error
if [[ "$update" == *.sql ]]; then
# SQL
cat "$update" | mysql_user_ve || abort_on_error
else
# CSV
local truncate table local sql
eval "$(get_csvinfo "$update")"
[ -n "$truncate" ] && sql="truncate table $table;"
[ "$load_data" == local ] && local=1 || local=
sql="${sql}load data${local:+ local} infile '$update' into table \`$table\`
character set 'utf8'
fields terminated by ','
optionally enclosed by '\\\"'
escaped by '\\\\'
lines terminated by '\\n'
starting by ''
ignore 1 lines
($(<"$update" awk '{ print; exit }'));"
echo "$sql" | mysql_user_ve || abort_on_error
fi
if [ -z "$updateone" ]; then
mysql_after_update "$dbname" || die
fi
@ -827,7 +953,7 @@ function oracle_source_adminconf() {
}
function oracle_source_userconf() {
local dir="$1" dbname="$2"
unset ORACLE_SID NLS_LANG ADMINCONNECT USERCONNECT SQLMIGLOG SUFFIX CSV_NULL
unset ORACLE_SID NLS_LANG ADMINCONNECT USERCONNECT SQLMIGLOG SUFFIX CSV2SQL CSV_NULL
setx defaults=oracle_get_defaults "$dir"
[ -f "$defaults" ] && source "$defaults"
[ -f "$dir/ora-${dbname}.conf" ] && source "$dir/ora-${dbname}.conf"
@ -851,10 +977,10 @@ function oracle_source_userconf() {
fi
[ -n "$SQLMIGLOG" ] || SQLMIGLOG="/tmp/sqlmig-${ORACLE_SID}-${dbname}.log"
[ -z "$suffix" ] && suffix="$SUFFIX"
[ -z "$csv_null" ] && {
csv_null="$CSV_NULL"
fix_csv_null
}
[ -z "$csv2sql" ] && csv2sql="$CSV2SQL"
[ -z "$csv_null" ] && csv_null="$CSV_NULL"
fix_csv2sql
fix_csv_null
}
ORACLE_ADMIN_CONF_DONE=
function oracle_admin_update() {
@ -918,7 +1044,9 @@ charset=
oracle_sid=
nls_lang=
suffix=
csv2sql=
csv_null=
load_data=
profile=
type=auto
action=update
@ -946,9 +1074,13 @@ args=(
-s:,--oracle-sid: oracle_sid=
--nls-lang: nls_lang=
--suffix: suffix=
--csv2sql csv2sql=1
--csv-null: csv_null=
--csv-null-empty csv_null=empty
--csv-null-mysql csv_null='\N'
--csv-null-upper csv_null=NULL
--no-csv2sql csv2sql=0
--load-data: load_data=
--profile: profile=
-P,--prod profile=prod
-T,--test profile=test
@ -1059,8 +1191,7 @@ grant all privileges on $dbname.* to '$dbname';"
default-character-set=utf8
[sqlmig]
#suffix=
csv_null="
#suffix="
fi
if [ ! -f "$dbdir/my-${dbname}.cnf" ]; then
@ -1069,7 +1200,12 @@ csv_null="
# Paramètres de connexion pour $dbname
[client]
#user=
#password="
#password=
[sqlmig]
#csv2sql=0
csv_null=
#load-data=default"
fi
elif [ "$type" == oracle ]; then
@ -1110,7 +1246,8 @@ USERCONNECT=$dbname/password
SQLMIGLOG=\"/tmp/sqlmig-\${ORACLE_SID}-${dbname}.log\"
# divers
#SUFFIX=
#CSV_NULL="
#CSV2SQL=0
CSV_NULL="
fi
else
@ -1289,9 +1426,9 @@ function should_update() {
elif [ "${name#maint-}" != "$name" ]; then
# ignorer les opérations de maintenance par défaut
return 1
elif [ "$dbmode" != devel -a "${name%.devel.sql}" != "$name" ]; then
elif [ "$dbmode" != devel -a "${name%.devel.*}" != "$name" ]; then
# si on est en mode autre que devel, le nom ne doit pas se terminer
# par .devel.sql
# par .devel.*
return 1
fi
return 0
@ -1347,13 +1484,16 @@ for dbdir in "${dbdirs[@]}"; do
ensure_dbtype "$dbdir" "$type"
ensure_dbmode "$dbtype" "$mode"
if [ -n "$data_csv" ]; then
# Conversion csv --> sql
array_lsfiles csvs "$dbdir" "*.csv"
if [ "$dbtype" == mysql ]; then
setx defaults=mysql_get_defaults "$dbdir"
set_csv_null=1
mysql__mconf_get "$defaults"
############################################################################
if [ "$dbtype" == mysql ]; then
# construire les paramètres pour mysql
mysql_set_adminargs "$dbdir"
mysql_set_userargs "$dbdir" "$dbname"
mysql_set_mysqlargs
if is_yes "$csv2sql" && [ -n "$data_csv" ]; then
# Conversion csv --> sql
array_lsfiles csvs "$dbdir" "*.csv"
etitled "Conversion"
for csv in "${csvs[@]}"; do
@ -1364,50 +1504,47 @@ for dbdir in "${dbdirs[@]}"; do
fi
estep "$csvname --> ${csvname%.csv}.sql"
script='{
truncate = ($0 ~ /-data_truncate(.devel)?.csv$/)? "1": ""
sub(/^.*\//, "")
sub(/^[A-Z0-9.]*[0-9]-?/, "")
sub(/\.csv$/, "")
sub(/\.devel$/, "")
sub(/-data(_[a-z]+*)?$/, "")
print "truncate=" truncate
gsub(/'\''/, "'\'\\\\\'\''")
print "table='\''" $0 "'\''"
}'
eval "$(awk "$script" <<<"$csvname")"
"$scriptdir/mysqlloadcsv" >"$sql" ${truncate:+-T} -Z "$csv_null" -nIf "$csv" "$table" --prefix "-- -*- coding: utf-8 mode: sql -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8"
eval "$(get_csvinfo "$csvname")"
mysqlloadcsv_args=(
${truncate:+-T}
-Z "$csv_null"
--prefix "-- -*- coding: utf-8 mode: sql -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8"
-nIf "$csv" "$table"
)
"$scriptdir/mysqlloadcsv" "${mysqlloadcsv_args[@]}" >"$sql"
done
eend; eclearp
fi
fi
# lister les mises à jour disponibles
drops=()
creates=()
updates=()
array_lsfiles files "$dbdir" "*.sql"
for file in "${files[@]}"; do
if have_tag drop "$file"; then
array_add drops "$file"
elif have_tag create "$file"; then
array_add creates "$file"
else
array_add updates "$file"
fi
done
############################################################################
if [ "$dbtype" == mysql ]; then
# construire les paramètres pour mysql
mysql_set_adminargs "$dbdir"
mysql_set_userargs "$dbdir" "$dbname"
mysql_set_mysqlargs
# lister les mises à jour disponibles
drops=()
creates=()
updates=()
have_csv=
array_lsfiles files "$dbdir" "*.sql" "*.csv"
for file in "${files[@]}"; do
if [[ "$file" == *.sql ]]; then
if have_tag drop "$file"; then
array_add drops "$file"
elif have_tag create "$file"; then
array_add creates "$file"
else
array_add updates "$file"
fi
elif [ ! -f "${file%.csv}.sql" ]; then
# n'ajouter le CSV que si le fichier SQL correspondant n'existe pas
array_add updates "$file"
have_csv=1
fi
done
if [ -n "$suffix" ]; then
estepi "Suffixe: $dbname --> $dbname$suffix"
dbname="$dbname$suffix"
fi
if is_no "$csv2sql" && [ -n "$have_csv" ]; then
estepi "Chargement des fichiers CSV avec la méthode $load_data"
fi
# Suppression
if [ -n "$drop" ]; then
@ -1449,10 +1586,16 @@ for dbdir in "${dbdirs[@]}"; do
mysql_tbconf "$dbname"
for update in "${updates[@]}"; do
should_update "$update" || continue
if have_tag admin "$update"; then
[ -n "$updatedir" ] && name="${update#$updatedir/}" || name="${update#$dbdir/}"
mysql_admin_update "$name" "$update" "$updateone"
else
if [[ "$update" == *.sql ]]; then
# fichier SQL
if have_tag admin "$update"; then
[ -n "$updatedir" ] && name="${update#$updatedir/}" || name="${update#$dbdir/}"
mysql_admin_update "$name" "$update" "$updateone"
else
mysql_user_update "${update#$dbdir/}" "$update" "$dbname" "$updateone"
fi
elif is_no "$csv2sql"; then
# fichier CSV, ne les traiter que si on est en mode --no-csv2sql
mysql_user_update "${update#$dbdir/}" "$update" "$dbname" "$updateone"
fi
done
@ -1466,6 +1609,28 @@ for dbdir in "${dbdirs[@]}"; do
oracle_source_userconf "$dbdir" "$dbname"
oracle_ensure_opdir
# lister les mises à jour disponibles
drops=()
creates=()
updates=()
have_csv=
array_lsfiles files "$dbdir" "*.sql" "*.csv"
for file in "${files[@]}"; do
if [[ "$file" == *.sql ]]; then
if have_tag drop "$file"; then
array_add drops "$file"
elif have_tag create "$file"; then
array_add creates "$file"
else
array_add updates "$file"
fi
elif [ ! -f "${file%.csv}.sql" ]; then
# n'ajouter le CSV que si le fichier SQL correspondant n'existe pas
array_add updates "$file"
have_csv=1
fi
done
if [ -n "$suffix" ]; then
estepi "Suffixe: $dbname --> $dbname$suffix"
dbname="$dbname$suffix"
@ -1511,11 +1676,14 @@ for dbdir in "${dbdirs[@]}"; do
oracle_tbconf "$dbname"
for update in "${updates[@]}"; do
should_update "$update" || continue
if have_tag admin "$update"; then
[ -n "$updatedir" ] && name="${update#$updatedir/}" || name="${update#$dbdir/}"
oracle_admin_update "$name" "$update" "$updateone"
else
oracle_user_update "${update#$dbdir/}" "$update" "$dbname" "$updateone"
if [[ "$update" == *.sql ]]; then
# fichier SQL
if have_tag admin "$update"; then
[ -n "$updatedir" ] && name="${update#$updatedir/}" || name="${update#$dbdir/}"
oracle_admin_update "$name" "$update" "$updateone"
else
oracle_user_update "${update#$dbdir/}" "$update" "$dbname" "$updateone"
fi
fi
done
eend; eclearp