From 376d15d7dc74bb3321dc78b372b157db7a1ce5d6 Mon Sep 17 00:00:00 2001
From: Alec Thomas <alec@swapoff.org>
Date: Fri, 25 Mar 2022 13:29:00 +1100
Subject: [PATCH] fix: allow envars to be overriden in active environments

---
 env.go                          | 20 ++++++++++++++++++++
 integration/integration_test.go | 10 ++++++++++
 2 files changed, 30 insertions(+)

diff --git a/env.go b/env.go
index 50fbd9c5..f5338166 100644
--- a/env.go
+++ b/env.go
@@ -748,6 +748,7 @@ func (e *Env) Exec(l *ui.UI, pkg *manifest.Package, binary string, args []string
 		return errors.WithStack(err)
 	}
 	ops := e.allEnvarOpsForPackages(runtimeDeps, pkg, installed...)
+	ops = append(ops, e.systemEnvOverrideOps(ops)...)
 	packageHermitBin, err := e.getPackageRuntimeEnvops(pkg)
 	if err != nil {
 		return errors.WithStack(err)
@@ -777,6 +778,25 @@ func (e *Env) Exec(l *ui.UI, pkg *manifest.Package, binary string, args []string
 	return errors.Errorf("%s: could not find binary %q", pkg, binary)
 }
 
+// systemEnvOverrideOps returns environment variables overrode in an already activated system environment
+func (e *Env) systemEnvOverrideOps(ops envars.Ops) envars.Ops {
+	if activeEnv, ok := os.LookupEnv("HERMIT_ENV"); !ok || activeEnv != e.envDir {
+		return envars.Ops{}
+	}
+
+	system := envars.Parse(os.Environ())
+	changed := system.Apply(e.Root(), ops).Changed(false)
+
+	var overrides envars.Ops
+	for envar := range changed {
+		if v, ok := system[envar]; ok {
+			overrides = append(overrides, &envars.Force{Name: envar, Value: v})
+		}
+	}
+
+	return overrides
+}
+
 func (e *Env) getPackageRuntimeEnvops(pkg *manifest.Package) (envars.Op, error) {
 	// If the package contains a Hermit env, add that to the PATH for runtime dependencies
 	pkgEnv, err := OpenEnv(pkg.Root, e.state, e.packageSource, nil, e.httpClient, e.scriptSums)
diff --git a/integration/integration_test.go b/integration/integration_test.go
index 62684ca7..6e9d3343 100644
--- a/integration/integration_test.go
+++ b/integration/integration_test.go
@@ -265,6 +265,16 @@ func TestIntegration(t *testing.T) {
 			assert test "$(testbin1.sh)" = "FOO=runtimefoo"
 			assert test "$(testbin2.sh)" = "BAR=hermitbar"
 			`},
+		{name: "SystemEnvOverridesAlreadyAcitvatedHermitEnv",
+			preparations: prep{fixture("testenv4"), activate(".")},
+			script: `
+			hermit install testbin1
+			hermit install testbin2
+			export FOO=systemfoo
+			assert test "$(testbin1.sh)" = "FOO=systemfoo"
+			export BAR=systembar
+			assert test "$(testbin2.sh)" = "BAR=systembar"
+			`},
 	}
 
 	checkForShells(t)