A stack is a directory of compose files; the current directory is a stack when it holds one. The same command works for a project, a catalogue stack, a group and a host singleton, and stacks sharing a project are now a single compose call. Two traps of the make engine are closed on the way: an unknown command is an error instead of a silent success, and a group is only expanded when its name is lowercase, so an environment variable can no longer be mistaken for one. That guard spells out its character class because a-z matches uppercase too under a dictionary collation.
75 lines
2.9 KiB
Bash
75 lines
2.9 KiB
Bash
#shellcheck shell=sh
|
|
# The commands that map straight onto docker compose.
|
|
#
|
|
# Stacks are grouped by compose project: every host stack shares the project of
|
|
# the machine, so `myos up host` is a single compose call with every file, the
|
|
# way the stack was meant to be described.
|
|
|
|
# myos_cmd_compose COMMAND
|
|
myos_cmd_compose() {
|
|
_cmd=$1
|
|
_projects=
|
|
_rc=0
|
|
|
|
for _ref in $MYOS_STACKS; do
|
|
_files=$(myos_stack_compose_files "$_ref") || { _rc=$MYOS_E_NOSTACK; continue; }
|
|
[ -n "$_files" ] || { myos_warning "no compose file for stack $_ref"; continue; }
|
|
_scope=$(myos_scope "$_ref")
|
|
_app=$(myos_stack_name "$_ref")
|
|
case $_ref in .|./*|/*|../*) _app=$(basename "$(myos_stack_resolve "$_ref")") ;; esac
|
|
_project=$(myos_project_name "$_scope" "$USER" "$ENV" "$_app")
|
|
# accumulate the files of every stack sharing a project, keeping the order
|
|
_projects=$(printf '%s\n%s\t%s' "$_projects" "$_project" "$(printf '%s' "$_files" | tr '\n' ' ')")
|
|
done
|
|
|
|
[ "$_rc" = 0 ] || return "$_rc"
|
|
|
|
for _project in $(printf '%s' "$_projects" | sed '/^$/d' | cut -f1 | awk '!seen[$0]++'); do
|
|
_files=$(printf '%s' "$_projects" | sed '/^$/d' | awk -F'\t' -v p="$_project" '$1==p {print $2}' | tr ' ' '\n' | sed '/^$/d' | awk '!seen[$0]++')
|
|
# the framework networks always come last, as the make engine did
|
|
[ -f "$MYOS_ROOT/share/compose/networks.yml" ] &&
|
|
_files="$_files
|
|
$MYOS_ROOT/share/compose/networks.yml"
|
|
|
|
COMPOSE_PROJECT_NAME=$_project
|
|
COMPOSE_SERVICE_NAME=$(myos_service_name "$_project")
|
|
DOCKER_NETWORK_DEFAULT=${DOCKER_NETWORK_DEFAULT:-$(myos_network_default "$_project")}
|
|
DOCKER_NETWORK_PRIVATE=$(myos_network_private "$USER" "$ENV")
|
|
# shellcheck disable=SC3028 # HOSTNAME is set by bin/myos, not by the shell
|
|
DOCKER_NETWORK_PUBLIC=$(myos_network_public "$HOSTNAME")
|
|
export COMPOSE_PROJECT_NAME COMPOSE_SERVICE_NAME
|
|
export DOCKER_NETWORK_DEFAULT DOCKER_NETWORK_PRIVATE DOCKER_NETWORK_PUBLIC
|
|
|
|
case $_cmd in
|
|
up) myos_network_ensure "$DOCKER_NETWORK_PRIVATE" "$DOCKER_NETWORK_PUBLIC" ;;
|
|
esac
|
|
|
|
# shellcheck disable=SC2086,SC2046 # options and MYOS_ARGS are word lists
|
|
myos_compose "$_project" "$_files" -- "$_cmd" $(myos_compose_options "$_cmd") ${MYOS_ARGS:-} || _rc=$?
|
|
done
|
|
return "$_rc"
|
|
}
|
|
|
|
# myos_compose_options COMMAND the default options of each compose command
|
|
myos_compose_options() {
|
|
case $1 in
|
|
up) printf '%s' "${DOCKER_COMPOSE_UP_OPTIONS:--d}" ;;
|
|
logs) printf '%s' "${DOCKER_COMPOSE_LOGS_OPTIONS:---follow --tail=100}" ;;
|
|
down) printf '%s' "${DOCKER_COMPOSE_DOWN_OPTIONS:-}" ;;
|
|
*) printf '' ;;
|
|
esac
|
|
}
|
|
|
|
# myos_network_ensure NAME... create the external networks if they are missing
|
|
myos_network_ensure() {
|
|
for _n in "$@"; do
|
|
[ -n "$_n" ] || continue
|
|
if [ "${DRYRUN:-false}" = true ]; then
|
|
printf 'docker network create %s\n' "$_n"
|
|
else
|
|
docker network inspect "$_n" >/dev/null 2>&1 || myos_run docker network create "$_n" >/dev/null
|
|
fi
|
|
done
|
|
return 0
|
|
}
|