-
Notifications
You must be signed in to change notification settings - Fork 16
/
dynamic_var.go
129 lines (119 loc) · 3.32 KB
/
dynamic_var.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package goflags
import (
"errors"
"fmt"
"reflect"
"strconv"
"strings"
)
type dynamicFlag struct {
field interface{}
defaultValue interface{}
name string
}
func (df *dynamicFlag) Set(value string) error {
fieldKind := reflect.TypeOf(df.field).Elem().Kind()
var (
optionWithoutValue bool
pv bool
)
if value == "t" || value == "T" || value == "true" || value == "TRUE" {
pv = true
optionWithoutValue = true
} else if value == "f" || value == "F" || value == "false" || value == "FALSE" {
pv = false
}
switch fieldKind {
case reflect.Bool:
boolField := df.field.(*bool)
*boolField = pv
case reflect.Int:
intField := df.field.(*int)
if optionWithoutValue {
*intField = df.defaultValue.(int)
return nil
}
newValue, err := strconv.Atoi(value)
if err != nil {
return err
}
*intField = newValue
case reflect.Float64:
floatField := df.field.(*float64)
if optionWithoutValue {
*floatField = df.defaultValue.(float64)
return nil
}
newValue, err := strconv.ParseFloat(value, 64)
if err != nil {
return err
}
*floatField = newValue
case reflect.String:
stringField := df.field.(*string)
if optionWithoutValue {
*stringField = df.defaultValue.(string)
return nil
}
*stringField = value
case reflect.Slice:
sliceField := df.field.(*[]string)
if optionWithoutValue {
*sliceField = df.defaultValue.([]string)
return nil
}
*sliceField = append(*sliceField, strings.Split(value, ",")...)
default:
return errors.New("unsupported type")
}
return nil
}
func (df *dynamicFlag) IsBoolFlag() bool {
return true
}
func (df *dynamicFlag) String() string {
return df.name
}
// DynamicVar acts as flag with a default value or a option with value
// example:
//
// var titleSize int
// flagSet.DynamicVar(&titleSize, "title", 50, "first N characters of the title")
//
// > go run ./examples/basic -title or go run ./examples/basic -title=100
// In case of `go run ./examples/basic -title` it will use default value 50
func (flagSet *FlagSet) DynamicVar(field interface{}, long string, defaultValue interface{}, usage string) *FlagData {
return flagSet.DynamicVarP(field, long, "", defaultValue, usage)
}
// DynamicVarP same as DynamicVar but with short name
func (flagSet *FlagSet) DynamicVarP(field interface{}, long, short string, defaultValue interface{}, usage string) *FlagData {
// validate field and defaultValue
if reflect.TypeOf(field).Kind() != reflect.Ptr {
panic(fmt.Errorf("-%v flag field must be a pointer", long))
}
if reflect.TypeOf(field).Elem().Kind() != reflect.TypeOf(defaultValue).Kind() {
panic(fmt.Errorf("-%v flag field and defaultValue mismatch: fied type is %v and defaultValue Type is %T", long, reflect.TypeOf(field).Elem().Kind(), defaultValue))
}
if field == nil {
panic(fmt.Errorf("field cannot be nil for flag -%v", long))
}
var dynamicFlag dynamicFlag
dynamicFlag.field = field
dynamicFlag.name = long
if defaultValue != nil {
dynamicFlag.defaultValue = defaultValue
}
flagData := &FlagData{
usage: usage,
long: long,
defaultValue: defaultValue,
}
if short != "" {
flagData.short = short
flagSet.CommandLine.Var(&dynamicFlag, short, usage)
flagSet.flagKeys.Set(short, flagData)
}
flagSet.CommandLine.Var(&dynamicFlag, long, usage)
flagSet.flagKeys.Set(long, flagData)
return flagData
}