2022-01-23 02:19:32 +01:00
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 )
2022-01-26 00:22:22 +01:00
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 ) )
}
2022-01-23 02:19:32 +01:00
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
}