diff --git a/plugins/config/docker-args-deploy b/plugins/config/docker-args-deploy index 366d2dd7d..55b9f5026 100755 --- a/plugins/config/docker-args-deploy +++ b/plugins/config/docker-args-deploy @@ -10,29 +10,8 @@ config_docker_args() { verify_app_name "$APP" if ! is_image_herokuish_based "$IMAGE"; then - shopt -s extglob - local ENV_ARGS - declare -A ENV_ARGS - for key in $(config_keys global); do - VAR="$(config_get --global "$key")" - printf -vVAR '%q' "${VAR%%*( )}" - ENV_ARGS[$key]="$VAR" - done - for key in $(config_keys app "$APP"); do - VAR="$(config_get "$APP" "$key")" - printf -vVAR '%q' "${VAR%%*( )}" - ENV_ARGS[$key]="$VAR" - done - shopt -u extglob - local ALL_ENV_ARGS - declare -a ALL_ENV_ARGS - for key in "${!ENV_ARGS[@]}"; do - local ARG="$key=${ENV_ARGS[$key]}" - ALL_ENV_ARGS+=("--env") - ALL_ENV_ARGS+=("$ARG") - done - - echo -n "$STDIN ${ALL_ENV_ARGS[@]}" + local ENV_ARGS="$(config_export app $APP --prefix="-e" --separator=" " --merged)" + echo -n "$STDIN $ENV_ARGS" else echo -n "$STDIN" fi diff --git a/plugins/config/src/configenv/configenv.go b/plugins/config/src/configenv/configenv.go index 7fdf53d7d..070ea0007 100644 --- a/plugins/config/src/configenv/configenv.go +++ b/plugins/config/src/configenv/configenv.go @@ -24,22 +24,23 @@ func (e *Env) String() string { //EnvfileString returns the contents of this Env in ENVFILE format func (e *Env) EnvfileString() string { - return e.stringWithEntryPrefix("") + return e.StringWithPrefixAndSeparator("", "\n") } //ExportfileString returns the contents of this Env as bash exports func (e *Env) ExportfileString() string { - return e.stringWithEntryPrefix("export ") + return e.StringWithPrefixAndSeparator("export ", "\n") } -func (e *Env) stringWithEntryPrefix(prefix string) string { +//StringWithPrefixAndSeparator makes a string of the environment +// with the given prefix and separator for each entry +func (e *Env) StringWithPrefixAndSeparator(prefix string, separator string) string { keys := e.Keys() - sort.Strings(keys) entries := make([]string, len(keys)) for i, k := range keys { entries[i] = fmt.Sprintf("%s%s='%s'", prefix, k, SingleQuoteEscape(e.env[k])) } - return strings.Join(entries, "\n") + return strings.Join(entries, separator) } //SingleQuoteEscape escapes the value as if it were shell-quoted in single quotes @@ -50,13 +51,23 @@ func SingleQuoteEscape(value string) string { // so that 'esc'apped' -> 'esc'\'' //NewFromTarget creates an env from the given target. Tareget is either "--global" or an app name func NewFromTarget(target string) (*Env, error) { if target == "--global" { - return parseEnv("global", getGlobalFile()) + return LoadGlobal() } - appfile, err := getAppFile(target) + return LoadApp(target) +} + +//LoadApp loads an environment for the given app +func LoadApp(appName string) (*Env, error) { + appfile, err := getAppFile(appName) if err != nil { return nil, err } - return parseEnv(target, appfile) + return parseEnv(appName, appfile) +} + +//LoadGlobal loads the global environmen +func LoadGlobal() (*Env, error) { + return parseEnv("global", getGlobalFile()) } //NewFromString creates an env from the given ENVFILE contents representation @@ -64,6 +75,13 @@ func NewFromString(rep string) (*Env, error) { return parseEnvFromReader("", "", strings.NewReader(rep)) } +//Merge merges the given environment on top of the reciever +func (e *Env) Merge(other *Env) { + for _, k := range other.Keys() { + e.Set(k, other.GetDefault(k, "")) + } +} + //Set an environment variable func (e *Env) Set(key string, value string) { e.env[key] = value @@ -80,6 +98,7 @@ func (e *Env) Keys() []string { for k := range e.env { keys = append(keys, k) } + sort.Strings(keys) return keys } @@ -108,6 +127,11 @@ func (e *Env) GetBoolDefault(key string, defaultValue bool) bool { return v != "0" } +//Len return the number of items in this environment +func (e *Env) Len() int { + return len(e.env) +} + //Map return the Env as a map func (e *Env) Map() map[string]string { return e.env diff --git a/plugins/config/src/configenv/configenv_test.go b/plugins/config/src/configenv/configenv_test.go index a948f865f..16b3e3db0 100644 --- a/plugins/config/src/configenv/configenv_test.go +++ b/plugins/config/src/configenv/configenv_test.go @@ -44,6 +44,21 @@ func TestExportfileErrors(t *testing.T) { Expect(err).To(HaveOccurred()) } +func TestMerge(t *testing.T) { + RegisterTestingT(t) + e, _ := NewFromString("FOO='bar'") + e2, _ := NewFromString("BAR='baz'") + e.Merge(e2) + Expect(e.Map()).To(Equal(pairs("BAR", "baz", "FOO", "bar"))) +} + +func TestArrayExport(t *testing.T) { + RegisterTestingT(t) + e, _ := NewFromString("BAR='BAZ'\nFOO='b'\\''ar '") + Expect(e.StringWithPrefixAndSeparator("", " ")).To(Equal("BAR='BAZ' FOO='b'\\''ar '")) + Expect(e.StringWithPrefixAndSeparator("-e", " ")).To(Equal("-eBAR='BAZ' -eFOO='b'\\''ar '")) +} + func pairs(vars ...string) map[string]string { res := map[string]string{} var i = 0 diff --git a/plugins/config/src/subcommands/export/export.go b/plugins/config/src/subcommands/export/export.go index 9253dc88f..d28a9b2f4 100644 --- a/plugins/config/src/subcommands/export/export.go +++ b/plugins/config/src/subcommands/export/export.go @@ -11,10 +11,14 @@ import ( // print the environment to stdout func main() { + const defaultPrefix = "export " args := flag.NewFlagSet("config: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") keys := args.Bool("keys", false, "--keys: export keys only") - envfile := args.Bool("envfile", false, "--envfile: export as envfile rather than bash exports") + envfile := args.Bool("envfile", false, "--envfile: export as envfile rather than bash exports (--prefix='')") + prefix := args.String("prefix", "export ", "--prefix: prefix") + separator := args.String("separator", "\n", "--separator: separator") args.Parse(os.Args[2:]) appName := args.Arg(0) @@ -26,6 +30,9 @@ func main() { if appName != "" { common.LogFail("Trailing argument: " + appName) } + if *merged == true { + common.LogFail("Only app environments can be merged") + } appName = "--global" } @@ -33,6 +40,16 @@ func main() { if err != nil { common.LogFail(err.Error()) } + + if *merged { + global, err := configenv.LoadGlobal() + if err != nil { + common.LogFail(err.Error()) + } + global.Merge(env) + env = global + } + if *keys { for _, k := range env.Keys() { fmt.Println(k) @@ -41,8 +58,11 @@ func main() { } if *envfile { - fmt.Println(env.EnvfileString()) - } else { - fmt.Println(env.ExportfileString()) + if *prefix != defaultPrefix { + common.LogFail("--prefix and --envfile cannot both be given") + return + } + *prefix = "" } + fmt.Println(env.StringWithPrefixAndSeparator(*prefix, *separator)) }