Skip to content

Commit

Permalink
Handle nil
Browse files Browse the repository at this point in the history
  • Loading branch information
ldemailly committed Nov 3, 2023
1 parent bf659cf commit bb5c713
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 8 deletions.
39 changes: 34 additions & 5 deletions env/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,30 @@ func ToShellWithPrefix(prefix string, kvl []KeyValue) string {
return sb.String()
}

func SerializeValue(value interface{}) string {
switch v := value.(type) {
case bool:
res := "false"
if v {
res = "true"
}
return res
case string:
return strconv.Quote(v)
default:
return strconv.Quote(fmt.Sprint(value))
}
}

func kindIsIn(k reflect.Kind, kinds ...reflect.Kind) bool {
for _, kind := range kinds {
if k == kind {
return true
}
}
return false
}

// StructToEnvVars converts a struct to a map of environment variables.
// The struct can have a `env` tag on each field.
// The tag should be in the format `env:"ENV_VAR_NAME"`.
Expand All @@ -119,16 +143,21 @@ func StructToEnvVars(s interface{}) []KeyValue {
}
t := v.Type()
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
tag := field.Tag.Get("env")
fieldType := t.Field(i)
tag := fieldType.Tag.Get("env")
if tag == "-" {
continue
}
if tag == "" {
tag = CamelCaseToUpperSnakeCase(field.Name)
tag = CamelCaseToUpperSnakeCase(fieldType.Name)
}
fieldValue := v.Field(i)
stringValue := ""
if !kindIsIn(fieldValue.Kind(), reflect.Ptr, reflect.Map, reflect.Array, reflect.Chan, reflect.Slice) {
value := fieldValue.Interface()
stringValue = SerializeValue(value)
}
value := v.Field(i).Interface()
envVars = append(envVars, KeyValue{Key: tag, Value: strconv.Quote(fmt.Sprint(value))})
envVars = append(envVars, KeyValue{Key: tag, Value: stringValue})
}
return envVars
}
12 changes: 9 additions & 3 deletions env/env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,32 +98,38 @@ type FooConfig struct {
Foo string
Bar string
Blah int `env:"A_SPECIAL_BLAH"`
ABool bool
NotThere int `env:"-"`
HTTPServer string
IntPointer *int
}

func TestStructToEnvVars(t *testing.T) {
foo := FooConfig{
Foo: "a\nfoo with \" quotes and \\ and '",
Bar: "42str",
Blah: 42,
ABool: true,
NotThere: 13,
HTTPServer: "http://localhost:8080",
IntPointer: nil,
}
empty := env.StructToEnvVars(42) // error/empty
if len(empty) != 0 {
t.Errorf("expected empty, got %v", empty)
}
envVars := env.StructToEnvVars(&foo)
if len(envVars) != 4 {
t.Errorf("expected 4 env vars, got %+v", envVars)
if len(envVars) != 6 {
t.Errorf("expected 4 env vars, got %d: %+v", len(envVars), envVars)
}
str := env.ToShellWithPrefix("TST_", envVars)
expected := `TST_FOO="a\nfoo with \" quotes and \\ and '"
TST_BAR="42str"
TST_A_SPECIAL_BLAH="42"
TST_A_BOOL=true
TST_HTTP_SERVER="http://localhost:8080"
export TST_FOO TST_BAR TST_A_SPECIAL_BLAH TST_HTTP_SERVER
TST_INT_POINTER=
export TST_FOO TST_BAR TST_A_SPECIAL_BLAH TST_A_BOOL TST_HTTP_SERVER TST_INT_POINTER
`
if str != expected {
t.Errorf("\n---expected:---\n%s\n---got:---\n%s", expected, str)
Expand Down

0 comments on commit bb5c713

Please sign in to comment.