78 lines
1.8 KiB
Go
78 lines
1.8 KiB
Go
package config
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
func ReadEnv(c *Config, prefix string) (namesAvailable, namesUsed []string) {
|
|
return structFromEnv(reflect.ValueOf(c), reflect.TypeOf(c), prefix)
|
|
}
|
|
|
|
func structFromEnv(v reflect.Value, t reflect.Type, prefix string) (namesAvailable, namesUsed []string) {
|
|
|
|
if v.Kind() == reflect.Ptr {
|
|
v = v.Elem()
|
|
t = t.Elem()
|
|
}
|
|
|
|
for i := 0; i < v.NumField(); i++ {
|
|
fv := v.Field(i)
|
|
ft := t.Field(i)
|
|
tag := ft.Tag.Get("env")
|
|
if !ft.IsExported() || tag == "-" {
|
|
continue
|
|
}
|
|
|
|
name := ft.Name
|
|
if tag != "" {
|
|
name = tag
|
|
}
|
|
|
|
if fv.Kind() == reflect.Struct {
|
|
na, nu := structFromEnv(fv, ft.Type, prefix+"_"+name)
|
|
namesAvailable = append(namesAvailable, na...)
|
|
namesUsed = append(namesUsed, nu...)
|
|
} else if !ft.Anonymous {
|
|
envName := strings.ToUpper(prefix + "_" + name)
|
|
namesAvailable = append(namesAvailable, envName)
|
|
|
|
val, ok := os.LookupEnv(envName)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if !fv.CanSet() {
|
|
panic("cannot set field for environment variable " + envName)
|
|
}
|
|
|
|
switch fk := fv.Kind(); fk {
|
|
case reflect.String:
|
|
fv.SetString(val)
|
|
case reflect.Int:
|
|
x, err := strconv.ParseInt(val, 10, 0)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
fv.SetInt(x)
|
|
case reflect.Bool:
|
|
switch strings.ToLower(val) {
|
|
case "1", "true", "t", "on":
|
|
fv.SetBool(true)
|
|
case "0", "false", "f", "off":
|
|
fv.SetBool(false)
|
|
default:
|
|
panic(fmt.Sprintf("cannot set field for environment variable %s: cannot parse %s as boolean. Please use one of: 1, true, t, on / 0, false, f, off", envName, fk))
|
|
}
|
|
default:
|
|
panic(fmt.Sprintf("cannot set field for environment variable %s: type %s is not supported", envName, fk))
|
|
}
|
|
namesUsed = append(namesUsed, envName)
|
|
}
|
|
|
|
}
|
|
return namesAvailable, namesUsed
|
|
}
|