From 748d53153bee15d81e9f9440e657fdced51ab252 Mon Sep 17 00:00:00 2001 From: Ulysses Souza Date: Mon, 4 Jul 2022 16:00:06 +0200 Subject: [PATCH] Fix lookup precedence Signed-off-by: Ulysses Souza --- cli/options.go | 4 -- dotenv/fixtures/substitutions-default.env | 5 ++ dotenv/fixtures/substitutions.env | 2 +- dotenv/godotenv_test.go | 64 +++++++++++++++++++++-- dotenv/parser.go | 4 -- loader/full-struct_test.go | 6 +-- loader/loader.go | 3 ++ 7 files changed, 73 insertions(+), 15 deletions(-) create mode 100644 dotenv/fixtures/substitutions-default.env diff --git a/cli/options.go b/cli/options.go index f42c67aa..e457b434 100644 --- a/cli/options.go +++ b/cli/options.go @@ -242,7 +242,6 @@ func GetEnvFromFile(currentEnv map[string]string, workingDir string, filename st env, err := dotenv.ParseWithLookup(file, func(k string) (string, bool) { v, ok := currentEnv[k] if !ok { - return "", false } return v, true @@ -251,9 +250,6 @@ func GetEnvFromFile(currentEnv map[string]string, workingDir string, filename st return envMap, err } for k, v := range env { - if _, set := currentEnv[k]; set { - continue - } envMap[k] = v } diff --git a/dotenv/fixtures/substitutions-default.env b/dotenv/fixtures/substitutions-default.env new file mode 100644 index 00000000..525dc131 --- /dev/null +++ b/dotenv/fixtures/substitutions-default.env @@ -0,0 +1,5 @@ +OPTION_A=${OPTION_A:-1} +OPTION_B=${OPTION_A} +OPTION_C=$OPTION_B +OPTION_D=${OPTION_A}_${OPTION_B} +OPTION_E=${OPTION_NOT_DEFINED} diff --git a/dotenv/fixtures/substitutions.env b/dotenv/fixtures/substitutions.env index 44337a99..6eb0868a 100644 --- a/dotenv/fixtures/substitutions.env +++ b/dotenv/fixtures/substitutions.env @@ -1,5 +1,5 @@ OPTION_A=1 OPTION_B=${OPTION_A} OPTION_C=$OPTION_B -OPTION_D=${OPTION_A}${OPTION_B} +OPTION_D=${OPTION_A}_${OPTION_B} OPTION_E=${OPTION_NOT_DEFINED} diff --git a/dotenv/godotenv_test.go b/dotenv/godotenv_test.go index e0dde43f..b8ff6aea 100644 --- a/dotenv/godotenv_test.go +++ b/dotenv/godotenv_test.go @@ -218,7 +218,7 @@ func TestSubstitutions(t *testing.T) { "OPTION_A": "1", "OPTION_B": "1", "OPTION_C": "1", - "OPTION_D": "11", + "OPTION_D": "1_1", "OPTION_E": "", } @@ -614,7 +614,7 @@ func TestExpendingEnvironmentWithLookup(t *testing.T) { } } -func TestSubstitutionsWithShellEnvPrecedence(t *testing.T) { +func TestSubstitutionsWithEnvFilePrecedence(t *testing.T) { os.Clearenv() const envKey = "OPTION_A" const envVal = "5" @@ -622,11 +622,69 @@ func TestSubstitutionsWithShellEnvPrecedence(t *testing.T) { defer os.Unsetenv(envKey) envFileName := "fixtures/substitutions.env" + expectedValues := map[string]string{ + "OPTION_A": "1", + "OPTION_B": "1", + "OPTION_C": "1", + "OPTION_D": "1_1", + "OPTION_E": "", + } + + envMap, err := ReadWithLookup(os.LookupEnv, envFileName) + if err != nil { + t.Error("Error reading file") + } + if len(envMap) != len(expectedValues) { + t.Error("Didn't get the right size map back") + } + + for key, value := range expectedValues { + if envMap[key] != value { + t.Errorf("Read got one of the keys wrong, [%q]->%q", key, envMap[key]) + } + } +} + +func TestSubstitutionsWithEnvFileDefaultValuePrecedence(t *testing.T) { + os.Clearenv() + const envKey = "OPTION_A" + const envVal = "5" + os.Setenv(envKey, envVal) + defer os.Unsetenv(envKey) + + envFileName := "fixtures/substitutions-default.env" expectedValues := map[string]string{ "OPTION_A": "5", "OPTION_B": "5", "OPTION_C": "5", - "OPTION_D": "55", + "OPTION_D": "5_5", + "OPTION_E": "", + } + + envMap, err := ReadWithLookup(os.LookupEnv, envFileName) + if err != nil { + t.Error("Error reading file") + } + if len(envMap) != len(expectedValues) { + t.Error("Didn't get the right size map back") + } + + for key, value := range expectedValues { + if envMap[key] != value { + t.Errorf("Read got one of the keys wrong, [%q]->%q", key, envMap[key]) + } + } +} + +func TestSubstitutionsWithUnsetVarEnvFileDefaultValuePrecedence(t *testing.T) { + os.Clearenv() + + envFileName := "fixtures/substitutions-default.env" + expectedValues := map[string]string{ + "OPTION_A": "1", + "OPTION_B": "1", + "OPTION_C": "1", + "OPTION_D": "1_1", "OPTION_E": "", } diff --git a/dotenv/parser.go b/dotenv/parser.go index e049123d..ecb94ee9 100644 --- a/dotenv/parser.go +++ b/dotenv/parser.go @@ -37,7 +37,6 @@ func parseBytes(src []byte, out map[string]string, lookupFn LookupFn) error { } if inherited { - value, ok := lookupFn(key) if ok { out[key] = value @@ -50,9 +49,6 @@ func parseBytes(src []byte, out map[string]string, lookupFn LookupFn) error { if err != nil { return err } - if lookUpValue, ok := lookupFn(key); ok { - value = lookUpValue - } out[key] = value cutset = left diff --git a/loader/full-struct_test.go b/loader/full-struct_test.go index b606e446..c3c7260e 100644 --- a/loader/full-struct_test.go +++ b/loader/full-struct_test.go @@ -165,7 +165,7 @@ func services(workingDir, homeDir string) []types.ServiceConfig { Entrypoint: []string{"/code/entrypoint.sh", "-p", "3000"}, Environment: map[string]*string{ "FOO": strPtr("foo_from_env_file"), - "BAR": strPtr("this is a secret"), + "BAR": strPtr("bar_from_env_file_2"), "BAZ": strPtr("baz_from_service_def"), "QUX": strPtr("qux_from_environment"), "ENV.WITH.DOT": strPtr("ok"), @@ -692,7 +692,7 @@ services: - -p - "3000" environment: - BAR: this is a secret + BAR: bar_from_env_file_2 BAZ: baz_from_service_def ENV.WITH.DOT: ok ENV_WITH_UNDERSCORE: ok @@ -1265,7 +1265,7 @@ func fullExampleJSON(workingDir, homeDir string) string { "3000" ], "environment": { - "BAR": "this is a secret", + "BAR": "bar_from_env_file_2", "BAZ": "baz_from_service_def", "ENV.WITH.DOT": "ok", "ENV_WITH_UNDERSCORE": "ok", diff --git a/loader/loader.go b/loader/loader.go index 2394ed15..acf11a95 100644 --- a/loader/loader.go +++ b/loader/loader.go @@ -624,6 +624,9 @@ func resolveEnvironment(serviceConfig *types.ServiceConfig, workingDir string, l environment := types.MappingWithEquals{} if len(serviceConfig.EnvFile) > 0 { + if serviceConfig.Environment == nil { + serviceConfig.Environment = types.MappingWithEquals{} + } for _, envFile := range serviceConfig.EnvFile { filePath := absPath(workingDir, envFile) file, err := os.Open(filePath)