4 changed files with 221 additions and 19 deletions
@ -0,0 +1,124 @@
@@ -0,0 +1,124 @@
|
||||
package confenv |
||||
|
||||
import ( |
||||
"fmt" |
||||
"os" |
||||
"reflect" |
||||
"strconv" |
||||
"strings" |
||||
"time" |
||||
) |
||||
|
||||
func process(env map[string]string, envKey string, rv reflect.Value) error { |
||||
rt := rv.Type() |
||||
|
||||
switch rt { |
||||
case reflect.TypeOf(time.Duration(0)): |
||||
if ev, ok := env[envKey]; ok { |
||||
d, err := time.ParseDuration(ev) |
||||
if err != nil { |
||||
return fmt.Errorf("%s: %s", envKey, err) |
||||
} |
||||
rv.Set(reflect.ValueOf(d)) |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
switch rt.Kind() { |
||||
case reflect.String: |
||||
if ev, ok := env[envKey]; ok { |
||||
rv.SetString(ev) |
||||
} |
||||
return nil |
||||
|
||||
case reflect.Int: |
||||
if ev, ok := env[envKey]; ok { |
||||
iv, err := strconv.ParseInt(ev, 10, 64) |
||||
if err != nil { |
||||
return fmt.Errorf("%s: %s", envKey, err) |
||||
} |
||||
rv.SetInt(iv) |
||||
} |
||||
return nil |
||||
|
||||
case reflect.Bool: |
||||
if ev, ok := env[envKey]; ok { |
||||
switch strings.ToLower(ev) { |
||||
case "yes", "true": |
||||
rv.SetBool(true) |
||||
|
||||
case "no", "false": |
||||
rv.SetBool(false) |
||||
|
||||
default: |
||||
return fmt.Errorf("%s: invalid value '%s'", envKey, ev) |
||||
} |
||||
} |
||||
return nil |
||||
|
||||
case reflect.Slice: |
||||
if rt.Elem().Kind() == reflect.String { |
||||
if ev, ok := env[envKey]; ok { |
||||
nv := reflect.Zero(rt) |
||||
for _, sv := range strings.Split(ev, ",") { |
||||
nv = reflect.Append(nv, reflect.ValueOf(sv)) |
||||
} |
||||
rv.Set(nv) |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
case reflect.Map: |
||||
for k := range env { |
||||
if !strings.HasPrefix(k, envKey) { |
||||
continue |
||||
} |
||||
|
||||
tmp := strings.Split(strings.TrimPrefix(k[len(envKey):], "_"), "_") |
||||
mapKey := strings.ToLower(tmp[0]) |
||||
|
||||
nv := rv.MapIndex(reflect.ValueOf(mapKey)) |
||||
zero := reflect.Value{} |
||||
if nv == zero { |
||||
nv = reflect.New(rt.Elem().Elem()) |
||||
rv.SetMapIndex(reflect.ValueOf(mapKey), nv) |
||||
} |
||||
|
||||
err := process(env, envKey+"_"+strings.ToUpper(mapKey), nv.Elem()) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
} |
||||
return nil |
||||
|
||||
case reflect.Struct: |
||||
flen := rt.NumField() |
||||
for i := 0; i < flen; i++ { |
||||
fieldName := rt.Field(i).Name |
||||
|
||||
// process only public fields
|
||||
if fieldName[0] < 'A' || fieldName[0] > 'Z' { |
||||
continue |
||||
} |
||||
|
||||
fieldEnvKey := envKey + "_" + strings.ToUpper(fieldName) |
||||
err := process(env, fieldEnvKey, rv.Field(i)) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
return fmt.Errorf("unsupported type: %v", rt) |
||||
} |
||||
|
||||
func Process(envKey string, v interface{}) error { |
||||
env := make(map[string]string) |
||||
for _, kv := range os.Environ() { |
||||
tmp := strings.Split(kv, "=") |
||||
env[tmp[0]] = tmp[1] |
||||
} |
||||
|
||||
return process(env, envKey, reflect.ValueOf(v).Elem()) |
||||
} |
||||
Loading…
Reference in new issue