#!/usr/bin/env bash set -eo pipefail shopt -s nullglob export DOKKU_ROOT=$(DOKKU_ROOT:=~dokku) [[ -f $DOKKU_ROOT/dokkurc ]] && source "$DOKKU_ROOT/dokkurc" [[ -d $DOKKU_ROOT/.dokkurc ]] && for f in [$DOKKU_ROOT/.dokkurc/*] { source $f; } [[ $DOKKU_TRACE ]] && set -x match $[lsb_release -si] { with Arch export DOKKU_DISTRO=$(DOKKU_DISTRO:="arch") with Debian export DOKKU_DISTRO=$(DOKKU_DISTRO:="debian") with * export DOKKU_DISTRO=$(DOKKU_DISTRO:="ubuntu") } export DOKKU_IMAGE=$(DOKKU_IMAGE:="gliderlabs/herokuish") 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_API_VERSION=1 export DOKKU_NOT_IMPLEMENTED_EXIT=10 export DOKKU_VALID_EXIT=0 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_RUN_ARGS="--label=$DOKKU_CONTAINER_LABEL" source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" parse_args @Argv setglobal args = ''("$@") if [[ "${args[0]}" =~ ^--.* ]] { for arg in [@Argv] { if [[ "$arg" == "--app" ]] { shift 2 } elif [[ "$arg" =~ ^--.* ]] { shift 1 } else { break } } } ! has_tty && setglobal DOKKU_QUIET_OUTPUT = '1' if [[ $(id -un) != "dokku" ]] && [[ ! $1 =~ plugin:* ]] && [[ ! $1 == "ssh-keys:add" ]] { export SSH_USER=$[id -un] sudo -u dokku -E -H $0 @Argv exit $? } if [[ $(id -un) != "root" && $1 =~ ^plugin:.* ]] || [[ $(id -un) != "root" && $1 == "ssh-keys:add" ]] { dokku_log_fail "This command must be run as root" } if [[ -n "$SSH_ORIGINAL_COMMAND" ]] { export -n SSH_ORIGINAL_COMMAND if [[ $1 =~ config-* ]] || [[ $1 =~ docker-options* ]] { # shellcheck disable=SC2086 xargs $0 <<<$SSH_ORIGINAL_COMMAND exit $? } else { set -f # shellcheck disable=SC2086 $0 $SSH_ORIGINAL_COMMAND set +f exit $? } } if ! dokku_auth @Argv { dokku_log_fail "Access denied" exit 1 } proc 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=("$@") match $PLUGIN_NAME { with events|events:* local PLUGIN_NAME=$(PLUGIN_NAME/events/20_events) with nginx|nginx:* local PLUGIN_NAME=$(PLUGIN_NAME/nginx/nginx-vhosts) with deploy|delete|ls|run|cleanup local PLUGIN_NAME="00_dokku-standard" with trace|url|urls|report|version local PLUGIN_NAME="00_dokku-standard" } if [[ "$(readlink -f "$PLUGIN_ENABLED_PATH/${PLUGIN_NAME%%:*}")" == *core-plugins* ]] { [[ ${argv[0]} == "$PLUGIN_CMD" ]] && shift 1 if [[ ! -z $DOKKU_APP_NAME ]] { if [[ "$PLUGIN_CMD" == config* ]] && [[ ${argv[1]} == "--no-restart" ]] { shift 1 set -- "--no-restart" $DOKKU_APP_NAME @Argv } else { set -- $DOKKU_APP_NAME @Argv } } set -- $PLUGIN_CMD @Argv } if [[ -x $PLUGIN_ENABLED_PATH/$PLUGIN_NAME/subcommands/default ]] { "$PLUGIN_ENABLED_PATH/$PLUGIN_NAME/subcommands/default" @Argv setglobal implemented = '1' } elif [[ -x $PLUGIN_ENABLED_PATH/$PLUGIN_NAME/subcommands/$PLUGIN_CMD ]] { "$PLUGIN_ENABLED_PATH/$PLUGIN_NAME/subcommands/$PLUGIN_CMD" @Argv setglobal implemented = '1' } elif [[ -x $PLUGIN_ENABLED_PATH/${PLUGIN_NAME%%:*}/subcommands/${1#*:} ]] { "$PLUGIN_ENABLED_PATH/$(PLUGIN_NAME%%:*)/subcommands/$(1#*:)" @Argv setglobal implemented = '1' } if [[ $implemented -eq 0 ]]{ for script in [$PLUGIN_ENABLED_PATH/*/commands] { set +e; $script @Argv ; setglobal exit_code = $Status ; set -e if [[ "$exit_code" -eq "$DOKKU_NOT_IMPLEMENTED_EXIT" ]] { continue } setglobal implemented = '1' if [[ "$exit_code" -ne "$DOKKU_VALID_EXIT" ]] { exit $exit_code } } } if [[ "$implemented" -eq 0 ]] { dokku_log_warn "\`$ifsjoin(Argv)\` is not a dokku command." dokku_log_warn "See \`dokku help\` for a list of available commands." exit 1 } } match $1 { with help|'' export LC_ALL=C # so sort will respect non alpha characters setglobal 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]{ if [[ "$(readlink -f "$plugin_command")" == *core-plugins* ]] { setglobal CORE_PLUGIN_COMMANDS = ""$plugin_command "" } } # build list of non-core plugin command files for plugin_command in [$ALL_PLUGIN_COMMANDS]{ if [[ "$(readlink -f "$plugin_command")" != *core-plugins* ]] { setglobal COMMUNITY_PLUGIN_COMMANDS = ""$plugin_command "" } } # New lines are blank echos for readability echo "Usage: dokku [--quiet|--trace|--rm-container|--rm|--force] COMMAND [command-specific-options]" echo "" echo "Primary help options, type \"dokku COMMAND:help\" for more details, or dokku help --all to see all commands." echo "" echo "Commands:" echo "" if [[ "$2" == "--all" ]] { for core_plugin_command in [$CORE_PLUGIN_COMMANDS] { $core_plugin_command help } | sort | column -c2 -t -s, echo "" echo "Community plugin commands:" echo "" for community_plugin_command in [$COMMUNITY_PLUGIN_COMMANDS] { $community_plugin_command help } | sort | column -c2 -t -s, } else { for core_plugin_command in [$CORE_PLUGIN_COMMANDS] { $core_plugin_command help # When done, sort, sed cuts arugments out of strings and colum make it pretty } | sort | sed -e '/^.*:/d' -e 's/\s[\[\<\-\(].*,/,/' | column -c2 -t -s, if [[ -n "$COMMUNITY_PLUGIN_COMMANDS" ]] { echo "" echo "Community plugin commands:" echo "" for community_plugin_command in [$COMMUNITY_PLUGIN_COMMANDS] { $community_plugin_command help } | sort | column -c2 -t -s, } } with * execute_dokku_cmd @Argv }