/
generator.go
152 lines (146 loc) · 3.31 KB
/
generator.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package flags
import (
"fmt"
"reflect"
"strings"
"github.com/fatih/structs"
"github.com/m0sth8/cli"
)
const (
DefaultDescTag = "desc"
DefaultFlagTag = "flag"
DefaultEnvTag = "env"
)
type Opts struct {
DescTag string
FlagTag string
Prefix string
EnvPrefix string
}
func GenerateFlags(cfg interface{}, opts ...Opts) []cli.Flag {
prefix := ""
envPrefix := ""
descTag := DefaultDescTag
flagTag := DefaultFlagTag
for _, opt := range opts {
if opt.DescTag != "" {
descTag = opt.DescTag
}
if opt.Prefix != "" {
prefix = opt.Prefix
}
if opt.EnvPrefix != "" {
envPrefix = opt.EnvPrefix
}
}
flags := []cli.Flag{}
s := structs.New(cfg)
srcStruct := reflect.ValueOf(cfg)
if srcStruct.Kind() == reflect.Ptr {
srcStruct = reflect.Indirect(srcStruct)
}
fields:
for _, field := range s.Fields() {
flagName := CamelToFlag(field.Name())
if flagTags := strings.Split(field.Tag(flagTag), ","); len(flagTags) > 0 {
switch fName := flagTags[0]; fName {
case "-":
continue fields
case "":
default:
flagName = fName
}
}
if prefix != "" {
flagName = fmt.Sprintf("%s%s%s", prefix, flagDivider, flagName)
}
envVar := FlagToEnv(flagName)
ignoreEnvPrefix := false
if envTags := strings.Split(field.Tag(DefaultEnvTag), ","); len(envTags) > 0 {
switch envName := envTags[0]; envName {
case "-":
// if tag is `env:"-"` then remove env var
envVar = ""
case "":
// if tag is `env:""` then env var is taken from flag name
default:
// if tag is `env:"NAME"` then env var is envPrefix_flagPrefix_NAME
// if tag is `env:"~NAME"` then env var is NAME
if strings.HasPrefix(envName, "~") {
envVar = envName[1:]
ignoreEnvPrefix = true
} else {
envVar = envName
if prefix != "" {
envVar = fmt.Sprintf("%s%s%s", FlagToEnv(prefix), envDivider, envVar)
}
}
}
}
if envVar != "" && !ignoreEnvPrefix && envPrefix != "" {
envVar = fmt.Sprintf("%s%s%s", envPrefix, envDivider, envVar)
}
usage := field.Tag(descTag)
var f cli.Flag
switch field.Kind() {
case reflect.String:
f = cli.StringFlag{
Name: flagName,
Value: field.Value().(string),
EnvVar: envVar,
Usage: usage,
}
case reflect.Int:
f = cli.IntFlag{
Name: flagName,
Value: field.Value().(int),
EnvVar: envVar,
Usage: usage,
}
case reflect.Bool:
f = cli.BoolFlag{
Name: flagName,
EnvVar: envVar,
Usage: usage,
}
case reflect.Struct:
opt := Opts{
DescTag: descTag,
Prefix: flagName,
FlagTag: flagTag,
EnvPrefix: envPrefix,
}
flags = append(flags, GenerateFlags(field.Value(), opt)...)
case reflect.Slice:
realField := srcStruct.FieldByName(field.Name())
switch realField.Type().Elem().Kind() {
case reflect.String:
slice := &cli.StringSlice{}
for _, s := range field.Value().([]string) {
slice.Set(s)
}
f = cli.StringSliceFlag{
Name: flagName,
EnvVar: envVar,
Usage: usage,
Value: slice,
}
case reflect.Int:
slice := &cli.IntSlice{}
for _, i := range field.Value().([]int) {
slice.Set(fmt.Sprintf("%d", i))
}
f = cli.IntSliceFlag{
Name: flagName,
EnvVar: envVar,
Usage: usage,
Value: slice,
}
}
}
if f != nil {
flags = append(flags, f)
}
}
return flags
}