subprocess: don't initialize environment at startup

Currently, the subprocess package reads from the environment as it's
created at startup when the init function is called.  However, we'll
soon want to modify the environment in this case before it gets
processed, so let's change the code to use a mutex to initialize the
environment once before using it and simply call that before using the
environment we've set up.

We'll want to reset the environment as well in a future commit, so let's
be sure to add a function for that.  We reuse the same internal function
and just ignore the return value to make our code paths simpler.
This commit is contained in:
brian m. carlson 2020-10-02 16:50:06 +00:00
parent 19b2cd8e90
commit 59f1496289
No known key found for this signature in database
GPG Key ID: 2D0C9BC12F82B3A1
3 changed files with 30 additions and 3 deletions

@ -9,6 +9,7 @@ import (
"os/exec"
"regexp"
"strings"
"sync"
"github.com/rubyist/tracerx"
)
@ -128,6 +129,7 @@ func quotedArgs(args []string) string {
// An env for an exec.Command without GIT_TRACE and GIT_INTERNAL_SUPER_PREFIX
var env []string
var envMu sync.Mutex
var traceEnv = "GIT_TRACE="
// Don't pass GIT_INTERNAL_SUPER_PREFIX back to Git. Git passes this environment
@ -138,7 +140,20 @@ var traceEnv = "GIT_TRACE="
// support --super-prefix and would immediately exit with an error as a result.
var superPrefixEnv = "GIT_INTERNAL_SUPER_PREFIX="
func init() {
func fetchEnvironment() []string {
envMu.Lock()
defer envMu.Unlock()
return fetchEnvironmentInternal()
}
// fetchEnvironmentInternal should only be called from fetchEnvironment or
// ResetEnvironment, who will hold the required lock.
func fetchEnvironmentInternal() []string {
if env != nil {
return env
}
realEnv := os.Environ()
env = make([]string, 0, len(realEnv))
@ -148,4 +163,16 @@ func init() {
}
env = append(env, kv)
}
return env
}
// ResetEnvironment resets the cached environment that's used in subprocess
// calls.
func ResetEnvironment() {
envMu.Lock()
defer envMu.Unlock()
env = nil
// Reinitialize the environment settings.
fetchEnvironmentInternal()
}

@ -9,6 +9,6 @@ import (
// ExecCommand is a small platform specific wrapper around os/exec.Command
func ExecCommand(name string, arg ...string) *Cmd {
cmd := exec.Command(name, arg...)
cmd.Env = env
cmd.Env = fetchEnvironment()
return newCmd(cmd)
}

@ -11,6 +11,6 @@ import (
func ExecCommand(name string, arg ...string) *Cmd {
cmd := exec.Command(name, arg...)
cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
cmd.Env = env
cmd.Env = fetchEnvironment()
return newCmd(cmd)
}