diff options
author | Brad Fitzpatrick <bradfitz@golang.org> | 2017-02-28 22:25:06 +0000 |
---|---|---|
committer | Brad Fitzpatrick <bradfitz@golang.org> | 2017-02-28 23:05:18 +0000 |
commit | e73f4894949c4ced611881329ff8f37805152585 (patch) | |
tree | fca8cbcf46e7252c7ba0a3cf2c0960ada04337de /src/os/exec/exec.go | |
parent | 3c023f75a62f903273c688432f95e77fc945b6fb (diff) | |
download | go-e73f4894949c4ced611881329ff8f37805152585.tar.gz go-e73f4894949c4ced611881329ff8f37805152585.zip |
os/exec: remove duplicate environment variables in Cmd.Start
Nobody intends to have duplicates anyway because it's so undefined
and everything handles it so poorly.
Removing duplicates automatically simplifies code and makes existing
code do what people already expect.
Fixes #12868
Change-Id: I95eeba8c59ff94d0f018012a6f4e031aaabfd5d9
Reviewed-on: https://go-review.googlesource.com/37586
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/os/exec/exec.go')
-rw-r--r-- | src/os/exec/exec.go | 40 |
1 files changed, 38 insertions, 2 deletions
diff --git a/src/os/exec/exec.go b/src/os/exec/exec.go index c4c5168b98..2bfc34f5ca 100644 --- a/src/os/exec/exec.go +++ b/src/os/exec/exec.go @@ -55,7 +55,11 @@ type Cmd struct { Args []string // Env specifies the environment of the process. - // If Env is nil, Run uses the current process's environment. + // Each entry is of the form "key=value". + // If Env is nil, the new process uses the current process's + // environment. + // If Env contains duplicate environment keys, only the last + // value in the slice for each duplicate key is used. Env []string // Dir specifies the working directory of the command. @@ -354,7 +358,7 @@ func (c *Cmd) Start() error { c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{ Dir: c.Dir, Files: c.childFiles, - Env: c.envv(), + Env: dedupEnv(c.envv()), Sys: c.SysProcAttr, }) if err != nil { @@ -712,3 +716,35 @@ func minInt(a, b int) int { } return b } + +// dedupEnv returns a copy of env with any duplicates removed, in favor of +// later values. +// Items not of the normal environment "key=value" form are preserved unchanged. +func dedupEnv(env []string) []string { + return dedupEnvCase(runtime.GOOS == "windows", env) +} + +// dedupEnvCase is dedupEnv with a case option for testing. +// If caseInsensitive is true, the case of keys is ignored. +func dedupEnvCase(caseInsensitive bool, env []string) []string { + out := make([]string, 0, len(env)) + saw := map[string]int{} // key => index into out + for _, kv := range env { + eq := strings.Index(kv, "=") + if eq < 0 { + out = append(out, kv) + continue + } + k := kv[:eq] + if caseInsensitive { + k = strings.ToLower(k) + } + if dupIdx, isDup := saw[k]; isDup { + out[dupIdx] = kv + continue + } + saw[k] = len(out) + out = append(out, kv) + } + return out +} |