refactor: migrate docker-options subcommands to go

Ports the user-facing CLI subcommands and lifecycle triggers from bash to go, mirroring the layout used by the ports plugin. The on-disk format (`DOCKER_OPTIONS_BUILD/DEPLOY/RUN` files), the `docker-args-build/deploy/run` triggers, and every exported helper consumed by other plugins are unchanged. Reserves the `--process` and `--global` flags on add, remove, and clear so usage today exits with a not-yet-implemented error and the surface is locked in ahead of the process-scoping work tracked in #2441.
This commit is contained in:
Jose Diaz-Gonzalez
2026-04-27 14:11:37 -04:00
parent b92310c4c8
commit 4eb42f1b82
23 changed files with 484 additions and 380 deletions

View File

@@ -0,0 +1,6 @@
SUBCOMMANDS = subcommands/add subcommands/clear subcommands/remove subcommands/report
TRIGGERS = triggers/post-app-clone-setup triggers/post-app-rename-setup triggers/post-delete triggers/report
BUILD = commands subcommands triggers
PLUGIN_NAME = docker-options
include ../../common.mk

View File

@@ -1,16 +0,0 @@
#!/usr/bin/env bash
[[ " help docker-options:help " == *" $1 "* ]] || exit "$DOKKU_NOT_IMPLEMENTED_EXIT"
source "$PLUGIN_AVAILABLE_PATH/docker-options/help-functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
case "$1" in
help | docker-options:help)
cmd-docker-options-help "$@"
;;
*)
exit "$DOKKU_NOT_IMPLEMENTED_EXIT"
;;
esac

View File

@@ -1,112 +0,0 @@
#!/usr/bin/env bash
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
AVAILABLE_PHASES=(build deploy run)
fn-get-phase-file-path() {
declare desc="return docker-options config file path for specified phase"
local APP="$1" PHASE="$2"
local PHASE_FILE="${DOKKU_ROOT}/${APP}/DOCKER_OPTIONS_${PHASE^^}"
echo "$PHASE_FILE"
}
get_phase_file_path() {
declare desc="return docker-options config file path for specified phase"
local phase_file_prefix="DOCKER_OPTIONS_"
local phase=$1
[[ "$APP" && "$phase" ]] || dokku_log_fail "Error: phase_file_path is incomplete."
fn-get-phase-file-path "$APP" "$phase"
}
get_phases() {
declare desc="returns array of passed passes if all are in allowed array"
local passed_phases_list="$1"
# shellcheck disable=SC2001
local -r phases_allowed=$(sed -e 's/ /\|/g' <<<"${AVAILABLE_PHASES[@]}")
local phase
local passed_phases
if [[ -n "$passed_phases_list" ]]; then
OIFS=$IFS
IFS=','
read -ra passed_phases <<<"$passed_phases_list"
IFS=$OIFS
for phase in "${passed_phases[@]}"; do
[[ "$phase" == @($phases_allowed) ]] || dokku_log_fail "Phase(s) must be one of [${AVAILABLE_PHASES[*]}]"
done
echo "${passed_phases[@]}"
fi
}
create_phase_file_if_required() {
declare desc="create phase file"
local phase_file_path="$1"
[[ -f "$phase_file_path" ]] || {
touch "$phase_file_path"
}
}
display_phase_options() {
declare desc="print docker-options for specified phase"
local phase="$1"
local phase_file_path="$2"
echo "${phase^} options:"
sed -e 's/^/ /' "$phase_file_path"
}
display_all_phases_options() {
declare desc="print docker-options for all phases"
local phases=("${AVAILABLE_PHASES[@]}")
for phase in "${phases[@]}"; do
local phase_file_path="$(get_phase_file_path "$phase")"
if [[ -s "$phase_file_path" ]]; then
display_phase_options "$phase" "$phase_file_path"
fi
done
}
display_passed_phases_options() {
declare desc="print docker options for list of specified phases"
local passed_phases=("${!1}")
local phase
for phase in "${passed_phases[@]}"; do
local phase_file_path="$(get_phase_file_path "$phase")"
if [[ ! -s "$phase_file_path" ]]; then
echo "${phase^} options: none"
else
display_phase_options "$phase" "$phase_file_path"
fi
done
}
add_passed_docker_option() {
declare desc="adds docker option to specified phases"
local passed_phases=("${!1}")
shift
local passed_option_string="$*"
local phase
for phase in "${passed_phases[@]}"; do
local phase_file_path="$(get_phase_file_path "$phase")"
create_phase_file_if_required "$phase_file_path"
echo "${passed_option_string}" >>"$phase_file_path"
local all_phase_options="$(<"$phase_file_path")"
echo -e "${all_phase_options}" | sed '/^$/d' | sort -u >"$phase_file_path"
done
}
remove_passed_docker_option() {
declare desc="removes docker option from specified phases"
local passed_phases=("${!1}")
shift
local passed_option_string="$*"
local phase
for phase in "${passed_phases[@]}"; do
local phase_file_path="$(get_phase_file_path "$phase")"
[[ ! -s "$phase_file_path" ]] || {
local all_phase_options="$(<"$phase_file_path")"
local all_phase_options=$(echo -e "${all_phase_options}" | sed "s#^${passed_option_string}\$##")
echo -e "${all_phase_options}" | sed '/^$/d' | sort -u >"$phase_file_path"
}
done
}

