From dba0cd229e9f42ea1e79d859680e857fadeaac68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mike=20Schw=C3=B6rer?= Date: Tue, 7 Mar 2023 10:43:30 +0100 Subject: [PATCH] v0.0.89 --- confext/confParser.go | 191 ++++++++++++++++++++----------------- confext/confParser_test.go | 57 +++++++++++ 2 files changed, 158 insertions(+), 90 deletions(-) diff --git a/confext/confParser.go b/confext/confParser.go index 530e6e1..4e94d81 100644 --- a/confext/confParser.go +++ b/confext/confParser.go @@ -70,103 +70,114 @@ func processEnvOverrides(rval reflect.Value, delim string, prefix string) error continue } - if rvfield.Type() == reflect.TypeOf("") { + if rvfield.Type().Kind() == reflect.Pointer { - rvfield.Set(reflect.ValueOf(envval)) + newval, err := parseEnvToValue(envval, fullEnvKey, rvfield.Type().Elem()) + if err != nil { + return err + } + + // converts reflect.Value to pointer + ptrval := reflect.New(rvfield.Type().Elem()) + ptrval.Elem().Set(newval) + + rvfield.Set(ptrval) fmt.Printf("[CONF] Overwrite config '%s' with '%s'\n", fullEnvKey, envval) - } else if rvfield.Type() == reflect.TypeOf(int(0)) { - - envint, err := strconv.ParseInt(envval, 10, bits.UintSize) - if err != nil { - return errors.New(fmt.Sprintf("Failed to parse env-config variable '%s' to int (value := '%s')", fullEnvKey, envval)) - } - - rvfield.Set(reflect.ValueOf(int(envint))) - - fmt.Printf("[CONF] Overwrite config '%s' with '%s'\n", fullEnvKey, envval) - - } else if rvfield.Type() == reflect.TypeOf(int64(0)) { - - envint, err := strconv.ParseInt(envval, 10, 64) - if err != nil { - return errors.New(fmt.Sprintf("Failed to parse env-config variable '%s' to int64 (value := '%s')", fullEnvKey, envval)) - } - - rvfield.Set(reflect.ValueOf(int64(envint))) - - fmt.Printf("[CONF] Overwrite config '%s' with '%s'\n", fullEnvKey, envval) - - } else if rvfield.Type() == reflect.TypeOf(int32(0)) { - - envint, err := strconv.ParseInt(envval, 10, 32) - if err != nil { - return errors.New(fmt.Sprintf("Failed to parse env-config variable '%s' to int32 (value := '%s')", fullEnvKey, envval)) - } - - rvfield.Set(reflect.ValueOf(int32(envint))) - - fmt.Printf("[CONF] Overwrite config '%s' with '%s'\n", fullEnvKey, envval) - - } else if rvfield.Type() == reflect.TypeOf(int8(0)) { - - envint, err := strconv.ParseInt(envval, 10, 8) - if err != nil { - return errors.New(fmt.Sprintf("Failed to parse env-config variable '%s' to int32 (value := '%s')", fullEnvKey, envval)) - } - - rvfield.Set(reflect.ValueOf(int8(envint))) - - fmt.Printf("[CONF] Overwrite config '%s' with '%s'\n", fullEnvKey, envval) - - } else if rvfield.Type() == reflect.TypeOf(time.Duration(0)) { - - dur, err := timeext.ParseDurationShortString(envval) - if err != nil { - return errors.New(fmt.Sprintf("Failed to parse env-config variable '%s' to duration (value := '%s')", fullEnvKey, envval)) - } - - rvfield.Set(reflect.ValueOf(dur)) - - fmt.Printf("[CONF] Overwrite config '%s' with '%s'\n", fullEnvKey, dur.String()) - - } else if rvfield.Type() == reflect.TypeOf(time.UnixMilli(0)) { - - tim, err := time.Parse(time.RFC3339Nano, envval) - if err != nil { - return errors.New(fmt.Sprintf("Failed to parse env-config variable '%s' to time.time (value := '%s')", fullEnvKey, envval)) - } - - rvfield.Set(reflect.ValueOf(tim)) - - fmt.Printf("[CONF] Overwrite config '%s' with '%s'\n", fullEnvKey, tim.String()) - - } else if rvfield.Type().ConvertibleTo(reflect.TypeOf(int(0))) { - - envint, err := strconv.ParseInt(envval, 10, 8) - if err != nil { - return errors.New(fmt.Sprintf("Failed to parse env-config variable '%s' to <%s, ,int> (value := '%s')", rvfield.Type().Name(), fullEnvKey, envval)) - } - - envcvl := reflect.ValueOf(envint).Convert(rvfield.Type()) - - rvfield.Set(envcvl) - - fmt.Printf("[CONF] Overwrite config '%s' with '%v'\n", fullEnvKey, envcvl.Interface()) - - } else if rvfield.Type().ConvertibleTo(reflect.TypeOf("")) { - - envcvl := reflect.ValueOf(envval).Convert(rvfield.Type()) - - rvfield.Set(envcvl) - - fmt.Printf("[CONF] Overwrite config '%s' with '%v'\n", fullEnvKey, envcvl.Interface()) - } else { - return errors.New(fmt.Sprintf("Unknown kind/type in config: [ %s | %s ]", rvfield.Kind().String(), rvfield.Type().String())) + + newval, err := parseEnvToValue(envval, fullEnvKey, rvfield.Type()) + if err != nil { + return err + } + + rvfield.Set(newval) + fmt.Printf("[CONF] Overwrite config '%s' with '%s'\n", fullEnvKey, envval) + } + } return nil } + +func parseEnvToValue(envval string, fullEnvKey string, rvtype reflect.Type) (reflect.Value, error) { + if rvtype == reflect.TypeOf("") { + + return reflect.ValueOf(envval), nil + + } else if rvtype == reflect.TypeOf(int(0)) { + + envint, err := strconv.ParseInt(envval, 10, bits.UintSize) + if err != nil { + return reflect.Value{}, errors.New(fmt.Sprintf("Failed to parse env-config variable '%s' to int (value := '%s')", fullEnvKey, envval)) + } + + return reflect.ValueOf(int(envint)), nil + + } else if rvtype == reflect.TypeOf(int64(0)) { + + envint, err := strconv.ParseInt(envval, 10, 64) + if err != nil { + return reflect.Value{}, errors.New(fmt.Sprintf("Failed to parse env-config variable '%s' to int64 (value := '%s')", fullEnvKey, envval)) + } + + return reflect.ValueOf(int64(envint)), nil + + } else if rvtype == reflect.TypeOf(int32(0)) { + + envint, err := strconv.ParseInt(envval, 10, 32) + if err != nil { + return reflect.Value{}, errors.New(fmt.Sprintf("Failed to parse env-config variable '%s' to int32 (value := '%s')", fullEnvKey, envval)) + } + + return reflect.ValueOf(int32(envint)), nil + + } else if rvtype == reflect.TypeOf(int8(0)) { + + envint, err := strconv.ParseInt(envval, 10, 8) + if err != nil { + return reflect.Value{}, errors.New(fmt.Sprintf("Failed to parse env-config variable '%s' to int32 (value := '%s')", fullEnvKey, envval)) + } + + return reflect.ValueOf(int8(envint)), nil + + } else if rvtype == reflect.TypeOf(time.Duration(0)) { + + dur, err := timeext.ParseDurationShortString(envval) + if err != nil { + return reflect.Value{}, errors.New(fmt.Sprintf("Failed to parse env-config variable '%s' to duration (value := '%s')", fullEnvKey, envval)) + } + + return reflect.ValueOf(dur), nil + + } else if rvtype == reflect.TypeOf(time.UnixMilli(0)) { + + tim, err := time.Parse(time.RFC3339Nano, envval) + if err != nil { + return reflect.Value{}, errors.New(fmt.Sprintf("Failed to parse env-config variable '%s' to time.time (value := '%s')", fullEnvKey, envval)) + } + + return reflect.ValueOf(tim), nil + + } else if rvtype.ConvertibleTo(reflect.TypeOf(int(0))) { + + envint, err := strconv.ParseInt(envval, 10, 8) + if err != nil { + return reflect.Value{}, errors.New(fmt.Sprintf("Failed to parse env-config variable '%s' to <%s, ,int> (value := '%s')", rvtype.Name(), fullEnvKey, envval)) + } + + envcvl := reflect.ValueOf(envint).Convert(rvtype) + + return envcvl, nil + + } else if rvtype.ConvertibleTo(reflect.TypeOf("")) { + + envcvl := reflect.ValueOf(envval).Convert(rvtype) + return envcvl, nil + + } else { + return reflect.Value{}, errors.New(fmt.Sprintf("Unknown kind/type in config: [ %s | %s ]", rvtype.Kind().String(), rvtype.String())) + } +} diff --git a/confext/confParser_test.go b/confext/confParser_test.go index ac558d5..967c6ad 100644 --- a/confext/confParser_test.go +++ b/confext/confParser_test.go @@ -213,8 +213,65 @@ func TestApplyEnvOverridesRecursive(t *testing.T) { assertEqual(t, data.Sub4.V9, time.Unix(2335219200, 0).UTC()) } +func TestApplyEnvOverridesPointer(t *testing.T) { + + type aliasint int + type aliasstring string + + type testdata struct { + V1 *int `env:"TEST_V1"` + VX *string `` + V2 *string `env:"TEST_V2"` + V3 *int8 `env:"TEST_V3"` + V4 *int32 `env:"TEST_V4"` + V5 *int64 `env:"TEST_V5"` + V6 *aliasint `env:"TEST_V6"` + VY *aliasint `` + V7 *aliasstring `env:"TEST_V7"` + V8 *time.Duration `env:"TEST_V8"` + V9 *time.Time `env:"TEST_V9"` + } + + data := testdata{} + + t.Setenv("TEST_V1", "846") + t.Setenv("TEST_V2", "hello_world") + t.Setenv("TEST_V3", "6") + t.Setenv("TEST_V4", "333") + t.Setenv("TEST_V5", "-937") + t.Setenv("TEST_V6", "070") + t.Setenv("TEST_V7", "AAAAAA") + t.Setenv("TEST_V8", "1min4s") + t.Setenv("TEST_V9", "2009-11-10T23:00:00Z") + + err := ApplyEnvOverrides(&data, ".") + if err != nil { + t.Errorf("%v", err) + t.FailNow() + } + + assertPtrEqual(t, data.V1, 846) + assertPtrEqual(t, data.V2, "hello_world") + assertPtrEqual(t, data.V3, 6) + assertPtrEqual(t, data.V4, 333) + assertPtrEqual(t, data.V5, -937) + assertPtrEqual(t, data.V6, 70) + assertPtrEqual(t, data.V7, "AAAAAA") + assertPtrEqual(t, data.V8, time.Second*64) + assertPtrEqual(t, data.V9, time.Unix(1257894000, 0).UTC()) +} + func assertEqual[T comparable](t *testing.T, actual T, expected T) { if actual != expected { t.Errorf("values differ: Actual: '%v', Expected: '%v'", actual, expected) } } + +func assertPtrEqual[T comparable](t *testing.T, actual *T, expected T) { + if actual == nil { + t.Errorf("values differ: Actual: NIL, Expected: '%v'", expected) + } + if *actual != expected { + t.Errorf("values differ: Actual: '%v', Expected: '%v'", actual, expected) + } +}