You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2019/10/10 17:15:10 UTC
[mynewt-newt] 06/08: Pass environment variables as map[string]string
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 <cc...@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},
}