diff --git a/cli.go b/cli.go index 62abb30..50794a6 100644 --- a/cli.go +++ b/cli.go @@ -216,9 +216,19 @@ func GetGeneratedCliFlags[T any](delimiter string) []string { panic("GetGeneratedEnv(...) only supports configs of Struct type") } + o := options{} + FromCli(delimiter)(&o) + cp := newCliLoader[T](&o) + var result []string for _, field := range getFields(true, &a) { - result = append(result, strings.Join(resolvePath(&a, field.path), delimiter)) + + cliName, ok := determineVariableName(&a, cp.o.cli.delimiter, nil, field) + if !ok { + continue + } + + result = append(result, cliName) } return result @@ -311,11 +321,10 @@ func (cp *ciParser[T]) apply(result *T) (somethingSet bool, err error) { field.value = field.value.Elem() } - // if this changes update LoadCli - flagName := strings.Join(resolvePath(dummyCopy, field.path), cp.o.cli.delimiter) - if cp.o.cli.transform != nil { - flagName = cp.o.cli.transform(flagName) - logger.Info("using transform func on cli flag", "before_func", strings.Join(resolvePath(dummyCopy, field.path), cp.o.cli.delimiter), "after_func", flagName) + flagName, ok := determineVariableName(result, cp.o.cli.delimiter, cp.o.cli.transform, field) + if !ok { + // logging done in determine variable + continue } logger.Info("resolved confy path", "resolved_path", flagName, "path", strings.Join(field.path, cp.o.cli.delimiter)) diff --git a/cli_test.go b/cli_test.go index f84d192..7f1c2af 100644 --- a/cli_test.go +++ b/cli_test.go @@ -136,7 +136,6 @@ func TestCliHelperMethod(t *testing.T) { expectedContents := []string{ "Thing", - "Nested", "Nested.NestedVal", } diff --git a/entry_test.go b/entry_test.go index 0e20fd9..83d63db 100644 --- a/entry_test.go +++ b/entry_test.go @@ -1,14 +1,13 @@ package confy import ( - "log/slog" "os" "testing" ) func TestMain(m *testing.M) { - level.Set(slog.LevelDebug) + level.Set(LoggingDisabled) code := m.Run() os.Exit(code) diff --git a/env.go b/env.go index 37d1c01..f784576 100644 --- a/env.go +++ b/env.go @@ -47,9 +47,19 @@ func GetGeneratedEnv[T any](delimiter string) []string { panic("GetGeneratedEnv(...) only supports configs of Struct type") } + o := options{} + FromEnvs(delimiter)(&o) + ep := newEnvLoader[T](&o) + var result []string for _, field := range getFields(true, &a) { - result = append(result, strings.Join(resolvePath(&a, field.path), delimiter)) + + envVariable, ok := determineVariableName(&a, ep.o.env.delimiter, nil, field) + if !ok { + continue + } + + result = append(result, envVariable) } return result @@ -76,34 +86,9 @@ func GetGeneratedEnvWithTransform[T any](delimiter string, transformFunc Transfo func (ep *envParser[T]) apply(result *T) (somethingSet bool, err error) { for _, field := range getFields(true, result) { - // Update GetGeneratedEnv if this changes - envVariable := strings.Join(resolvePath(result, field.path), ep.o.env.delimiter) - if ep.o.env.transform != nil { - envVariable = ep.o.env.transform(envVariable) - logger.Info("using transform func on env variable", "before_func", strings.Join(resolvePath(result, field.path), ep.o.env.delimiter), "after_func", envVariable) - } - - if field.value.Kind() == reflect.Struct { - current := field.value - _, ok := current.Addr().Interface().(encoding.TextUnmarshaler) - if !ok { - logger.Warn("type doesnt implement encoding.TextUnmarshaler skipping looking for an ENV variable for it", "path", strings.Join(field.path, ep.o.env.delimiter)) - continue - } - } - - if field.value.Kind() == reflect.Array || field.value.Kind() == reflect.Slice { - sliceContentType := field.value.Type().Elem() - - switch sliceContentType.Kind() { - case reflect.String, reflect.Int, reflect.Int64, reflect.Float64, reflect.Bool: - default: - inter := reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() - if !reflect.PointerTo(sliceContentType).Implements(inter) { - logger.Warn("type inside of complex slice did not implement encoding.TextUnmarshaler", "path", strings.Join(field.path, ep.o.env.delimiter)) - continue - } - } + envVariable, ok := determineVariableName(result, ep.o.env.delimiter, ep.o.env.transform, field) + if !ok { + continue } value, wasSet := os.LookupEnv(envVariable) diff --git a/env_test.go b/env_test.go index ac93802..6116be9 100644 --- a/env_test.go +++ b/env_test.go @@ -94,7 +94,6 @@ func TestEnvHelperMethod(t *testing.T) { expectedContents := []string{ "Thing", - "Nested", "Nested_NestedVal", } diff --git a/reflection_utils.go b/reflection_utils.go index 5472949..c9bd421 100644 --- a/reflection_utils.go +++ b/reflection_utils.go @@ -1,6 +1,7 @@ package confy import ( + "encoding" "reflect" "strings" ) @@ -158,3 +159,38 @@ func maskSensitive(value string, tag reflect.StructTag) string { return printedValue } + +// determineVariableName returns the variable name after resolving and transforming +// ok: bool indicates whether this is a decodable type +func determineVariableName[T any](result *T, delimiter string, transform Transform, field fieldsData) (string, bool) { + variable := strings.Join(resolvePath(result, field.path), delimiter) + if transform != nil { + variable = transform(variable) + logger.Info("using transform func on variable", "before_func", strings.Join(resolvePath(result, field.path), delimiter), "after_func", variable) + } + + if field.value.Kind() == reflect.Struct { + current := field.value + _, ok := current.Addr().Interface().(encoding.TextUnmarshaler) + if !ok { + logger.Warn("type doesnt implement encoding.TextUnmarshaler skipping looking for an ENV variable for it", "path", strings.Join(field.path, delimiter)) + return "", false + } + } + + if field.value.Kind() == reflect.Array || field.value.Kind() == reflect.Slice { + sliceContentType := field.value.Type().Elem() + + switch sliceContentType.Kind() { + case reflect.String, reflect.Int, reflect.Int64, reflect.Float64, reflect.Bool: + default: + inter := reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() + if !reflect.PointerTo(sliceContentType).Implements(inter) { + logger.Warn("type inside of complex slice did not implement encoding.TextUnmarshaler", "path", strings.Join(field.path, delimiter)) + return "", false + } + } + } + + return variable, true +}