-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparse.go
More file actions
168 lines (134 loc) · 3.1 KB
/
Copy pathparse.go
File metadata and controls
168 lines (134 loc) · 3.1 KB
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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package confparse
import (
"flag"
"os"
"reflect"
"strconv"
"time"
)
// Parse config container. A container is a pointer to a structure with tags.
func Parse(container interface{}) error {
val, typ := determine(container)
// Find all fields and read tag
for i := 0; i < typ.NumField(); i++ {
name, value, usage, envVar := extractTags(typ.Field(i).Tag)
addr := val.Field(i).Addr().Interface()
if err := declareFlag(name, value, usage, envVar, addr); err != nil {
return err
}
}
// Parse all defined arguments
flag.Parse()
return nil
}
// Determine container value and type
func determine(container interface{}) (val reflect.Value, typ reflect.Type) {
val = reflect.ValueOf(container).Elem()
typ = val.Type()
return
}
// Extract container field tags values
func extractTags(tags reflect.StructTag) (name, value, help, envVar string) {
name = tags.Get("name")
value = tags.Get("value")
help = tags.Get("usage")
envVar = tags.Get("envVar")
return
}
// Declare CLI argument
func declareFlag(name, value, usage, envVar string, addr interface{}) error {
// read environment variable and set as default value
if envVar != "" {
envValue := os.Getenv(envVar)
if envValue != "" {
value = envValue
}
}
switch ptr := addr.(type) {
case *bool:
if v, err := toBool(value); err != nil {
return err
} else {
flag.BoolVar(ptr, name, v, usage)
}
// String argument type
case *string:
flag.StringVar(ptr, name, value, usage)
// Integer argument type
case *int:
if v, err := toInt(value); err != nil {
return err
} else {
flag.IntVar(ptr, name, v, usage)
}
case *int64:
if v, err := toInt64(value); err != nil {
return err
} else {
flag.Int64Var(ptr, name, v, usage)
}
case *uint:
if v, err := toUint(value); err != nil {
return err
} else {
flag.UintVar(ptr, name, v, usage)
}
case *uint64:
if v, err := toUint64(value); err != nil {
return err
} else {
flag.Uint64Var(ptr, name, v, usage)
}
// Time duration argument type
case *time.Duration:
if v, err := toTimeDuration(value); err != nil {
return err
} else {
flag.DurationVar(ptr, name, v, usage)
}
}
return nil
}
// From string value to boolean
func toBool(value string) (result bool, err error) {
if value != "" {
result, err = strconv.ParseBool(value)
}
return
}
func toUint(value string) (result uint, err error) {
if value != "" {
result, err := strconv.ParseUint(value, 10, 64)
if err != nil {
return 0, err
}
return uint(result), nil
}
return
}
func toUint64(value string) (result uint64, err error) {
if value != "" {
result, err = strconv.ParseUint(value, 10, 64)
}
return
}
// From string value to integer value
func toInt(value string) (result int, err error) {
if value != "" {
result, err = strconv.Atoi(value)
}
return
}
func toInt64(value string) (result int64, err error) {
if value != "" {
result, err = strconv.ParseInt(value, 10, 64)
}
return
}
// From string value to time duration
func toTimeDuration(value string) (result time.Duration, err error) {
if value != "" {
result, err = time.ParseDuration(value)
}
return
}