From 2e16b70e4a3534a67725e25148a70dbb0936640d Mon Sep 17 00:00:00 2001 From: timest Date: Tue, 10 Jul 2018 21:00:31 +0800 Subject: [PATCH] init commit --- .gitignore | 15 ++++++ env.go | 150 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 .gitignore create mode 100644 env.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b66cec6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +# Created by .ignore support plugin (hsz.mobi) +### Go template +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + diff --git a/env.go b/env.go new file mode 100644 index 0000000..f601188 --- /dev/null +++ b/env.go @@ -0,0 +1,150 @@ +package env + +import ( + "reflect" + "strings" + "log" + "strconv" + "os" + "fmt" + "time" +) + +var ( + DEFAULT_SEPARATOR = "_" +) + +func upper(v string) string { + return strings.ToUpper(v) +} + +func Fill(v interface{}) error { + if reflect.ValueOf(v).Kind() != reflect.Ptr { + return fmt.Errorf("Fill只接受指针类型的值") + } + //for _, v := range os.Environ() { + // if strings.HasPrefix(v, "CONFIG") { + // log.Print(v) + // } + //} + ind := reflect.Indirect(reflect.ValueOf(v)) + prefix := upper(ind.Type().Name()) + err := fill(prefix, ind) + if err != nil { + return err + } + return nil +} + +func combine(p, n string, v string, ok bool) string{ + if !ok { + return p + DEFAULT_SEPARATOR + n + } + return p + v + n +} + +func parseBool(v string) (bool, error) { + if v == "" { + return false, nil + } + return strconv.ParseBool(v) +} + +func fill(pf string, ind reflect.Value) error{ + 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 { + log.Print("parse:", prefix, f.String(), f.Type().String(), f.Kind().String()) + df := sf.Tag.Get("default") + isRequire, err := parseBool(sf.Tag.Get("require")) + if err != nil { + return fmt.Errorf("字段:%s require不是合法的布尔值,支持: 1 t T true TRUE True.", prefix) + } + ev, exist := os.LookupEnv(prefix) + + if !exist && isRequire { + return fmt.Errorf("%s 是必须的变量,但没有被设置", prefix) + } + if !exist && df != "" { + ev = df + } + log.Print("ev:", ev) + switch f.Kind() { + case reflect.String: + f.SetString(df) + 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: + f32, err := strconv.ParseFloat(ev, 32) + if err != nil { + return err + } + f.SetFloat(f32) + case reflect.Float64: + f64, err := strconv.ParseFloat(ev, 64) + if err != nil { + return err + } + f.SetFloat(f64) + case reflect.Bool: + b, err := parseBool(ev) + if err != nil { + return err + } + f.SetBool(b) + } + return nil +} \ No newline at end of file