diff --git a/env_test.go b/env_test.go index 0565f1ebf..e6b9437c6 100644 --- a/env_test.go +++ b/env_test.go @@ -5,7 +5,6 @@ import ( "net/http" "os" "path/filepath" - "reflect" "strings" "testing" "time" @@ -417,10 +416,8 @@ func TestEnv_EphemeralVariableSubstitutionOverride(t *testing.T) { func opsContains[T any](t *testing.T, slice []T, needle T) { t.Helper() - for _, el := range slice { - if reflect.DeepEqual(el, needle) { - return - } + if envars.OpsContains(slice, needle) { + return } t.Fatalf("%v does not contain %v", slice, needle) } diff --git a/envars/ops.go b/envars/ops.go index 283132fac..e1da92990 100644 --- a/envars/ops.go +++ b/envars/ops.go @@ -39,9 +39,15 @@ func (e Envars) System() []string { // // Envars are not modified. func (e Envars) Apply(envRoot string, ops Ops) *Transform { + existingOps := Ops{} + if rawExistingOps, err := UnmarshalOps([]byte(e["HERMIT_ENV_OPS"])); err == nil { + existingOps = rawExistingOps + } transform := transform(envRoot, e) for _, op := range ops { - op.Apply(transform) + if !OpsContains(existingOps, op) { + op.Apply(transform) + } } return transform } @@ -389,6 +395,15 @@ func makeRevertKey(transform *Transform, op Op) string { return fmt.Sprintf("_HERMIT_OLD_%s_%X", op.Envar(), hash.Sum(nil)) } +func OpsContains[T any](slice []T, needle T) bool { + for _, el := range slice { + if reflect.DeepEqual(el, needle) { + return true + } + } + return false +} + // transform returns a Transform with e as the base. func transform(envRoot string, e Envars) *Transform { return &Transform{ diff --git a/envars/ops_test.go b/envars/ops_test.go index a8a16058f..932e59856 100644 --- a/envars/ops_test.go +++ b/envars/ops_test.go @@ -118,6 +118,18 @@ func TestIssue47(t *testing.T) { assert.Equal(t, original, reverted) } +func TestSkipEnvarReapply(t *testing.T) { + original := Envars{ + "PATH": "/bin:/usr/bin", + "HERMIT_ENV_OPS": "[{\"p\":{\"n\":\"PATH\",\"v\":\"/usr/bin\"}}]", + } + ops := Ops{ + &Prepend{Name: "PATH", Value: "/usr/bin"}, + } + actual := original.Apply("/home/user/project", ops).Combined() + assert.Equal(t, original, actual) +} + func TestEncodeDecodeOps(t *testing.T) { actual := Ops{ &Append{"APPEND", "${APPEND}:text"},