package args import ( "fmt" "math" "strconv" "strings" "time" ) type Arg struct { Env string Flag string Help string Default interface{} Value interface{} ArgType Type } func NewArg(argType Type, key, help string, def interface{}) *Arg { return &Arg{ Env: strings.ToUpper(key), Flag: strings.ToLower(key), Help: help, Default: def, Value: def, ArgType: argType, } } func (a *Arg) String() string { return fmt.Sprintf("[%s $%s/-%s, %v from %v, help %v]", a.ArgType, a.Env, a.Flag, a.Value, a.Default, a.Help, ) } func (a *Arg) Get() interface{} { return a.Value } func (a *Arg) GetInt() int { if a.ArgType != INT { return -1 } if _, ok := a.Value.(int); !ok { return -1 } return a.Value.(int) } func (a *Arg) GetString() string { if a.ArgType != STRING { return "" } if _, ok := a.Value.(string); !ok { return "" } return a.Value.(string) } func (a *Arg) GetBool() bool { if a.ArgType != BOOL { return false } if _, ok := a.Value.(bool); !ok { return false } return a.Value.(bool) } func (a *Arg) GetDuration() time.Duration { if a.ArgType != DURATION { return time.Duration(-1) } if _, ok := a.Value.(time.Duration); !ok { return time.Duration(-1) } return a.Value.(time.Duration) } func (a *Arg) GetTime() time.Time { if a.ArgType != TIME { return time.Date(1995, 1, 1, 0, 0, 0, 0, time.UTC) } if _, ok := a.Value.(time.Time); !ok { return time.Date(1995, 1, 1, 0, 0, 0, 0, time.UTC) } return a.Value.(time.Time) } func (a *Arg) GetFloat() float32 { if a.ArgType != FLOAT { return float32(-1) } if _, ok := a.Value.(float32); !ok { return float32(-1) } return a.Value.(float32) } func (a *Arg) Set(value interface{}) error { err := fmt.Errorf("incompatible set of type %T for arg $%v/-%v type %v", value, a.Env, a.Flag, a.ArgType) switch a.ArgType { case INT: switch value.(type) { case int: a.Value = value.(int) err = nil case string: s := value.(string) var i int if i, err = strconv.Atoi(s); err == nil { a.Value = i err = nil } case float64: f := value.(float64) if f-float64(int(f)) == 0 { a.Value = int(f) err = nil } } case STRING: i, ok := value.(string) if ok { a.Value = i err = nil } case BOOL: i, ok := value.(bool) if ok { a.Value = i err = nil } else if s, ok := value.(string); !ok { } else if i, err = strconv.ParseBool(s); err == nil { a.Value = i err = nil } case DURATION: i, ok := value.(time.Duration) if ok { a.Value = i err = nil } else if s, ok := value.(string); !ok { } else if i, err = time.ParseDuration(s); err == nil { a.Value = i err = nil } case TIME: if i, ok := value.(time.Duration); ok { a.Value = time.Now().Add(i) err = nil } else if j, ok := value.(time.Time); ok { a.Value = j err = nil } else if s, ok := value.(string); !ok { } else if i, err = time.ParseDuration(s); err == nil { a.Value = time.Now().Add(i) err = nil } else { layouts := []string{ "01-02-2006", "01/02/2006", "01-02-06", "01/02/06", "2006-01-02", "2006/01/02", "06-01-02", "06/01/02", "2006-01-02 15:04:05.999999999 -0700 MST", "15:04:05.999999999 -0700 MST", "15:04:05 -0700 MST", "15:04 -0700 MST", "15:04", } for k := range layouts { if j, err = time.Parse(layouts[k], s); err == nil { a.Value = j err = nil break } } if err == nil && s != "" { j, _ := a.Value.(time.Time) if j.Year() < 1980 { n := time.Now() j = j.AddDate(n.Year()-j.Year(), int(n.Month()-j.Month()), n.Day()-j.Day()) j = j.In(time.Local) t := time.Date(2000, 02, 02, 12, 02, 02, 02, time.UTC) l := t.Local() tzDiff := int(math.Abs(float64(t.Hour() - l.Hour()))) j = j.Add(time.Hour * time.Duration(tzDiff)) } a.Value = j } } case FLOAT: if i, ok := value.(float32); ok { a.Value = i err = nil } else if j, ok := value.(float64); ok { a.Value = float32(j) err = nil } else if k, ok := value.(int); ok { a.Value = float32(k) err = nil } else if s, ok := value.(string); !ok { } else if j, err = strconv.ParseFloat(s, 32); err == nil { a.Value = float32(j) err = nil } else if k, err = strconv.Atoi(s); err == nil { a.Value = float32(k) err = nil } } return err }