2018-07-10 21:00:31 +08:00
|
|
|
|
package env
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"reflect"
|
|
|
|
|
"strings"
|
|
|
|
|
"strconv"
|
|
|
|
|
"os"
|
|
|
|
|
"fmt"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
var (
|
2018-07-10 22:27:19 +08:00
|
|
|
|
defaultSep = "_"
|
2018-07-10 21:00:31 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func upper(v string) string {
|
|
|
|
|
return strings.ToUpper(v)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Fill(v interface{}) error {
|
|
|
|
|
if reflect.ValueOf(v).Kind() != reflect.Ptr {
|
2018-07-10 22:27:19 +08:00
|
|
|
|
return fmt.Errorf("only the pointer to a struct is supported")
|
2018-07-10 21:00:31 +08:00
|
|
|
|
}
|
|
|
|
|
ind := reflect.Indirect(reflect.ValueOf(v))
|
|
|
|
|
prefix := upper(ind.Type().Name())
|
|
|
|
|
err := fill(prefix, ind)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-10 22:27:19 +08:00
|
|
|
|
func combine(p, n string, v string, ok bool) string {
|
2018-07-10 21:00:31 +08:00
|
|
|
|
if !ok {
|
2018-07-10 22:27:19 +08:00
|
|
|
|
return p + defaultSep + n
|
2018-07-10 21:00:31 +08:00
|
|
|
|
}
|
|
|
|
|
return p + v + n
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func parseBool(v string) (bool, error) {
|
|
|
|
|
if v == "" {
|
|
|
|
|
return false, nil
|
|
|
|
|
}
|
|
|
|
|
return strconv.ParseBool(v)
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-10 22:27:19 +08:00
|
|
|
|
func fill(pf string, ind reflect.Value) error {
|
2018-07-10 21:00:31 +08:00
|
|
|
|
for i := 0; i < ind.NumField(); i++ {
|
|
|
|
|
f := ind.Type().Field(i)
|
|
|
|
|
name := f.Name
|
|
|
|
|
envName, exist := f.Tag.Lookup("env")
|
|
|
|
|
if exist {
|
|
|
|
|
name = envName
|
|
|
|
|
}
|
|
|
|
|
s, exist := f.Tag.Lookup("sep")
|
|
|
|
|
p := combine(pf, upper(name), s, exist)
|
|
|
|
|
switch ind.Field(i).Kind() {
|
|
|
|
|
case reflect.Struct:
|
|
|
|
|
err := fill(p, ind.Field(i))
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
err := parse(p, ind.Field(i), f)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func parse(prefix string, f reflect.Value, sf reflect.StructField) error {
|
2018-07-10 22:14:10 +08:00
|
|
|
|
//log.Print("parse:", prefix, f.String(), f.Type().String(), f.Kind().String())
|
2018-07-10 21:00:31 +08:00
|
|
|
|
df := sf.Tag.Get("default")
|
|
|
|
|
isRequire, err := parseBool(sf.Tag.Get("require"))
|
|
|
|
|
if err != nil {
|
2018-07-10 22:27:19 +08:00
|
|
|
|
return fmt.Errorf("the value of %s is not a valid `member` of bool ,only "+
|
|
|
|
|
"[1 0 t f T F true false TRUE FALSE True False] are supported", prefix)
|
2018-07-10 21:00:31 +08:00
|
|
|
|
}
|
|
|
|
|
ev, exist := os.LookupEnv(prefix)
|
|
|
|
|
|
|
|
|
|
if !exist && isRequire {
|
2018-07-10 22:27:19 +08:00
|
|
|
|
return fmt.Errorf("%s is required, but has not been set", prefix)
|
2018-07-10 21:00:31 +08:00
|
|
|
|
}
|
|
|
|
|
if !exist && df != "" {
|
|
|
|
|
ev = df
|
|
|
|
|
}
|
2018-07-10 22:14:10 +08:00
|
|
|
|
//log.Print("ev:", ev)
|
2018-07-10 21:00:31 +08:00
|
|
|
|
switch f.Kind() {
|
|
|
|
|
case reflect.String:
|
2018-07-10 22:14:10 +08:00
|
|
|
|
f.SetString(ev)
|
2018-07-10 21:00:31 +08:00
|
|
|
|
case reflect.Int:
|
|
|
|
|
iv, err := strconv.ParseInt(ev, 10, 32)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
f.SetInt(iv)
|
|
|
|
|
case reflect.Int64:
|
|
|
|
|
if f.Type().String() == "time.Duration" {
|
|
|
|
|
t, err := time.ParseDuration(ev)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
f.Set(reflect.ValueOf(t))
|
|
|
|
|
} else {
|
|
|
|
|
iv, err := strconv.ParseInt(ev, 10, 64)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
f.SetInt(iv)
|
|
|
|
|
}
|
|
|
|
|
case reflect.Uint:
|
|
|
|
|
uiv, err := strconv.ParseUint(ev, 10, 32)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
f.SetUint(uiv)
|
|
|
|
|
case reflect.Uint64:
|
|
|
|
|
uiv, err := strconv.ParseUint(ev, 10, 64)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
f.SetUint(uiv)
|
|
|
|
|
case reflect.Float32:
|
2018-07-10 22:27:19 +08:00
|
|
|
|
f32, err := strconv.ParseFloat(ev, 32)
|
2018-07-10 21:00:31 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
f.SetFloat(f32)
|
|
|
|
|
case reflect.Float64:
|
2018-07-10 22:27:19 +08:00
|
|
|
|
f64, err := strconv.ParseFloat(ev, 64)
|
2018-07-10 21:00:31 +08:00
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
f.SetFloat(f64)
|
|
|
|
|
case reflect.Bool:
|
|
|
|
|
b, err := parseBool(ev)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
f.SetBool(b)
|
2018-07-10 22:14:10 +08:00
|
|
|
|
case reflect.Slice:
|
|
|
|
|
sep := ";"
|
|
|
|
|
s, exist := sf.Tag.Lookup("slice_sep")
|
|
|
|
|
if exist && s != "" {
|
|
|
|
|
sep = s
|
|
|
|
|
}
|
|
|
|
|
vals := strings.Split(ev, sep)
|
|
|
|
|
switch f.Type() {
|
|
|
|
|
case reflect.TypeOf([]string{}):
|
|
|
|
|
f.Set(reflect.ValueOf(vals))
|
|
|
|
|
case reflect.TypeOf([]int{}):
|
|
|
|
|
t := make([]int, len(vals))
|
|
|
|
|
for i, v := range vals {
|
|
|
|
|
val, err := strconv.ParseInt(v, 10, 32)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
t[i] = int(val)
|
|
|
|
|
}
|
|
|
|
|
case reflect.TypeOf([]int64{}):
|
|
|
|
|
t := make([]int64, len(vals))
|
|
|
|
|
for i, v := range vals {
|
|
|
|
|
val, err := strconv.ParseInt(v, 10, 64)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
t[i] = val
|
|
|
|
|
}
|
|
|
|
|
case reflect.TypeOf([]uint{}):
|
|
|
|
|
t := make([]uint, len(vals))
|
|
|
|
|
for i, v := range vals {
|
|
|
|
|
val, err := strconv.ParseUint(v, 10, 32)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
t[i] = uint(val)
|
|
|
|
|
}
|
|
|
|
|
case reflect.TypeOf([]uint64{}):
|
|
|
|
|
t := make([]uint64, len(vals))
|
|
|
|
|
for i, v := range vals {
|
|
|
|
|
val, err := strconv.ParseUint(v, 10, 64)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
t[i] = val
|
|
|
|
|
}
|
|
|
|
|
case reflect.TypeOf([]float32{}):
|
|
|
|
|
t := make([]float32, len(vals))
|
|
|
|
|
for i, v := range vals {
|
|
|
|
|
val, err := strconv.ParseFloat(v, 32)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
t[i] = float32(val)
|
|
|
|
|
}
|
|
|
|
|
case reflect.TypeOf([]float64{}):
|
|
|
|
|
t := make([]float64, len(vals))
|
|
|
|
|
for i, v := range vals {
|
|
|
|
|
val, err := strconv.ParseFloat(v, 64)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
t[i] = val
|
|
|
|
|
}
|
|
|
|
|
case reflect.TypeOf([]bool{}):
|
|
|
|
|
t := make([]bool, len(vals))
|
|
|
|
|
for i, v := range vals {
|
|
|
|
|
val, err := parseBool(v)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
t[i] = val
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-07-10 21:00:31 +08:00
|
|
|
|
}
|
|
|
|
|
return nil
|
2018-07-10 22:14:10 +08:00
|
|
|
|
}
|