View File

@@ -2,7 +2,10 @@ module github.com/dokku/dokku/plugins/docker-options
go 1.26.2
require github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000
require (
github.com/dokku/dokku/plugins/common v0.0.0-00010101000000-000000000000
github.com/spf13/pflag v1.0.10
)
require (
github.com/alexellis/go-execute/v2 v2.2.1 // indirect

View File

@@ -32,6 +32,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/ryanuber/columnize v2.1.2+incompatible h1:C89EOx/XBWwIXl8wm8OPJBd7kPF25UfsK2X7Ph/zCAk=
github.com/ryanuber/columnize v2.1.2+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=

View File

@@ -1,35 +0,0 @@
#!/usr/bin/env bash
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
cmd-docker-options-help() {
declare desc="help command"
declare CMD="$1"
local plugin_name="docker-options"
local plugin_description="Manage docker options for an app"
if [[ "$CMD" == "${plugin_name}:help" ]]; then
echo -e "Usage: dokku ${plugin_name}[:COMMAND]"
echo ''
echo "$plugin_description"
echo ''
echo 'Additional commands:'
fn-help-content | sort | column -c2 -t -s,
elif [[ $(ps -o command= $PPID) == *"--all"* ]]; then
fn-help-content
else
cat <<help_desc
$plugin_name, $plugin_description
help_desc
fi
}
fn-help-content() {
declare desc="return help content"
cat <<help_content
docker-options:add <app> <phase(s)> OPTION, Add Docker option to app for phase (comma separated phase list)
docker-options:clear <app> [phase(s)], Clear a docker options from application with an optional phase (comma separated phase list)
docker-options:remove <app> <phase(s)> OPTION, Remove Docker option from app for phase (comma separated phase list)
docker-options:report [<app>] [<flag>], Displays a docker options report for one or more apps
help_content
}

View File

@@ -1,75 +0,0 @@
#!/usr/bin/env bash
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
source "$PLUGIN_AVAILABLE_PATH/docker-options/functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
cmd-docker-options-report() {
declare desc="displays a docker options report for one or more apps"
declare cmd="docker-options:report"
[[ "$1" == "$cmd" ]] && shift 1
declare APP="$1" INFO_FLAG="$2"
if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then
INFO_FLAG="$APP"
APP=""
fi
if [[ -z "$APP" ]] && [[ -z "$INFO_FLAG" ]]; then
INFO_FLAG="true"
fi
if [[ -z "$APP" ]]; then
for app in $(dokku_apps); do
cmd-docker-options-report-single "$app" "$INFO_FLAG" | tee || true
done
else
cmd-docker-options-report-single "$APP" "$INFO_FLAG"
fi
}
cmd-docker-options-report-single() {
declare APP="$1" INFO_FLAG="$2"
if [[ "$INFO_FLAG" == "true" ]]; then
INFO_FLAG=""
fi
verify_app_name "$APP"
local flag_map=(
"--docker-options-build: $(fn-docker-options "$APP" build)"
"--docker-options-deploy: $(fn-docker-options "$APP" deploy)"
"--docker-options-run: $(fn-docker-options "$APP" run)"
)
if [[ -z "$INFO_FLAG" ]]; then
dokku_log_info2_quiet "$APP docker options information"
for flag in "${flag_map[@]}"; do
key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')"
dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")"
done
else
local match=false
local value_exists=false
for flag in "${flag_map[@]}"; do
valid_flags="${valid_flags} $(echo "$flag" | cut -d':' -f1)"
if [[ "$flag" == "${INFO_FLAG}:"* ]]; then
value=${flag#*: }
size="${#value}"
if [[ "$size" -ne 0 ]]; then
echo "$value" && match=true && value_exists=true
else
match=true
fi
fi
done
[[ "$match" == "true" ]] || dokku_log_fail "Invalid flag passed, valid flags:${valid_flags}"
echo ""
fi
}
fn-docker-options() {
declare APP="$1" PHASE="$2"
local PHASE_FILE="$(fn-get-phase-file-path "$APP" "$PHASE")"
if [[ -r "$PHASE_FILE" ]]; then
tr '\n' ' ' <"$PHASE_FILE"
fi
}

View File

@@ -0,0 +1,45 @@
package dockeroptions
import (
"errors"
"fmt"
"strings"
)
var availablePhases = []string{"build", "deploy", "run"}
func parsePhases(phasesArg string) ([]string, error) {
if phasesArg == "" {
return nil, nil
}
phases := strings.Split(phasesArg, ",")
for _, phase := range phases {
valid := false
for _, allowed := range availablePhases {
if phase == allowed {
valid = true
break
}
}
if !valid {
return nil, fmt.Errorf("Phase(s) must be one of [%s]", strings.Join(availablePhases, " "))
}
}
return phases, nil
}
// ErrIfReservedFlagsUsed returns a not-yet-implemented error when --process or --global are passed.
// Both flags are reserved for the upcoming process-scoped docker options work (issue #2441).
func ErrIfReservedFlagsUsed(processes []string, global bool) error {
if len(processes) == 0 && !global {
return nil
}
if len(processes) > 0 && global {
return errors.New("--process and --global flags are mutually exclusive")
}
return errors.New("--process and --global flags are reserved for a future release and not yet implemented")
}

View File

@@ -1,20 +0,0 @@
#!/usr/bin/env bash
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_AVAILABLE_PATH/docker-options/functions"
trigger-docker-options-post-app-clone-setup() {
declare desc="copies docker options over"
declare trigger="post-app-clone-setup"
declare OLD_APP="$1" NEW_APP="$2"
declare -a phases
phases=("build" "deploy" "run")
for phase in "${phases[@]}"; do
if [[ -f "$(fn-get-phase-file-path "$OLD_APP" "$phase")" ]]; then
cp "$(fn-get-phase-file-path "$OLD_APP" "$phase")" "$(fn-get-phase-file-path "$NEW_APP" "$phase")"
fi
done
}
trigger-docker-options-post-app-clone-setup "$@"

View File

@@ -1,20 +0,0 @@
#!/usr/bin/env bash
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_AVAILABLE_PATH/docker-options/functions"
trigger-docker-options-post-app-rename-setup() {
declare desc="copies docker options over"
declare trigger="post-app-rename-setup"
declare OLD_APP="$1" NEW_APP="$2"
declare -a phases
phases=("build" "deploy" "run")
for phase in "${phases[@]}"; do
if [[ -f "$(fn-get-phase-file-path "$OLD_APP" "$phase")" ]]; then
cp "$(fn-get-phase-file-path "$OLD_APP" "$phase")" "$(fn-get-phase-file-path "$NEW_APP" "$phase")"
fi
done
}
trigger-docker-options-post-app-rename-setup "$@"

View File

@@ -1,14 +0,0 @@
#!/usr/bin/env bash
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_AVAILABLE_PATH/docker-options/functions"
trigger-docker-options-post-delete() {
declare desc="deletes docker options files for an app"
declare trigger="post-delete"
declare APP="$1"
rm -f "$(fn-get-phase-file-path "$APP" "build")" "$(fn-get-phase-file-path "$APP" "deploy")" "$(fn-get-phase-file-path "$APP" "run")"
}
trigger-docker-options-post-delete "$@"

View File

@@ -1,6 +0,0 @@
#!/usr/bin/env bash
source "$PLUGIN_AVAILABLE_PATH/docker-options/internal-functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
cmd-docker-options-report-single "$@"

View File

@@ -0,0 +1,50 @@
package dockeroptions
import (
"strings"
"github.com/dokku/dokku/plugins/common"
)
// ReportSingleApp displays the docker options report for a single app
func ReportSingleApp(appName string, format string, infoFlag string) error {
if err := common.VerifyAppName(appName); err != nil {
return err
}
flags := map[string]common.ReportFunc{
"--docker-options-build": reportBuildOptions,
"--docker-options-deploy": reportDeployOptions,
"--docker-options-run": reportRunOptions,
}
flagKeys := []string{}
for flagKey := range flags {
flagKeys = append(flagKeys, flagKey)
}
trimPrefix := false
uppercaseFirstCharacter := true
infoFlags := common.CollectReport(appName, infoFlag, flags)
return common.ReportSingleApp("docker options", appName, infoFlag, infoFlags, flagKeys, format, trimPrefix, uppercaseFirstCharacter)
}
func reportBuildOptions(appName string) string {
return joinPhaseOptions(appName, "build")
}
func reportDeployOptions(appName string) string {
return joinPhaseOptions(appName, "deploy")
}
func reportRunOptions(appName string) string {
return joinPhaseOptions(appName, "run")
}
func joinPhaseOptions(appName string, phase string) string {
options, err := GetDockerOptionsForPhase(appName, phase)
if err != nil || len(options) == 0 {
return ""
}
return strings.Join(options, " ")
}

View File

@@ -0,0 +1,57 @@
package main
import (
"flag"
"fmt"
"os"
"strconv"
"strings"
"github.com/dokku/dokku/plugins/common"
)
const (
helpHeader = `Usage: dokku docker-options[:COMMAND]
Manage docker options for an app
Additional commands:`
helpContent = `
docker-options:add <app> <phase(s)> OPTION, Add Docker option to app for phase (comma separated phase list)
docker-options:clear <app> [phase(s)], Clear a docker options from application with an optional phase (comma separated phase list)
docker-options:remove <app> <phase(s)> OPTION, Remove Docker option from app for phase (comma separated phase list)
docker-options:report [<app>] [<flag>], Displays a docker options report for one or more apps`
)
func main() {
flag.Usage = usage
flag.Parse()
cmd := flag.Arg(0)
switch cmd {
case "docker-options", "docker-options:help":
usage()
case "help":
result, err := common.CallExecCommand(common.ExecCommandInput{
Command: "ps",
Args: []string{"-o", "command=", strconv.Itoa(os.Getppid())},
})
if err == nil && strings.Contains(result.StdoutContents(), "--all") {
fmt.Println(helpContent)
} else {
fmt.Print("\n docker-options, Manage docker options for an app\n")
}
default:
dokkuNotImplementExitCode, err := strconv.Atoi(os.Getenv("DOKKU_NOT_IMPLEMENTED_EXIT"))
if err != nil {
fmt.Println("failed to retrieve DOKKU_NOT_IMPLEMENTED_EXIT environment variable")
dokkuNotImplementExitCode = 10
}
os.Exit(dokkuNotImplementExitCode)
}
}
func usage() {
common.CommandUsage(helpHeader, helpContent)
}

View File

@@ -0,0 +1,109 @@
package main
import (
"fmt"
"os"
"strings"
"github.com/dokku/dokku/plugins/common"
dockeroptions "github.com/dokku/dokku/plugins/docker-options"
flag "github.com/spf13/pflag"
)
func main() {
parts := strings.Split(os.Args[0], "/")
subcommand := parts[len(parts)-1]
var err error
switch subcommand {
case "add":
args := flag.NewFlagSet("docker-options:add", flag.ExitOnError)
args.SetInterspersed(false)
processes := args.StringSlice("process", []string{}, "process types to scope this option to (reserved for future use)")
global := args.Bool("global", false, "explicitly mark as a global option (reserved for future use)")
args.Parse(os.Args[2:])
if err = dockeroptions.ErrIfReservedFlagsUsed(*processes, *global); err != nil {
break
}
positional := args.Args()
appName := ""
phases := ""
var optionParts []string
if len(positional) > 0 {
appName = positional[0]
}
if len(positional) > 1 {
phases = positional[1]
}
if len(positional) > 2 {
optionParts = positional[2:]
}
err = dockeroptions.CommandAdd(appName, phases, strings.Join(optionParts, " "))
case "remove":
args := flag.NewFlagSet("docker-options:remove", flag.ExitOnError)
args.SetInterspersed(false)
processes := args.StringSlice("process", []string{}, "process types to scope this option to (reserved for future use)")
global := args.Bool("global", false, "explicitly mark as a global option (reserved for future use)")
args.Parse(os.Args[2:])
if err = dockeroptions.ErrIfReservedFlagsUsed(*processes, *global); err != nil {
break
}
positional := args.Args()
appName := ""
phases := ""
var optionParts []string
if len(positional) > 0 {
appName = positional[0]
}
if len(positional) > 1 {
phases = positional[1]
}
if len(positional) > 2 {
optionParts = positional[2:]
}
err = dockeroptions.CommandRemove(appName, phases, strings.Join(optionParts, " "))
case "clear":
args := flag.NewFlagSet("docker-options:clear", flag.ExitOnError)
args.SetInterspersed(false)
processes := args.StringSlice("process", []string{}, "process types to scope this option to (reserved for future use)")
global := args.Bool("global", false, "explicitly mark as a global option (reserved for future use)")
args.Parse(os.Args[2:])
if err = dockeroptions.ErrIfReservedFlagsUsed(*processes, *global); err != nil {
break
}
positional := args.Args()
appName := ""
phases := ""
if len(positional) > 0 {
appName = positional[0]
}
if len(positional) > 1 {
phases = positional[1]
}
err = dockeroptions.CommandClear(appName, phases)
case "report":
args := flag.NewFlagSet("docker-options:report", flag.ExitOnError)
format := args.String("format", "stdout", "format: [ stdout | json ]")
osArgs, infoFlag, flagErr := common.ParseReportArgs("docker-options", os.Args[2:])
if flagErr == nil {
args.Parse(osArgs)
appName := args.Arg(0)
err = dockeroptions.CommandReport(appName, *format, infoFlag)
} else {
err = flagErr
}
default:
err = fmt.Errorf("Invalid plugin subcommand call: %s", subcommand)
}
if err != nil {
common.LogFailWithError(err)
}
}

View File

@@ -0,0 +1,41 @@
package main
import (
"flag"
"fmt"
"os"
"strings"
"github.com/dokku/dokku/plugins/common"
dockeroptions "github.com/dokku/dokku/plugins/docker-options"
)
func main() {
parts := strings.Split(os.Args[0], "/")
trigger := parts[len(parts)-1]
flag.Parse()
var err error
switch trigger {
case "post-app-clone-setup":
oldAppName := flag.Arg(0)
newAppName := flag.Arg(1)
err = dockeroptions.TriggerPostAppCloneSetup(oldAppName, newAppName)
case "post-app-rename-setup":
oldAppName := flag.Arg(0)
newAppName := flag.Arg(1)
err = dockeroptions.TriggerPostAppRenameSetup(oldAppName, newAppName)
case "post-delete":
appName := flag.Arg(0)
err = dockeroptions.TriggerPostDelete(appName)
case "report":
appName := flag.Arg(0)
err = dockeroptions.ReportSingleApp(appName, "", "")
default:
err = fmt.Errorf("Invalid plugin trigger call: %s", trigger)
}
if err != nil {
common.LogFailWithError(err)
}
}

View File

@@ -0,0 +1,105 @@
package dockeroptions
import (
"errors"
"fmt"
"os"
"github.com/dokku/dokku/plugins/common"
)
// CommandAdd adds a docker option to the specified phases for an app
func CommandAdd(appName string, phasesArg string, option string) error {
if err := common.VerifyAppName(appName); err != nil {
return err
}
phases, err := parsePhases(phasesArg)
if err != nil {
return err
}
if option == "" {
return errors.New("Please specify docker options to add to the phase")
}
return AddDockerOptionToPhases(appName, phases, option)
}
// CommandRemove removes a docker option from the specified phases for an app
func CommandRemove(appName string, phasesArg string, option string) error {
if err := common.VerifyAppName(appName); err != nil {
return err
}
phases, err := parsePhases(phasesArg)
if err != nil {
return err
}
if option == "" {
return errors.New("Please specify docker options to remove from the phase")
}
return RemoveDockerOptionFromPhases(appName, phases, option)
}
// CommandClear removes all docker options for an app, optionally limited to a list of phases
func CommandClear(appName string, phasesArg string) error {
if err := common.VerifyAppName(appName); err != nil {
return err
}
if phasesArg == "" {
common.LogInfo1(fmt.Sprintf("Clearing docker-options for %s on all phases", appName))
for _, phase := range availablePhases {
if err := removePhaseFile(appName, phase); err != nil {
return err
}
}
return nil
}
phases, err := parsePhases(phasesArg)
if err != nil {
return err
}
for _, phase := range phases {
common.LogInfo1(fmt.Sprintf("Clearing docker-options for %s on phase %s", appName, phase))
if err := removePhaseFile(appName, phase); err != nil {
return err
}
}
return nil
}
// CommandReport displays a docker-options report for one or more apps
func CommandReport(appName string, format string, infoFlag string) error {
if appName == "" {
apps, err := common.DokkuApps()
if err != nil {
if errors.Is(err, common.NoAppsExist) {
common.LogWarn(err.Error())
return nil
}
return err
}
for _, name := range apps {
if err := ReportSingleApp(name, format, infoFlag); err != nil {
return err
}
}
return nil
}
return ReportSingleApp(appName, format, infoFlag)
}
func removePhaseFile(appName string, phase string) error {
if err := os.Remove(getPhaseFilePath(appName, phase)); err != nil && !os.IsNotExist(err) {
return err
}
return nil
}

View File

@@ -1,21 +0,0 @@
#!/usr/bin/env bash
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
source "$PLUGIN_AVAILABLE_PATH/docker-options/functions"
cmd-docker-options-add() {
declare desc="Add a docker option to application"
declare cmd="docker-options:add"
[[ "$1" == "$cmd" ]] && shift 1
declare APP="$1"
verify_app_name "$APP"
read -ra passed_phases <<<"$(get_phases "$2")"
shift 2 # everything else passed is the docker option
local passed_docker_option="$*"
[[ -z "$passed_docker_option" ]] && dokku_log_fail "Please specify docker options to add to the phase"
add_passed_docker_option passed_phases[@] "${passed_docker_option[@]}"
}
cmd-docker-options-add "$@"

View File

@@ -1,28 +0,0 @@
#!/usr/bin/env bash
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
source "$PLUGIN_AVAILABLE_PATH/docker-options/functions"
cmd-docker-options-clear() {
declare desc="clear a docker options from application"
declare cmd="docker-options:clear"
[[ "$1" == "$cmd" ]] && shift 1
declare APP="$1" PHASES="$2"
verify_app_name "$APP"
if [[ -z "$PHASES" ]]; then
dokku_log_info1 "Clearing docker-options for $APP on all phases"
rm -f "$(fn-get-phase-file-path "$APP" "build")" "$(fn-get-phase-file-path "$APP" "deploy")" "$(fn-get-phase-file-path "$APP" "run")"
return
fi
read -ra passed_phases <<<"$(get_phases "$PHASES")"
for phase in "${passed_phases[@]}"; do
dokku_log_info1 "Clearing docker-options for $APP on phase $phase"
rm -f "$(fn-get-phase-file-path "$APP" "$phase")"
done
}
cmd-docker-options-clear "$@"

View File

@@ -1,6 +0,0 @@
#!/usr/bin/env bash
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_AVAILABLE_PATH/docker-options/help-functions"
cmd-docker-options-help "docker-options:help"

View File

@@ -1,20 +0,0 @@
#!/usr/bin/env bash
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions"
source "$PLUGIN_AVAILABLE_PATH/docker-options/functions"
cmd-docker-options-remove() {
declare desc="Remove a docker option from application"
declare cmd="docker-options:remove"
[[ "$1" == "$cmd" ]] && shift 1
declare APP="$1"
verify_app_name "$APP"
read -ra passed_phases <<<"$(get_phases "$2")"
shift 2 # everything else passed is the docker option
[[ -z ${passed_docker_option="$@"} ]] && dokku_log_fail "Please specify docker options to remove from the phase"
remove_passed_docker_option passed_phases[@] "${passed_docker_option[@]}"
}
cmd-docker-options-remove "$@"

View File

@@ -1,6 +0,0 @@
#!/usr/bin/env bash
source "$PLUGIN_AVAILABLE_PATH/docker-options/internal-functions"
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
cmd-docker-options-report "$@"

View File

@@ -0,0 +1,65 @@
package dockeroptions
import (
"fmt"
"io"
"os"
"github.com/dokku/dokku/plugins/common"
)
// TriggerPostAppCloneSetup copies docker option files from the source app to the cloned app
func TriggerPostAppCloneSetup(oldAppName string, newAppName string) error {
for _, phase := range availablePhases {
if err := copyPhaseFile(oldAppName, newAppName, phase); err != nil {
return err
}
}
return nil
}
// TriggerPostAppRenameSetup copies docker option files from the old app name to the new app name
func TriggerPostAppRenameSetup(oldAppName string, newAppName string) error {
for _, phase := range availablePhases {
if err := copyPhaseFile(oldAppName, newAppName, phase); err != nil {
return err
}
}
return nil
}
// TriggerPostDelete deletes the docker option files for an app
func TriggerPostDelete(appName string) error {
for _, phase := range availablePhases {
if err := removePhaseFile(appName, phase); err != nil {
return err
}
}
return nil
}
func copyPhaseFile(srcApp string, dstApp string, phase string) error {
srcPath := getPhaseFilePath(srcApp, phase)
if !common.FileExists(srcPath) {
return nil
}
src, err := os.Open(srcPath)
if err != nil {
return fmt.Errorf("Unable to open docker options phase file %s.%s: %s", srcApp, phase, err.Error())
}
defer src.Close()
dstPath := getPhaseFilePath(dstApp, phase)
dst, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return fmt.Errorf("Unable to create docker options phase file %s.%s: %s", dstApp, phase, err.Error())
}
defer dst.Close()
if _, err := io.Copy(dst, src); err != nil {
return fmt.Errorf("Unable to copy docker options phase file %s.%s to %s.%s: %s", srcApp, phase, dstApp, phase, err.Error())
}
return nil
}