90 lines
2.1 KiB
Go
90 lines
2.1 KiB
Go
package config
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
func getEnvVar(value reflect.Value, rtype reflect.Type, counter int, prefix string) error {
|
|
if value.Kind() != reflect.Ptr {
|
|
return errors.New("not a pointer value")
|
|
}
|
|
f := reflect.StructField{}
|
|
if counter != -1 {
|
|
f = rtype.Field(counter)
|
|
}
|
|
value = reflect.Indirect(value)
|
|
fName := strings.ToUpper(f.Name)
|
|
if prefix != "" {
|
|
prefix = strings.TrimLeft(prefix, "_")
|
|
}
|
|
|
|
env := os.Getenv(prefix + fName)
|
|
if err := selector(env, &value); err != nil {
|
|
return fmt.Errorf("could set value: %w", err)
|
|
}
|
|
if value.Kind() == reflect.Struct {
|
|
for i := 0; i < value.NumField(); i++ {
|
|
if err := getEnvVar(value.Field(i).Addr(), value.Type(), i, prefix+fName+"_"); err != nil {
|
|
return fmt.Errorf("could not apply env var: %w", err)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func parseToStruct(value reflect.Value, rtype reflect.Type, counter int, prefix string, index map[string]string) error {
|
|
if value.Kind() != reflect.Ptr {
|
|
return errors.New("not a pointer value")
|
|
}
|
|
f := reflect.StructField{}
|
|
if counter != -1 {
|
|
f = rtype.Field(counter)
|
|
}
|
|
value = reflect.Indirect(value)
|
|
fName := strings.ToLower(f.Name)
|
|
if prefix != "" {
|
|
prefix = strings.TrimLeft(prefix, ".")
|
|
}
|
|
|
|
env := index[prefix+fName]
|
|
if err := selector(env, &value); err != nil {
|
|
return fmt.Errorf("could set value: %w", err)
|
|
}
|
|
if value.Kind() == reflect.Struct {
|
|
for i := 0; i < value.NumField(); i++ {
|
|
if err := parseToStruct(value.Field(i).Addr(), value.Type(), i, prefix+fName+".", index); err != nil {
|
|
return fmt.Errorf("could not apply env var: %w", err)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func selector(env string, value *reflect.Value) error {
|
|
if env != "" {
|
|
//nolint:exhaustive
|
|
switch value.Kind() {
|
|
case reflect.Int:
|
|
envI, err := strconv.Atoi(env)
|
|
if err != nil {
|
|
return fmt.Errorf("could not parse to int: %w", err)
|
|
}
|
|
value.SetInt(int64(envI))
|
|
case reflect.String:
|
|
value.SetString(env)
|
|
case reflect.Bool:
|
|
envB, err := strconv.ParseBool(env)
|
|
if err != nil {
|
|
return fmt.Errorf("could not parse bool: %w", err)
|
|
}
|
|
value.SetBool(envB)
|
|
}
|
|
}
|
|
return nil
|
|
}
|