When setting the `--app` flag, there was a special case for the config plugin. This plugin used to take the `--no-restart` flag as the first argument - and still did until this change - resulting in an invalid call to the plugin subcommands. What is worse is that this functionality carried over to all other plugins as they were rewritten in golang, and thus the issue spread without us knowing. The fix is to support GNU flag parsing rules, which Golang does not do by default (Because Of Reasons™). Switching to `github.com/spf13/pflag` fixes this issue, and also allows positional arguments to be placed wherever, even in the middle of flags. Closes #4255
254 lines
7.8 KiB
Bash
Executable File
254 lines
7.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -eo pipefail
|
|
shopt -s nullglob
|
|
|
|
export DOCKER_BIN=docker
|
|
if [[ -r /etc/default/dokku ]]; then
|
|
# shellcheck disable=SC1091
|
|
source /etc/default/dokku
|
|
fi
|
|
|
|
export DOKKU_ROOT=${DOKKU_ROOT:=~dokku}
|
|
if [[ -f "$DOKKU_ROOT/dokkurc" ]]; then
|
|
if [[ -r $DOKKU_ROOT/dokkurc ]]; then
|
|
source "$DOKKU_ROOT/dokkurc"
|
|
else
|
|
echo "Unable to read $DOKKU_ROOT/dokkurc for sourcing" 1>&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
if [[ -d $DOKKU_ROOT/.dokkurc ]]; then
|
|
for f in $DOKKU_ROOT/.dokkurc/*; do
|
|
if [[ -r "$f" ]]; then
|
|
source "$f"
|
|
else
|
|
echo "Unable to read $f for sourcing" 1>&2
|
|
exit 1
|
|
fi
|
|
done
|
|
fi
|
|
[[ $DOKKU_TRACE ]] && set -x
|
|
export DOKKU_HOST_ROOT=${DOKKU_HOST_ROOT:=$DOKKU_ROOT}
|
|
|
|
export DOKKU_DISTRO
|
|
# shellcheck disable=SC1091
|
|
DOKKU_DISTRO=$(
|
|
. /etc/os-release >/dev/null 2>&1 || true
|
|
echo "$ID"
|
|
)
|
|
|
|
# Specify twice so that only host-level
|
|
# configuration can ever override the DOCKER_BIN value
|
|
export DOCKER_BIN=${DOCKER_BIN:="docker"}
|
|
|
|
export DOKKU_IMAGE=${DOKKU_IMAGE:="gliderlabs/herokuish:latest"}
|
|
export DOKKU_LIB_ROOT=${DOKKU_LIB_PATH:="/var/lib/dokku"}
|
|
|
|
export PLUGIN_PATH=${PLUGIN_PATH:="$DOKKU_LIB_ROOT/plugins"}
|
|
export PLUGIN_AVAILABLE_PATH=${PLUGIN_AVAILABLE_PATH:="$PLUGIN_PATH/available"}
|
|
export PLUGIN_ENABLED_PATH=${PLUGIN_ENABLED_PATH:="$PLUGIN_PATH/enabled"}
|
|
export PLUGIN_CORE_PATH=${PLUGIN_CORE_PATH:="$DOKKU_LIB_ROOT/core-plugins"}
|
|
export PLUGIN_CORE_AVAILABLE_PATH=${PLUGIN_CORE_AVAILABLE_PATH:="$PLUGIN_CORE_PATH/available"}
|
|
export PLUGIN_CORE_ENABLED_PATH=${PLUGIN_CORE_ENABLED_PATH:="$PLUGIN_CORE_PATH/enabled"}
|
|
export DOKKU_SYSTEM_GROUP=${DOKKU_SYSTEM_GROUP:="dokku"}
|
|
export DOKKU_SYSTEM_USER=${DOKKU_SYSTEM_USER:="dokku"}
|
|
|
|
export DOKKU_API_VERSION=1
|
|
export DOKKU_NOT_IMPLEMENTED_EXIT=10
|
|
export DOKKU_VALID_EXIT=0
|
|
export DOKKU_PID="$BASHPID"
|
|
|
|
export DOKKU_LOGS_DIR=${DOKKU_LOGS_DIR:="/var/log/dokku"}
|
|
export DOKKU_EVENTS_LOGFILE=${DOKKU_EVENTS_LOGFILE:="$DOKKU_LOGS_DIR/events.log"}
|
|
|
|
export DOKKU_CONTAINER_LABEL=dokku
|
|
export DOKKU_GLOBAL_BUILD_ARGS="--label=org.label-schema.schema-version=1.0 --label=org.label-schema.vendor=dokku --label=$DOKKU_CONTAINER_LABEL"
|
|
export DOKKU_GLOBAL_RUN_ARGS="--label=org.label-schema.schema-version=1.0 --label=org.label-schema.vendor=dokku --label=$DOKKU_CONTAINER_LABEL"
|
|
|
|
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
|
|
|
|
parse_args "$@"
|
|
args=("$@")
|
|
skip_arg=false
|
|
if [[ "${args[0]}" =~ ^--.* ]]; then
|
|
for arg in "$@"; do
|
|
$skip_arg && skip_arg=false && continue
|
|
if [[ "$arg" == "--version" ]]; then
|
|
continue
|
|
fi
|
|
if [[ "$arg" == "--app" ]]; then
|
|
shift 2 && skip_arg=true
|
|
elif [[ "$arg" =~ ^--.* ]]; then
|
|
shift 1
|
|
else
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
! has_tty && DOKKU_QUIET_OUTPUT=1
|
|
|
|
if [[ $(id -un) != "dokku" ]] && [[ ! $1 =~ plugin:* ]] && [[ $1 != "ssh-keys:add" ]] && [[ $1 != "ssh-keys:remove" ]]; then
|
|
export SSH_USER=$(id -un)
|
|
sudo -u dokku -E -H "$0" "$@"
|
|
exit $?
|
|
fi
|
|
|
|
if [[ $1 =~ ^plugin:.* && $1 != "plugin:help" && $1 != "plugin:list" ]] || [[ $1 == "ssh-keys:add" ]] || [[ $1 == "ssh-keys:remove" ]]; then
|
|
if [[ $(id -un) != "root" ]]; then
|
|
dokku_log_fail "This command must be run as root"
|
|
else
|
|
export SSH_USER=root
|
|
fi
|
|
fi
|
|
|
|
if [[ -n "$SSH_ORIGINAL_COMMAND" ]]; then
|
|
export -n SSH_ORIGINAL_COMMAND
|
|
if [[ $1 =~ config-* ]] || [[ $1 =~ docker-options* ]]; then
|
|
# shellcheck disable=SC2086
|
|
xargs $0 <<<$SSH_ORIGINAL_COMMAND
|
|
exit $?
|
|
else
|
|
set -f
|
|
# shellcheck disable=SC2086
|
|
$0 $SSH_ORIGINAL_COMMAND
|
|
set +f
|
|
exit $?
|
|
fi
|
|
fi
|
|
|
|
if ! dokku_auth "$@"; then
|
|
dokku_log_fail "Access denied"
|
|
exit 1
|
|
fi
|
|
|
|
execute_dokku_cmd() {
|
|
declare desc="executes dokku sub-commands"
|
|
local PLUGIN_NAME="$1"
|
|
local PLUGIN_CMD=$PLUGIN_NAME
|
|
local implemented=0
|
|
local script
|
|
local argv=("$@")
|
|
|
|
case "$PLUGIN_NAME" in
|
|
events | events:*)
|
|
local PLUGIN_NAME=${PLUGIN_NAME/events/20_events}
|
|
;;
|
|
nginx | nginx:*)
|
|
local PLUGIN_NAME=${PLUGIN_NAME/nginx/nginx-vhosts}
|
|
;;
|
|
deploy | run | cleanup | url | urls | report)
|
|
local PLUGIN_NAME="00_dokku-standard"
|
|
;;
|
|
esac
|
|
|
|
if [[ "$(readlink -f "$PLUGIN_ENABLED_PATH/${PLUGIN_NAME%%:*}")" == *core-plugins* ]]; then
|
|
[[ ${argv[0]} == "$PLUGIN_CMD" ]] && shift 1
|
|
if [[ -n $DOKKU_APP_NAME ]]; then
|
|
set -- "$DOKKU_APP_NAME" "$@"
|
|
fi
|
|
set -- "$PLUGIN_CMD" "$@"
|
|
fi
|
|
|
|
if [[ -x $PLUGIN_ENABLED_PATH/$PLUGIN_NAME/subcommands/default ]]; then
|
|
"$PLUGIN_ENABLED_PATH/$PLUGIN_NAME/subcommands/default" "$@"
|
|
implemented=1
|
|
elif [[ -x $PLUGIN_ENABLED_PATH/$PLUGIN_NAME/subcommands/$PLUGIN_CMD ]]; then
|
|
"$PLUGIN_ENABLED_PATH/$PLUGIN_NAME/subcommands/$PLUGIN_CMD" "$@"
|
|
implemented=1
|
|
elif [[ -x $PLUGIN_ENABLED_PATH/${PLUGIN_NAME%%:*}/subcommands/${1#*:} ]] && [[ -n "${1#*:}" ]]; then
|
|
"$PLUGIN_ENABLED_PATH/${PLUGIN_NAME%%:*}/subcommands/${1#*:}" "$@"
|
|
implemented=1
|
|
fi
|
|
|
|
if [[ $implemented -eq 0 ]]; then
|
|
for script in $PLUGIN_ENABLED_PATH/*/commands; do
|
|
set +e
|
|
$script "$@"
|
|
exit_code=$?
|
|
set -e
|
|
if [[ "$exit_code" -eq "$DOKKU_NOT_IMPLEMENTED_EXIT" ]]; then
|
|
continue
|
|
fi
|
|
implemented=1
|
|
if [[ "$exit_code" -ne "$DOKKU_VALID_EXIT" ]]; then
|
|
exit $exit_code
|
|
fi
|
|
done
|
|
fi
|
|
|
|
if [[ "$implemented" -eq 0 ]]; then
|
|
dokku_log_warn "\`$*\` is not a dokku command."
|
|
dokku_log_warn "See \`dokku help\` for a list of available commands."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
case "$1" in
|
|
help | '')
|
|
export LC_ALL=C # so sort will respect non alpha characters
|
|
ALL_PLUGIN_COMMANDS=$(find -L "$PLUGIN_PATH/enabled" -name commands 2>/dev/null || true)
|
|
|
|
# build list of core plugin command files
|
|
for plugin_command in $ALL_PLUGIN_COMMANDS; do
|
|
if [[ "$(readlink -f "$plugin_command")" == *core-plugins* ]]; then
|
|
CORE_PLUGIN_COMMANDS+="$plugin_command "
|
|
fi
|
|
done
|
|
# build list of non-core plugin command files
|
|
for plugin_command in $ALL_PLUGIN_COMMANDS; do
|
|
if [[ "$(readlink -f "$plugin_command")" != *core-plugins* ]]; then
|
|
COMMUNITY_PLUGIN_COMMANDS+="$plugin_command "
|
|
fi
|
|
done
|
|
|
|
# New lines are blank echos for readability
|
|
dokku_log_quiet "Usage: dokku [--quiet|--trace|--rm-container|--rm|--force] COMMAND <app> [command-specific-options]"
|
|
dokku_log_quiet ""
|
|
dokku_log_quiet "Primary help options, type \"dokku COMMAND:help\" for more details, or dokku help --all to see all commands."
|
|
dokku_log_quiet ""
|
|
dokku_log_quiet "Commands:"
|
|
dokku_log_quiet ""
|
|
|
|
if [[ "$2" == "--all" ]]; then
|
|
for core_plugin_command in $CORE_PLUGIN_COMMANDS; do
|
|
$core_plugin_command help
|
|
done | sort | column -c2 -t -s,
|
|
dokku_log_quiet ""
|
|
dokku_log_quiet "Community plugin commands:"
|
|
dokku_log_quiet ""
|
|
for community_plugin_command in $COMMUNITY_PLUGIN_COMMANDS; do
|
|
$community_plugin_command help
|
|
done | sort | column -c2 -t -s,
|
|
else
|
|
for core_plugin_command in $CORE_PLUGIN_COMMANDS; do
|
|
$core_plugin_command help
|
|
# When done, sort, sed cuts arugments out of strings and colum make it pretty
|
|
done | sort | sed -e '/^.*:/d' -e 's/\s[\[\<\-\(].*,/,/' | column -c2 -t -s,
|
|
if [[ -n "$COMMUNITY_PLUGIN_COMMANDS" ]]; then
|
|
dokku_log_quiet ""
|
|
dokku_log_quiet "Community plugin commands:"
|
|
dokku_log_quiet ""
|
|
for community_plugin_command in $COMMUNITY_PLUGIN_COMMANDS; do
|
|
$community_plugin_command help
|
|
done | sort | column -c2 -t -s,
|
|
fi
|
|
fi
|
|
;;
|
|
|
|
version | -v | --version)
|
|
if [[ -f "$DOKKU_LIB_ROOT/STABLE_VERSION" ]]; then
|
|
DOKKU_VERSION=$(cat "${DOKKU_LIB_ROOT}/STABLE_VERSION")
|
|
elif [[ -f "$DOKKU_LIB_ROOT/VERSION" ]]; then
|
|
DOKKU_VERSION=$(cat "${DOKKU_LIB_ROOT}/VERSION")
|
|
else
|
|
dokku_log_fail "Unable to determine dokku's version"
|
|
fi
|
|
echo "dokku version ${DOKKU_VERSION}"
|
|
;;
|
|
|
|
*)
|
|
execute_dokku_cmd "$@"
|
|
;;
|
|
|
|
esac
|