This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-newt.git

commit ec5657770d612abaab60d5d61250a87f0927abb6
Author: Christopher Collins <ccoll...@apache.org>
AuthorDate: Fri Oct 4 17:52:55 2019 -0700

    Pass environment variables as map[string]string
    
    Prior to this commit, the util shell functions accepted env vars as
    string slices (`k=v`).  The problem with this approach was that env vars
    already defined in the process would not get overwritten by new ones
    (the new ones would be appended to the list; if they conflicted with old
    ones, they were ignored).
    
    Now environment variables are passed in maps.  Newt manually overwrites
    old env vars with new ones.
---
 newt/builder/buildutil.go | 29 ++++++----------
 newt/builder/extcmd.go    | 13 +++++--
 newt/builder/load.go      | 30 +++++++---------
 util/util.go              | 87 ++++++++++++++++++++++++++++++++++++++++-------
 4 files changed, 107 insertions(+), 52 deletions(-)

diff --git a/newt/builder/buildutil.go b/newt/builder/buildutil.go
index b71fa94..65a24ad 100644
--- a/newt/builder/buildutil.go
+++ b/newt/builder/buildutil.go
@@ -21,7 +21,6 @@ package builder
 
 import (
        "bytes"
-       "fmt"
        "sort"
        "strconv"
        "strings"
@@ -33,6 +32,7 @@ import (
        "mynewt.apache.org/newt/newt/pkg"
        "mynewt.apache.org/newt/newt/project"
        "mynewt.apache.org/newt/newt/resolve"
+       "mynewt.apache.org/newt/newt/toolchain"
        "mynewt.apache.org/newt/util"
 )
 
@@ -173,6 +173,15 @@ func BasicEnvVars(binBase string, bspPkg *pkg.BspPackage) 
map[string]string {
        return m
 }
 
+func ToolchainEnvVars(c *toolchain.Compiler) map[string]string {
+       return map[string]string{
+               "MYNEWT_CC_PATH":  c.GetCcPath(),
+               "MYNEWT_CPP_PATH": c.GetCppPath(),
+               "MYNEWT_AS_PATH":  c.GetAsPath(),
+               "MYNEWT_AR_PATH":  c.GetArPath(),
+       }
+}
+
 // SettingsEnvVars calculates the syscfg set of environment variables required
 // by image loading scripts.
 func SettingsEnvVars(settings map[string]string) map[string]string {
@@ -299,21 +308,3 @@ func (b *Builder) EnvVars(imageSlot int) 
(map[string]string, error) {
 
        return env, nil
 }
-
-// EnvVarsToSlice converts an environment variable map into a slice of strings
-// suitable for "shell command" functions defined in `util` (e.g.,
-// util.ShellCommand).
-func EnvVarsToSlice(env map[string]string) []string {
-       keys := make([]string, 0, len(env))
-       for k, _ := range env {
-               keys = append(keys, k)
-       }
-       sort.Strings(keys)
-
-       slice := make([]string, 0, len(env))
-       for _, key := range keys {
-               slice = append(slice, fmt.Sprintf("%s=%s", key, env[key]))
-       }
-
-       return slice
-}
diff --git a/newt/builder/extcmd.go b/newt/builder/extcmd.go
index ba64280..cddea76 100644
--- a/newt/builder/extcmd.go
+++ b/newt/builder/extcmd.go
@@ -102,11 +102,19 @@ func (t *TargetBuilder) envVarsForCmd(sf stage.StageFunc, 
userSrcDir string,
                WorkDir:    workDir,
        }
        uenv := UserEnvVars(p)
-
        for k, v := range uenv {
                env[k] = v
        }
 
+       c, err := t.NewCompiler("", "")
+       if err != nil {
+               return nil, err
+       }
+       tenv := ToolchainEnvVars(c)
+       for k, v := range tenv {
+               env[k] = v
+       }
+
        return env, nil
 }
 
@@ -147,8 +155,7 @@ func (t *TargetBuilder) execExtCmds(sf stage.StageFunc, 
userSrcDir string,
        defer os.Chdir(pwd)
 
        util.StatusMessage(util.VERBOSITY_DEFAULT, "Executing %s\n", sf.Name)
-       envs := EnvVarsToSlice(env)
-       if err := util.ShellInteractiveCommand(toks, envs, true); err != nil {
+       if err := util.ShellInteractiveCommand(toks, env, true); err != nil {
                return err
        }
 
diff --git a/newt/builder/load.go b/newt/builder/load.go
index a166b8c..5f8421f 100644
--- a/newt/builder/load.go
+++ b/newt/builder/load.go
@@ -85,7 +85,7 @@ func (t *TargetBuilder) Load(extraJtagCmd string) error {
        return err
 }
 
-func RunOptionalCheck(checkScript string, env []string) error {
+func RunOptionalCheck(checkScript string, env map[string]string) error {
        if checkScript == "" {
                return nil
        }
@@ -125,9 +125,8 @@ func Load(binBasePath string, bspPkg *pkg.BspPackage,
        for k, v := range extraEnvSettings {
                env[k] = v
        }
-       envSlice := EnvVarsToSlice(env)
 
-       RunOptionalCheck(bspPkg.OptChkScript, envSlice)
+       RunOptionalCheck(bspPkg.OptChkScript, env)
        // bspPath, binBasePath are passed in command line for backwards
        // compatibility
        cmd := []string{
@@ -142,7 +141,7 @@ func Load(binBasePath string, bspPkg *pkg.BspPackage,
        for _, v := range env {
                util.StatusMessage(util.VERBOSITY_VERBOSE, "* %s\n", v)
        }
-       if _, err := util.ShellCommand(cmd, envSlice); err != nil {
+       if _, err := util.ShellCommand(cmd, env); err != nil {
                return err
        }
        util.StatusMessage(util.VERBOSITY_VERBOSE, "Successfully loaded 
image.\n")
@@ -211,31 +210,26 @@ func (b *Builder) debugBin(binPath string, extraJtagCmd 
string, reset bool,
 
        bspPath := b.bspPkg.rpkg.Lpkg.BasePath()
        binBasePath := binPath
-       featureString := FeatureString(b.cfg.SettingValues())
        bspPkg := b.targetBuilder.bspPkg
 
-       coreRepo := project.GetProject().FindRepo("apache-mynewt-core")
-       envSettings := []string{
-               fmt.Sprintf("CORE_PATH=%s", coreRepo.Path()),
-               fmt.Sprintf("BSP_PATH=%s", bspPath),
-               fmt.Sprintf("BIN_BASENAME=%s", binBasePath),
-               fmt.Sprintf("FEATURES=%s", featureString),
-               fmt.Sprintf("MYNEWT_PROJECT_ROOT=%s", ProjectRoot()),
+       env, err := b.EnvVars(0)
+       if err != nil {
+               return err
        }
+
        if extraJtagCmd != "" {
-               envSettings = append(envSettings,
-                       fmt.Sprintf("EXTRA_JTAG_CMD=%s", extraJtagCmd))
+               env["EXTRA_JTAG_CMD"] = extraJtagCmd
        }
        if reset == true {
-               envSettings = append(envSettings, fmt.Sprintf("RESET=true"))
+               env["RESET"] = "true"
        }
        if noGDB == true {
-               envSettings = append(envSettings, fmt.Sprintf("NO_GDB=1"))
+               env["NO_GDB"] = "1"
        }
 
        os.Chdir(project.GetProject().Path())
 
-       RunOptionalCheck(bspPkg.OptChkScript, envSettings)
+       RunOptionalCheck(bspPkg.OptChkScript, env)
        // bspPath, binBasePath are passed in command line for backwards
        // compatibility
        cmdLine := []string{
@@ -243,7 +237,7 @@ func (b *Builder) debugBin(binPath string, extraJtagCmd 
string, reset bool,
        }
 
        fmt.Printf("%s\n", cmdLine)
-       return util.ShellInteractiveCommand(cmdLine, envSettings, false)
+       return util.ShellInteractiveCommand(cmdLine, env, false)
 }
 
 func (b *Builder) Debug(extraJtagCmd string, reset bool, noGDB bool) error {
diff --git a/util/util.go b/util/util.go
index aa46495..9800ea8 100644
--- a/util/util.go
+++ b/util/util.go
@@ -273,10 +273,11 @@ func fixupCmdArgs(args []string) {
        }
 }
 
-func LogShellCmd(cmdStrs []string, env []string) {
+func LogShellCmd(cmdStrs []string, env map[string]string) {
        envLogStr := ""
        if len(env) > 0 {
-               envLogStr = strings.Join(env, " ") + " "
+               s := EnvVarsToSlice(env)
+               envLogStr = strings.Join(s, " ") + " "
        }
        log.Debugf("%s%s", envLogStr, strings.Join(cmdStrs, " "))
 
@@ -285,12 +286,58 @@ func LogShellCmd(cmdStrs []string, env []string) {
        }
 }
 
+// EnvVarsToSlice converts an environment variable map into a slice of `k=v`
+// strings.
+func EnvVarsToSlice(env map[string]string) []string {
+       keys := make([]string, 0, len(env))
+       for k, _ := range env {
+               keys = append(keys, k)
+       }
+       sort.Strings(keys)
+
+       slice := make([]string, 0, len(env))
+       for _, key := range keys {
+               slice = append(slice, fmt.Sprintf("%s=%s", key, env[key]))
+       }
+
+       return slice
+}
+
+// SliceToEnvVars converts a slice of `k=v` strings into an environment
+// variable map.
+func SliceToEnvVars(slc []string) (map[string]string, error) {
+       m := make(map[string]string, len(slc))
+       for _, s := range slc {
+               parts := strings.SplitN(s, "=", 2)
+               if len(parts) != 2 {
+                       return nil, FmtNewtError("invalid env var string: 
\"%s\"", s)
+               }
+
+               m[parts[0]] = parts[1]
+       }
+
+       return m, nil
+}
+
+// EnvironAsMap gathers the current process's set of environment variables and
+// returns them as a map.
+func EnvironAsMap() (map[string]string, error) {
+       slc := os.Environ()
+
+       m, err := SliceToEnvVars(slc)
+       if err != nil {
+               return nil, err
+       }
+
+       return m, nil
+}
+
 // Execute the specified process and block until it completes.  Additionally,
 // the amount of combined stdout+stderr output to be logged to the debug log
 // can be restricted to a maximum number of characters.
 //
 // @param cmdStrs               The "argv" strings of the command to execute.
-// @param env                   Additional key=value pairs to inject into the
+// @param env                   Additional key,value pairs to inject into the
 //                                  child process's environment.  Specify null
 //                                  to just inherit the parent environment.
 // @param logCmd                Whether to log the command being executed.
@@ -304,8 +351,8 @@ func LogShellCmd(cmdStrs []string, env []string) {
 //                                  or if it just returned a non-zero exit
 //                                  status.
 func ShellCommandLimitDbgOutput(
-       cmdStrs []string, env []string, logCmd bool, maxDbgOutputChrs int) (
-       []byte, error) {
+       cmdStrs []string, env map[string]string, logCmd bool,
+       maxDbgOutputChrs int) ([]byte, error) {
 
        var name string
        var args []string
@@ -328,7 +375,15 @@ func ShellCommandLimitDbgOutput(
        cmd := exec.Command(name, args...)
 
        if env != nil {
-               cmd.Env = append(env, os.Environ()...)
+               m, err := EnvironAsMap()
+               if err != nil {
+                       return nil, err
+               }
+
+               for k, v := range env {
+                       m[k] = v
+               }
+               cmd.Env = EnvVarsToSlice(m)
        }
 
        o, err := cmd.CombinedOutput()
@@ -356,18 +411,20 @@ func ShellCommandLimitDbgOutput(
 // Execute the specified process and block until it completes.
 //
 // @param cmdStrs               The "argv" strings of the command to execute.
-// @param env                   Additional key=value pairs to inject into the
+// @param env                   Additional key,value pairs to inject into the
 //                                  child process's environment.  Specify null
 //                                  to just inherit the parent environment.
 //
 // @return []byte               Combined stdout and stderr output of process.
 // @return error                NewtError on failure.
-func ShellCommand(cmdStrs []string, env []string) ([]byte, error) {
+func ShellCommand(cmdStrs []string, env map[string]string) ([]byte, error) {
        return ShellCommandLimitDbgOutput(cmdStrs, env, true, -1)
 }
 
 // Run interactive shell command
-func ShellInteractiveCommand(cmdStr []string, env []string, flagBlock bool) 
error {
+func ShellInteractiveCommand(cmdStr []string, env map[string]string,
+       flagBlock bool) error {
+
        // Escape special characters for Windows.
        fixupCmdArgs(cmdStr)
 
@@ -385,15 +442,21 @@ func ShellInteractiveCommand(cmdStr []string, env 
[]string, flagBlock bool) erro
                }()
        }
 
-       if env != nil {
-               env = append(env, os.Environ()...)
+       m, err := EnvironAsMap()
+       if err != nil {
+               return err
+       }
+
+       for k, v := range env {
+               m[k] = v
        }
+       envSlice := EnvVarsToSlice(m)
 
        // Transfer stdin, stdout, and stderr to the new process
        // and also set target directory for the shell to start in.
        // and set the additional environment variables
        pa := os.ProcAttr{
-               Env:   env,
+               Env:   envSlice,
                Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
        }
 

Reply via email to