Skip to content

Commit 0892e0e

Browse files
authored
Refactor env vars as map[string]string instead of []string (#621)
## Summary This makes it easier to manipulate vars in functions (like `computeNixEnv`). On the flip side, it does mean we need to convert them to `[]string` in order to pass them to a `Command`, which is a bit annoying, but I think it's reasonable. We can introduce a helper function `asPairs(map[string]string)` or something like that later on if we feel the need to clean up. ## How was it tested? CICD
1 parent b4014e8 commit 0892e0e

File tree

6 files changed

+44
-30
lines changed

6 files changed

+44
-30
lines changed

internal/impl/devbox.go

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ func (d *Devbox) RunScript(cmdName string, cmdArgs []string) error {
309309
return err
310310
}
311311
cmdWithArgs = []string{d.scriptPath(d.scriptFilename(arbitraryCmdFilename))}
312-
env = append(env, fmt.Sprintf("DEVBOX_RUN_CMD=%s", strings.Join(append([]string{cmdName}, cmdArgs...), " ")))
312+
env["DEVBOX_RUN_CMD"] = strings.Join(append([]string{cmdName}, cmdArgs...), " ")
313313
}
314314

315315
return nix.RunScript(d.projectDir, strings.Join(cmdWithArgs, " "), env)
@@ -696,7 +696,7 @@ func (d *Devbox) printPackageUpdateMessage(
696696
// 3. Append the cleaned host PATH (tradeoff between reproducibility and ease of use).
697697
// 4. Prepend the devbox-managed nix profile path (which is needed to support devbox add inside shell--can we do without it?).
698698
// 5. Prepend the paths of any plugins (tbd whether it's actually needed).
699-
func (d *Devbox) computeNixEnv() ([]string, error) {
699+
func (d *Devbox) computeNixEnv() (map[string]string, error) {
700700

701701
vaf, err := nix.PrintDevEnv(d.nixShellFilePath(), d.nixFlakesFilePath())
702702
if err != nil {
@@ -722,35 +722,32 @@ func (d *Devbox) computeNixEnv() ([]string, error) {
722722
}
723723
}
724724

725-
// PATH handling.
726-
pluginVirtenvPath := d.pluginVirtenvPath() // TODO: consider removing this; not being used?
727-
nixProfilePath, err := d.profileBinPath()
728-
if err != nil {
729-
return nil, err
730-
}
731-
nixPath := env["PATH"]
732-
hostPath := nix.CleanEnvPath(os.Getenv("PATH"), os.Getenv("NIX_PROFILES"))
733-
734-
env["PATH"] = fmt.Sprintf("%s:%s:%s:%s", pluginVirtenvPath, nixProfilePath, nixPath, hostPath)
735-
736-
envPairs := []string{}
737-
for k, v := range env {
738-
envPairs = append(envPairs, fmt.Sprintf("%s=%s", k, v))
739-
}
740-
741725
pluginEnv, err := plugin.Env(d.packages(), d.projectDir)
742726
if err != nil {
743727
return nil, err
744728
}
745-
envPairs = append(envPairs, pluginEnv...)
729+
for k, v := range pluginEnv {
730+
env[k] = v
731+
}
746732

747733
// TODO: add shell-specific vars, including:
748734
// - NIXPKGS_ALLOW_UNFREE=1 (not needed in run because we don't expect nix calls there)
749735
// - __ETC_PROFILE_NIX_SOURCED=1 (not needed in run because we don't expect rc files to try to load nix profiles)
750736
// - HISTFILE (not needed in run because it's non-interactive)
751737
// - (some of) nix.envToKeep.
752738

753-
return envPairs, nil
739+
// PATH handling.
740+
pluginVirtenvPath := d.pluginVirtenvPath() // TODO: consider removing this; not being used?
741+
nixProfilePath, err := d.profileBinPath()
742+
if err != nil {
743+
return nil, err
744+
}
745+
nixPath := env["PATH"]
746+
hostPath := nix.CleanEnvPath(os.Getenv("PATH"), os.Getenv("NIX_PROFILES"))
747+
748+
env["PATH"] = fmt.Sprintf("%s:%s:%s:%s", pluginVirtenvPath, nixProfilePath, nixPath, hostPath)
749+
750+
return env, nil
754751
}
755752

756753
// TODO savil. move to packages.go

internal/nix/nix.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,18 @@ func (i *Info) String() string {
5050
return fmt.Sprintf("%s-%s", i.Name, i.Version)
5151
}
5252

53-
func Exec(path string, command []string, env []string) error {
53+
func Exec(path string, command []string, envPairs map[string]string) error {
54+
env := DefaultEnv()
55+
for k, v := range envPairs {
56+
env = append(env, fmt.Sprintf("%s=%s", k, v))
57+
}
58+
5459
runCmd := strings.Join(command, " ")
5560
cmd := exec.Command("nix-shell", path, "--run", runCmd)
5661
cmd.Stdin = os.Stdin
5762
cmd.Stdout = os.Stdout
5863
cmd.Stderr = os.Stderr
59-
cmd.Env = append(DefaultEnv(), env...)
64+
cmd.Env = env
6065
return errors.WithStack(usererr.NewExecError(cmd.Run()))
6166
}
6267

internal/nix/run.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package nix
22

33
import (
4+
"fmt"
45
"os"
56
"os/exec"
67

@@ -9,18 +10,23 @@ import (
910
"go.jetpack.io/devbox/internal/debug"
1011
)
1112

12-
func RunScript(projectDir string, cmdWithArgs string, env []string) error {
13+
func RunScript(projectDir string, cmdWithArgs string, env map[string]string) error {
1314
if cmdWithArgs == "" {
1415
return errors.New("attempted to run an empty command or script")
1516
}
1617

18+
envPairs := []string{}
19+
for k, v := range env {
20+
envPairs = append(envPairs, fmt.Sprintf("%s=%s", k, v))
21+
}
22+
1723
// Try to find sh in the PATH, if not, default to a well known absolute path.
1824
shPath, err := exec.LookPath("sh")
1925
if err != nil {
2026
shPath = "/bin/sh"
2127
}
2228
cmd := exec.Command(shPath, "-c", cmdWithArgs)
23-
cmd.Env = env
29+
cmd.Env = envPairs
2430
cmd.Dir = projectDir
2531
cmd.Stdin = os.Stdin
2632
cmd.Stdout = os.Stdout

internal/nix/shell.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,11 @@ func WithHistoryFile(historyFile string) ShellOption {
129129

130130
// TODO: Consider removing this once plugins add env vars directly to binaries
131131
// via wrapper scripts.
132-
func WithEnvVariables(envVariables []string) ShellOption {
132+
func WithEnvVariables(envVariables map[string]string) ShellOption {
133133
return func(s *Shell) {
134-
s.env = append(s.env, envVariables...)
134+
for k, v := range envVariables {
135+
s.env = append(s.env, fmt.Sprintf("%s=%s", k, v))
136+
}
135137
}
136138
}
137139

internal/plugin/pkgcfg.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ func (m *Manager) CreateFilesAndShowReadme(pkg, projectDir string) error {
107107
// Env returns the environment variables for the given plugins.
108108
// TODO: We should associate the env variables with the individual plugin
109109
// binaries via wrappers instead of adding to the environment everywhere.
110-
func Env(pkgs []string, projectDir string) ([]string, error) {
111-
env := []string{}
110+
func Env(pkgs []string, projectDir string) (map[string]string, error) {
111+
env := map[string]string{}
112112
for _, pkg := range pkgs {
113113
cfg, err := getConfigIfAny(pkg, projectDir)
114114
if err != nil {
@@ -118,7 +118,7 @@ func Env(pkgs []string, projectDir string) ([]string, error) {
118118
continue
119119
}
120120
for k, v := range cfg.Env {
121-
env = append(env, fmt.Sprintf("%s=%s", k, v))
121+
env[k] = v
122122
}
123123
}
124124
return env, nil

internal/services/services.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ func toggleServices(
4646
if err != nil {
4747
return err
4848
}
49+
env := []string{}
50+
for k, v := range envVars {
51+
env = append(env, fmt.Sprintf("%s=%s", k, v))
52+
}
4953
contextChannels := []<-chan struct{}{}
5054
for _, name := range serviceNames {
5155
service, found := services[name]
@@ -59,7 +63,7 @@ func toggleServices(
5963
)
6064
cmd.Stdout = w
6165
cmd.Stderr = w
62-
cmd.Env = envVars
66+
cmd.Env = env
6367
cmd.Env = append(cmd.Env, os.Environ()...)
6468
if err = cmd.Run(); err != nil {
6569
actionString := lo.Ternary(action == startService, "start", "stop")

0 commit comments

Comments
 (0)