diff --git a/plugins/common/common.go b/plugins/common/common.go index 4039fe7d2..091f15451 100644 --- a/plugins/common/common.go +++ b/plugins/common/common.go @@ -581,6 +581,11 @@ func VerifyAppName(appName string) error { return &AppDoesNotExist{appName} } + apps, _ := filterApps([]string{appName}) + if len(apps) != 1 { + return &AppDoesNotExist{appName} + } + return nil } diff --git a/plugins/common/common_test.go b/plugins/common/common_test.go index 3e31967e1..6f30e385d 100644 --- a/plugins/common/common_test.go +++ b/plugins/common/common_test.go @@ -20,6 +20,10 @@ var ( testEnvLine2 = "export testKey=TESTING" ) +func setupTests() (err error) { + return os.Setenv("PLUGIN_ENABLED_PATH", "/var/lib/dokku/plugins/enabled") +} + func setupTestApp() (err error) { Expect(os.MkdirAll(testAppDir, 0644)).To(Succeed()) b := []byte(testEnvLine + "\n") @@ -48,32 +52,37 @@ func teardownTestApp2() { func TestCommonGetEnv(t *testing.T) { RegisterTestingT(t) + Expect(setupTests()).To(Succeed()) Expect(MustGetEnv("DOKKU_ROOT")).To(Equal("/home/dokku")) } func TestCommonGetAppImageRepo(t *testing.T) { RegisterTestingT(t) + Expect(setupTests()).To(Succeed()) Expect(GetAppImageRepo("testapp")).To(Equal("dokku/testapp")) } func TestCommonVerifyImageInvalid(t *testing.T) { RegisterTestingT(t) + Expect(setupTests()).To(Succeed()) Expect(VerifyImage("testapp")).To(Equal(false)) } func TestCommonVerifyAppNameInvalid(t *testing.T) { RegisterTestingT(t) - err := VerifyAppName("1994testApp") - Expect(err).To(HaveOccurred()) + Expect(setupTests()).To(Succeed()) + Expect(VerifyAppName("1994testApp")).To(HaveOccurred()) } func TestCommonVerifyAppName(t *testing.T) { RegisterTestingT(t) + Expect(setupTests()).To(Succeed()) Expect(setupTestApp()).To(Succeed()) Expect(VerifyAppName(testAppName)).To(Succeed()) teardownTestApp() RegisterTestingT(t) + Expect(setupTests()).To(Succeed()) Expect(setupTestApp2()).To(Succeed()) Expect(VerifyAppName(testAppName2)).To(Succeed()) teardownTestApp2() @@ -81,13 +90,14 @@ func TestCommonVerifyAppName(t *testing.T) { func TestCommonDokkuAppsError(t *testing.T) { RegisterTestingT(t) + Expect(setupTests()).To(Succeed()) _, err := DokkuApps() Expect(err).To(HaveOccurred()) } func TestCommonDokkuApps(t *testing.T) { RegisterTestingT(t) - os.Setenv("PLUGIN_ENABLED_PATH", "/var/lib/dokku/plugins/enabled") + Expect(setupTests()).To(Succeed()) Expect(setupTestApp()).To(Succeed()) apps, err := DokkuApps() Expect(err).NotTo(HaveOccurred()) @@ -98,6 +108,7 @@ func TestCommonDokkuApps(t *testing.T) { func TestCommonStripInlineComments(t *testing.T) { RegisterTestingT(t) + Expect(setupTests()).To(Succeed()) text := StripInlineComments(strings.Join([]string{testEnvLine, "# testing comment"}, " ")) Expect(text).To(Equal(testEnvLine)) } diff --git a/plugins/common/functions b/plugins/common/functions index 181fccb27..98237caf5 100755 --- a/plugins/common/functions +++ b/plugins/common/functions @@ -250,23 +250,12 @@ is_valid_app_name_old() { verify_app_name() { declare desc="verify app name format and app existence" declare APP="$1" - local VALID_NEW=false - local VALID_OLD=false - if fn-is-valid-app-name "$APP" 2>/dev/null; then - VALID_NEW=true + + if "$PLUGIN_CORE_AVAILABLE_PATH/common/common" --quiet verify-app-name "$APP"; then + return 0 fi - if fn-is-valid-app-name-old "$APP" 2>/dev/null; then - VALID_OLD=true - fi - - if [[ "$VALID_NEW" == "false" ]] && [[ "$VALID_OLD" == "false" ]]; then - dokku_log_fail "App name must begin with lowercase alphanumeric character, and cannot include uppercase characters, colons, or underscores" - fi - - [[ ! -d "$DOKKU_ROOT/$APP" ]] && DOKKU_FAIL_EXIT_CODE=20 dokku_log_fail "App $APP does not exist" - - return 0 + DOKKU_FAIL_EXIT_CODE=20 dokku_log_fail "App $APP does not exist" } verify_image() { diff --git a/plugins/common/log.go b/plugins/common/log.go index d45f26e48..dec3791b1 100644 --- a/plugins/common/log.go +++ b/plugins/common/log.go @@ -61,6 +61,19 @@ func LogFailWithError(err error) { os.Exit(1) } +// LogFailWithErrorQuiet is the failure log formatter (with quiet option) +// prints text to stderr and exits with the specified exit code +// The error message is not printed if DOKKU_QUIET_OUTPUT has any value +func LogFailWithErrorQuiet(err error) { + if os.Getenv("DOKKU_QUIET_OUTPUT") == "" { + fmt.Fprintln(os.Stderr, fmt.Sprintf(" ! %s", err.Error())) + } + if errExit, ok := err.(ErrWithExitCode); ok { + os.Exit(errExit.ExitCode()) + } + os.Exit(1) +} + // LogFailQuiet is the failure log formatter (with quiet option) // prints text to stderr and exits with status 1 func LogFailQuiet(text string) { diff --git a/plugins/common/src/common/common.go b/plugins/common/src/common/common.go index 432aa00e8..4b4c078dc 100644 --- a/plugins/common/src/common/common.go +++ b/plugins/common/src/common/common.go @@ -38,11 +38,14 @@ func main() { appName = "--global" } fmt.Print(common.GetAppScheduler(appName)) + case "verify-app-name": + appName := flag.Arg(1) + err = common.VerifyAppName(appName) default: err = fmt.Errorf("Invalid common command call: %v", cmd) } if err != nil { - common.LogFailQuiet(err.Error()) + common.LogFailWithErrorQuiet(err) } } diff --git a/plugins/config/Makefile b/plugins/config/Makefile index 7be217943..6a4bef9ec 100644 --- a/plugins/config/Makefile +++ b/plugins/config/Makefile @@ -1,6 +1,12 @@ SUBCOMMANDS = subcommands/bundle subcommands/clear subcommands/export subcommands/get subcommands/keys subcommands/show subcommands/set subcommands/unset TRIGGERS = triggers/config-export triggers/config-get triggers/config-get-global -BUILD = commands subcommands triggers +BUILD = commands config_sub subcommands triggers PLUGIN_NAME = config +clean-config_sub: + rm -rf config_sub + +config_sub: clean-config_sub **/**/config_sub.go + go build -ldflags="-s -w" $(GO_ARGS) -o config_sub src/config_sub/config_sub.go + include ../../common.mk diff --git a/plugins/config/config_test.go b/plugins/config/config_test.go index ff2502fd2..769132c80 100644 --- a/plugins/config/config_test.go +++ b/plugins/config/config_test.go @@ -18,6 +18,10 @@ var ( globalConfigFile = strings.Join([]string{dokkuRoot, "ENV"}, "/") ) +func setupTests() (err error) { + return os.Setenv("PLUGIN_ENABLED_PATH", "/var/lib/dokku/plugins/enabled") +} + func setupTestApp() (err error) { Expect(os.MkdirAll(testAppDir, 0766)).To(Succeed()) b := []byte("export testKey=TESTING\n") @@ -38,6 +42,7 @@ func teardownTestApp() { func TestConfigGetWithDefault(t *testing.T) { RegisterTestingT(t) + Expect(setupTests()).To(Succeed()) Expect(setupTestApp()).To(Succeed()) Expect(GetWithDefault(testAppName, "unknownKey", "UNKNOWN")).To(Equal("UNKNOWN")) Expect(GetWithDefault(testAppName, "testKey", "testKey")).To(Equal("TESTING")) @@ -47,6 +52,7 @@ func TestConfigGetWithDefault(t *testing.T) { func TestConfigGet(t *testing.T) { RegisterTestingT(t) + Expect(setupTests()).To(Succeed()) Expect(setupTestApp()).To(Succeed()) defer teardownTestApp() @@ -59,45 +65,48 @@ func TestConfigGet(t *testing.T) { func TestConfigSetMany(t *testing.T) { RegisterTestingT(t) + Expect(setupTests()).To(Succeed()) Expect(setupTestApp()).To(Succeed()) defer teardownTestApp() expectValue(testAppName, "testKey", "TESTING") - vals := map[string]string{"testKey": "updated", "testKey2": "new"} - Expect(SetMany(testAppName, vals, false)).To(Succeed()) + vals := []string{"testKey=updated", "testKey2=new"} + Expect(CommandSet(testAppName, vals, false, true, false)).To(Succeed()) expectValue(testAppName, "testKey", "updated") expectValue(testAppName, "testKey2", "new") - vals = map[string]string{"testKey": "updated_global", "testKey2": "new_global"} - Expect(SetMany("", vals, false)).To(Succeed()) + vals = []string{"testKey=updated_global", "testKey2=new_global"} + Expect(CommandSet("", vals, true, true, false)).To(Succeed()) expectValue("", "testKey", "updated_global") expectValue("", "testKey2", "new_global") expectValue("", "globalKey", "GLOBAL_VALUE") expectValue(testAppName, "testKey", "updated") expectValue(testAppName, "testKey2", "new") - Expect(SetMany(testAppName+"does_not_exist", vals, false)).ToNot(Succeed()) + Expect(CommandSet(testAppName+"does_not_exist", vals, false, true, false)).ToNot(Succeed()) } func TestConfigUnsetAll(t *testing.T) { RegisterTestingT(t) + Expect(setupTests()).To(Succeed()) Expect(setupTestApp()).To(Succeed()) defer teardownTestApp() expectValue(testAppName, "testKey", "TESTING") expectValue("", "testKey", "GLOBAL_TESTING") - Expect(UnsetAll(testAppName, false)).To(Succeed()) + Expect(CommandClear(testAppName, false, true)).To(Succeed()) expectNoValue(testAppName, "testKey") expectNoValue(testAppName, "noKey") expectNoValue(testAppName, "globalKey") - Expect(UnsetAll(testAppName+"does-not-exist", false)).ToNot(Succeed()) + Expect(CommandClear(testAppName+"does-not-exist", false, true)).ToNot(Succeed()) } func TestConfigUnsetMany(t *testing.T) { RegisterTestingT(t) + Expect(setupTests()).To(Succeed()) Expect(setupTestApp()).To(Succeed()) defer teardownTestApp() @@ -105,19 +114,20 @@ func TestConfigUnsetMany(t *testing.T) { expectValue("", "testKey", "GLOBAL_TESTING") keys := []string{"testKey", "noKey"} - Expect(UnsetMany(testAppName, keys, false)).To(Succeed()) + Expect(CommandUnset(testAppName, keys, false, true)).To(Succeed()) expectNoValue(testAppName, "testKey") expectValue("", "testKey", "GLOBAL_TESTING") - Expect(UnsetMany(testAppName, keys, false)).To(Succeed()) + Expect(CommandUnset(testAppName, keys, false, true)).To(Succeed()) expectNoValue(testAppName, "testKey") expectNoValue(testAppName, "globalKey") - Expect(UnsetMany(testAppName+"does-not-exist", keys, false)).ToNot(Succeed()) + Expect(CommandUnset(testAppName+"does-not-exist", keys, false, true)).ToNot(Succeed()) } func TestEnvironmentLoading(t *testing.T) { RegisterTestingT(t) + Expect(setupTests()).To(Succeed()) Expect(setupTestApp()).To(Succeed()) defer teardownTestApp() @@ -142,6 +152,7 @@ func TestEnvironmentLoading(t *testing.T) { func TestInvalidKeys(t *testing.T) { RegisterTestingT(t) + Expect(setupTests()).To(Succeed()) Expect(setupTestApp()).To(Succeed()) defer teardownTestApp() @@ -158,6 +169,7 @@ func TestInvalidKeys(t *testing.T) { func TestInvalidEnvOnDisk(t *testing.T) { RegisterTestingT(t) + Expect(setupTests()).To(Succeed()) Expect(setupTestApp()).To(Succeed()) defer teardownTestApp() diff --git a/plugins/config/environment.go b/plugins/config/environment.go index 8e26f0a80..2f6ddf071 100644 --- a/plugins/config/environment.go +++ b/plugins/config/environment.go @@ -60,10 +60,6 @@ func newEnvFromString(rep string) (env *Env, err error) { //LoadAppEnv loads an environment for the given app func LoadAppEnv(appName string) (env *Env, err error) { - err = common.VerifyAppName(appName) - if err != nil { - return - } appfile, err := getAppFile(appName) if err != nil { return @@ -357,10 +353,6 @@ func loadFromFile(name string, filename string) (env *Env, err error) { } func getAppFile(appName string) (string, error) { - err := common.VerifyAppName(appName) - if err != nil { - return "", err - } return filepath.Join(common.MustGetEnv("DOKKU_ROOT"), appName, "ENV"), nil } diff --git a/plugins/config/functions b/plugins/config/functions index 9cb3dccbf..fa3b4e0e3 100755 --- a/plugins/config/functions +++ b/plugins/config/functions @@ -7,7 +7,7 @@ config_sub() { declare desc="executes a config subcommand" local name="$1" shift - "$PLUGIN_AVAILABLE_PATH/config/subcommands/$name" "config:$name" "$@" + "$PLUGIN_AVAILABLE_PATH/config/config_sub" "$name" "$@" } config_export() { diff --git a/plugins/config/functions.go b/plugins/config/functions.go index 13407fbfb..28997d25a 100644 --- a/plugins/config/functions.go +++ b/plugins/config/functions.go @@ -1,13 +1,16 @@ package config -import "fmt" +import ( + "encoding/base64" + "errors" + "fmt" + "os" + "strings" -func export(appName string, global bool, merged bool, format string) error { - appName, err := getAppNameOrGlobal(appName, global) - if err != nil { - return err - } + "github.com/dokku/dokku/plugins/common" +) +func export(appName string, merged bool, format string) error { env := getEnvironment(appName, merged) exportType := ExportFormatExports suffix := "\n" @@ -37,3 +40,113 @@ func export(appName string, global bool, merged bool, format string) error { fmt.Print(exported + suffix) return nil } + +// SubBundle implements the logic for config:bundle without app name validation +func SubBundle(appName string, merged bool) error { + env := getEnvironment(appName, merged) + return env.ExportBundle(os.Stdout) +} + +// SubClear implements the logic for config:clear without app name validation +func SubClear(appName string, noRestart bool) error { + return UnsetAll(appName, !noRestart) +} + +// SubExport implements the logic for config:export without app name validation +func SubExport(appName string, merged bool, format string) error { + return export(appName, merged, format) +} + +// SubGet implements the logic for config:get without app name validation +func SubGet(appName string, keys []string, quoted bool) error { + if len(keys) == 0 { + return errors.New("Expected: key") + } + + if len(keys) != 1 { + return fmt.Errorf("Unexpected argument(s): %v", keys[1:]) + } + + value, ok := Get(appName, keys[0]) + if !ok { + os.Exit(1) + return nil + } + + if quoted { + fmt.Printf("'%s'\n", singleQuoteEscape(value)) + } else { + fmt.Printf("%s\n", value) + } + + return nil +} + +// SubKeys implements the logic for config:keys without app name validation +func SubKeys(appName string, merged bool) error { + env := getEnvironment(appName, merged) + for _, k := range env.Keys() { + fmt.Println(k) + } + return nil +} + +// SubSet implements the logic for config:set without app name validation +func SubSet(appName string, pairs []string, noRestart bool, encoded bool) error { + if len(pairs) == 0 { + return errors.New("At least one env pair must be given") + } + + updated := make(map[string]string) + for _, e := range pairs { + parts := strings.SplitN(e, "=", 2) + if len(parts) == 1 { + return fmt.Errorf("Invalid env pair: %v", e) + } + + key, value := parts[0], parts[1] + if encoded { + decoded, err := base64.StdEncoding.DecodeString(value) + if err != nil { + return fmt.Errorf("%s for key '%s'", err.Error(), key) + } + value = string(decoded) + } + updated[key] = value + } + + return SetMany(appName, updated, !noRestart) +} + +// SubShow implements the logic for config:show without app name validation +func SubShow(appName string, merged bool, shell bool, export bool) error { + env := getEnvironment(appName, merged) + if shell && export { + return errors.New("Only one of --shell and --export can be given") + } + if shell { + common.LogWarn("Deprecated: Use 'config:export --format shell' instead") + fmt.Print(env.Export(ExportFormatShell)) + } else if export { + common.LogWarn("Deprecated: Use 'config:export --format exports' instead") + fmt.Println(env.Export(ExportFormatExports)) + } else { + contextName := "global" + if appName != "" { + contextName = appName + } + common.LogInfo2Quiet(contextName + " env vars") + fmt.Println(env.Export(ExportFormatPretty)) + } + + return nil +} + +// SubUnset implements the logic for config:unset without app name validation +func SubUnset(appName string, keys []string, noRestart bool) error { + if len(keys) == 0 { + return fmt.Errorf("At least one key must be given") + } + + return UnsetMany(appName, keys, !noRestart) +} diff --git a/plugins/config/src/config_sub/config_sub.go b/plugins/config/src/config_sub/config_sub.go new file mode 100644 index 000000000..42dc7d70e --- /dev/null +++ b/plugins/config/src/config_sub/config_sub.go @@ -0,0 +1,112 @@ +package main + +import ( + "fmt" + "os" + + "github.com/dokku/dokku/plugins/common" + "github.com/dokku/dokku/plugins/config" + + flag "github.com/spf13/pflag" +) + +func getKeys(args []string, global bool) []string { + keys := args + if !global && len(keys) > 0 { + keys = keys[1:] + } + return keys +} + +// main entrypoint to all subcommands +func main() { + action := os.Args[1] + + var err error + appName := "--global" + switch action { + case "bundle": + args := flag.NewFlagSet("bundle", flag.ExitOnError) + global := args.Bool("global", false, "--global: use the global environment") + merged := args.Bool("merged", false, "--merged: merge app environment and global environment") + args.Parse(os.Args[2:]) + if !*global { + appName = args.Arg(0) + } + err = config.SubBundle(appName, *merged) + case "clear": + args := flag.NewFlagSet("clear", flag.ExitOnError) + global := args.Bool("global", false, "--global: use the global environment") + noRestart := args.Bool("no-restart", false, "--no-restart: no restart") + args.Parse(os.Args[2:]) + if !*global { + appName = args.Arg(0) + } + err = config.SubClear(appName, *noRestart) + case "export": + args := flag.NewFlagSet("export", flag.ExitOnError) + global := args.Bool("global", false, "--global: use the global environment") + merged := args.Bool("merged", false, "--merged: merge app environment and global environment") + format := args.String("format", "exports", "--format: [ docker-args | docker-args-keys | exports | envfile | json | json-list | pack-keys | pretty | shell ] which format to export as)") + args.Parse(os.Args[2:]) + if !*global { + appName = args.Arg(0) + } + err = config.SubExport(appName, *merged, *format) + case "get": + args := flag.NewFlagSet("get", flag.ExitOnError) + global := args.Bool("global", false, "--global: use the global environment") + quoted := args.Bool("quoted", false, "--quoted: get the value quoted") + args.Parse(os.Args[2:]) + if !*global { + appName = args.Arg(0) + } + keys := getKeys(args.Args(), *global) + err = config.SubGet(appName, keys, *quoted) + case "keys": + args := flag.NewFlagSet("keys", flag.ExitOnError) + global := args.Bool("global", false, "--global: use the global environment") + merged := args.Bool("merged", false, "--merged: merge app environment and global environment") + args.Parse(os.Args[2:]) + if !*global { + appName = args.Arg(0) + } + err = config.SubKeys(appName, *merged) + case "show": + args := flag.NewFlagSet("show", flag.ExitOnError) + global := args.Bool("global", false, "--global: use the global environment") + merged := args.Bool("merged", false, "--merged: display the app's environment merged with the global environment") + args.Parse(os.Args[2:]) + if !*global { + appName = args.Arg(0) + } + err = config.SubShow(appName, *merged, false, false) + case "set": + args := flag.NewFlagSet("set", flag.ExitOnError) + global := args.Bool("global", false, "--global: use the global environment") + encoded := args.Bool("encoded", false, "--encoded: interpret VALUEs as base64") + noRestart := args.Bool("no-restart", false, "--no-restart: no restart") + args.Parse(os.Args[2:]) + if !*global { + appName = args.Arg(0) + } + pairs := getKeys(args.Args(), *global) + err = config.SubSet(appName, pairs, *noRestart, *encoded) + case "unset": + args := flag.NewFlagSet("unset", flag.ExitOnError) + global := args.Bool("global", false, "--global: use the global environment") + noRestart := args.Bool("no-restart", false, "--no-restart: no restart") + args.Parse(os.Args[2:]) + if !*global { + appName = args.Arg(0) + } + keys := getKeys(args.Args(), *global) + err = config.SubUnset(appName, keys, *noRestart) + default: + err = fmt.Errorf("Invalid plugin config_sub call: %s", action) + } + + if err != nil { + common.LogFailWithError(err) + } +} diff --git a/plugins/config/subcommands.go b/plugins/config/subcommands.go index 033b45dd2..fe7e252d6 100644 --- a/plugins/config/subcommands.go +++ b/plugins/config/subcommands.go @@ -1,156 +1,83 @@ package config -import ( - "encoding/base64" - "errors" - "fmt" - "os" - "strings" - - "github.com/dokku/dokku/plugins/common" -) - -// CommandBundle implements config:bundle +// CommandBundle creates a tarball of a .env.d directory +// containing env vars for the app func CommandBundle(appName string, global bool, merged bool) error { appName, err := getAppNameOrGlobal(appName, global) if err != nil { return err } - env := getEnvironment(appName, merged) - return env.ExportBundle(os.Stdout) + return SubBundle(appName, merged) } -// CommandClear implements config:clear +// CommandClear unsets all environment variables in use func CommandClear(appName string, global bool, noRestart bool) error { appName, err := getAppNameOrGlobal(appName, global) if err != nil { return err } - return UnsetAll(appName, !noRestart) + return SubClear(appName, noRestart) } -// CommandExport implements config:export +// CommandExport outputs all env vars (merged or not, global or not) +// in the specified format for consumption by other tools func CommandExport(appName string, global bool, merged bool, format string) error { - return export(appName, global, merged, format) + appName, err := getAppNameOrGlobal(appName, global) + if err != nil { + return err + } + + return SubExport(appName, merged, format) } -// CommandGet implements config:get +// CommandGet gets the value for the specified environment variable func CommandGet(appName string, keys []string, global bool, quoted bool) error { appName, err := getAppNameOrGlobal(appName, global) if err != nil { return err } - if len(keys) == 0 { - return errors.New("Expected: key") - } - - if len(keys) != 1 { - return fmt.Errorf("Unexpected argument(s): %v", keys[1:]) - } - - value, ok := Get(appName, keys[0]) - if !ok { - os.Exit(1) - return nil - } - - if quoted { - fmt.Printf("'%s'\n", singleQuoteEscape(value)) - } else { - fmt.Printf("%s\n", value) - } - - return nil + return SubGet(appName, keys, quoted) } -// CommandKeys implements config:keys +// CommandKeys shows the keys set for the specified environment func CommandKeys(appName string, global bool, merged bool) error { appName, err := getAppNameOrGlobal(appName, global) if err != nil { return err } - env := getEnvironment(appName, merged) - for _, k := range env.Keys() { - fmt.Println(k) - } - return nil + return SubKeys(appName, merged) } -// CommandSet implements config:set +// CommandSet sets one or more environment variable pairs func CommandSet(appName string, pairs []string, global bool, noRestart bool, encoded bool) error { appName, err := getAppNameOrGlobal(appName, global) if err != nil { return err } - if len(pairs) == 0 { - return errors.New("At least one env pair must be given") - } - - updated := make(map[string]string) - for _, e := range pairs { - parts := strings.SplitN(e, "=", 2) - if len(parts) == 1 { - return fmt.Errorf("Invalid env pair: %v", e) - } - - key, value := parts[0], parts[1] - if encoded { - decoded, err := base64.StdEncoding.DecodeString(value) - if err != nil { - return fmt.Errorf("%s for key '%s'", err.Error(), key) - } - value = string(decoded) - } - updated[key] = value - } - - return SetMany(appName, updated, !noRestart) + return SubSet(appName, pairs, noRestart, encoded) } -// CommandShow implements config:show +// CommandShow pretty-prints the specified environment vaiables func CommandShow(appName string, global bool, merged bool, shell bool, export bool) error { appName, err := getAppNameOrGlobal(appName, global) if err != nil { return err } - env := getEnvironment(appName, merged) - if shell && export { - return errors.New("Only one of --shell and --export can be given") - } - if shell { - common.LogWarn("Deprecated: Use 'config:export --format shell' instead") - fmt.Print(env.Export(ExportFormatShell)) - } else if export { - common.LogWarn("Deprecated: Use 'config:export --format exports' instead") - fmt.Println(env.Export(ExportFormatExports)) - } else { - contextName := "global" - if appName != "" { - contextName = appName - } - common.LogInfo2Quiet(contextName + " env vars") - fmt.Println(env.Export(ExportFormatPretty)) - } - - return nil + return SubShow(appName, merged, shell, export) } -// CommandUnset implements config:unset +// CommandUnset unsets one or more keys in a specified environment func CommandUnset(appName string, keys []string, global bool, noRestart bool) error { appName, err := getAppNameOrGlobal(appName, global) if err != nil { return err } - if len(keys) == 0 { - return fmt.Errorf("At least one key must be given") - } - - return UnsetMany(appName, keys, !noRestart) + return SubUnset(appName, keys, noRestart) } diff --git a/plugins/config/triggers.go b/plugins/config/triggers.go index 7bcfbb50f..3014f6d26 100644 --- a/plugins/config/triggers.go +++ b/plugins/config/triggers.go @@ -16,7 +16,13 @@ func TriggerConfigExport(appName string, global string, merged string, format st if err != nil { return err } - return export(appName, g, m, format) + + appName, err = getAppNameOrGlobal(appName, g) + if err != nil { + return err + } + + return export(appName, m, format) } // TriggerConfigGet returns an app config value by key