env/env.go

242 lines
5.0 KiB
Go
Raw Normal View History

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
)
2018-07-11 11:53:49 +08:00
var env *Env
type Env struct {
ignorePrefix bool
}
func init() {
env = &Env{false}
}
2018-07-10 21:00:31 +08:00
func upper(v string) string {
return strings.ToUpper(v)
}
2018-07-11 11:53:49 +08:00
func IgnorePrefix() {
env.ignorePrefix = true
}
2018-07-10 21:00:31 +08:00
func Fill(v interface{}) error {
2018-07-11 11:53:49 +08:00
return env.Fill(v)
}
func (e *Env)Fill(v interface{}) error {
ind := reflect.Indirect(reflect.ValueOf(v))
if reflect.ValueOf(v).Kind() != reflect.Ptr || ind.Kind() != reflect.Struct{
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
}
2018-07-11 11:53:49 +08:00
2018-07-10 21:00:31 +08:00
prefix := upper(ind.Type().Name())
2018-07-11 11:53:49 +08:00
if e.ignorePrefix {
prefix = ""
}
2018-07-10 21:00:31 +08:00
err := fill(prefix, ind)
if err != nil {
return err
}
return nil
}
2018-07-11 11:53:49 +08:00
func combine(p, n string, sep string, ok bool) string {
if p == "" {
return n
}
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
}
2018-07-11 11:53:49 +08:00
return p + sep + n
2018-07-10 21:00:31 +08:00
}
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 {
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 {
2018-07-11 11:53:49 +08:00
return fmt.Errorf("%s:%s", prefix, err)
2018-07-10 21:00:31 +08:00
}
f.SetInt(iv)
case reflect.Int64:
if f.Type().String() == "time.Duration" {
t, err := time.ParseDuration(ev)
if err != nil {
2018-07-11 11:53:49 +08:00
return fmt.Errorf("%s:%s", prefix, err)
2018-07-10 21:00:31 +08:00
}
f.Set(reflect.ValueOf(t))
} else {
iv, err := strconv.ParseInt(ev, 10, 64)
if err != nil {
2018-07-11 11:53:49 +08:00
return fmt.Errorf("%s:%s", prefix, err)
2018-07-10 21:00:31 +08:00
}
f.SetInt(iv)
}
case reflect.Uint:
uiv, err := strconv.ParseUint(ev, 10, 32)
if err != nil {
2018-07-11 11:53:49 +08:00
return fmt.Errorf("%s:%s", prefix, err)
2018-07-10 21:00:31 +08:00
}
f.SetUint(uiv)
case reflect.Uint64:
uiv, err := strconv.ParseUint(ev, 10, 64)
if err != nil {
2018-07-11 11:53:49 +08:00
return fmt.Errorf("%s:%s", prefix, err)
2018-07-10 21:00:31 +08:00
}
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 {
2018-07-11 11:53:49 +08:00
return fmt.Errorf("%s:%s", prefix, err)
2018-07-10 21:00:31 +08:00
}
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 {
2018-07-11 11:53:49 +08:00
return fmt.Errorf("%s:%s", prefix, err)
2018-07-10 21:00:31 +08:00
}
f.SetFloat(f64)
case reflect.Bool:
b, err := parseBool(ev)
if err != nil {
2018-07-11 11:53:49 +08:00
return fmt.Errorf("%s:%s", prefix, err)
2018-07-10 21:00:31 +08:00
}
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 {
2018-07-11 11:53:49 +08:00
return fmt.Errorf("%s:%s", prefix, err)
2018-07-10 22:14:10 +08:00
}
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 {
2018-07-11 11:53:49 +08:00
return fmt.Errorf("%s:%s", prefix, err)
2018-07-10 22:14:10 +08:00
}
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 {
2018-07-11 11:53:49 +08:00
return fmt.Errorf("%s:%s", prefix, err)
2018-07-10 22:14:10 +08:00
}
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 {
2018-07-11 11:53:49 +08:00
return fmt.Errorf("%s:%s", prefix, err)
2018-07-10 22:14:10 +08:00
}
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 {
2018-07-11 11:53:49 +08:00
return fmt.Errorf("%s:%s", prefix, err)
2018-07-10 22:14:10 +08:00
}
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 {
2018-07-11 11:53:49 +08:00
return fmt.Errorf("%s:%s", prefix, err)
2018-07-10 22:14:10 +08:00
}
t[i] = val
}
case reflect.TypeOf([]bool{}):
t := make([]bool, len(vals))
for i, v := range vals {
val, err := parseBool(v)
if err != nil {
2018-07-11 11:53:49 +08:00
return fmt.Errorf("%s:%s", prefix, err)
2018-07-10 22:14:10 +08:00
}
t[i] = val
}
}
2018-07-10 21:00:31 +08:00
}
return nil
2018-07-10 22:14:10 +08:00
}