aboutsummaryrefslogtreecommitdiff
path: root/cli/annotated_config.go
diff options
context:
space:
mode:
Diffstat (limited to 'cli/annotated_config.go')
-rw-r--r--cli/annotated_config.go192
1 files changed, 192 insertions, 0 deletions
diff --git a/cli/annotated_config.go b/cli/annotated_config.go
new file mode 100644
index 0000000..feb9c6e
--- /dev/null
+++ b/cli/annotated_config.go
@@ -0,0 +1,192 @@
1package cli
2
3import (
4 "fmt"
5 "log"
6 "reflect"
7 "time"
8
9 "code.crute.us/mcrute/golib/vault"
10 "github.com/spf13/cobra"
11)
12
13func MustGetConfig(cmd *cobra.Command, out interface{}) {
14 if err := GetConfig(cmd, out); err != nil {
15 log.Fatal(err)
16 }
17}
18
19func GetConfig(cmd *cobra.Command, out interface{}) error {
20 t := reflect.TypeOf(out).Elem()
21 o := reflect.ValueOf(out).Elem()
22 o.FieldByName("TemplateGlob").Set(reflect.ValueOf("test"))
23
24 for i := 0; i < t.NumField(); i++ {
25 tf := t.Field(i)
26 f := o.FieldByName(tf.Name)
27
28 // Fields with no name are not considered flags
29 name := tf.Tag.Get("flag")
30 if name == "" {
31 continue
32 }
33
34 switch f.Type().Kind() {
35 case reflect.Bool:
36 v, _ := cmd.Flags().GetBool(name)
37 f.Set(reflect.ValueOf(v))
38 case reflect.String:
39 v, _ := cmd.Flags().GetString(name)
40 f.Set(reflect.ValueOf(v))
41 case reflect.Int:
42 v, _ := cmd.Flags().GetInt(name)
43 f.Set(reflect.ValueOf(v))
44 case reflect.Int32:
45 v, _ := cmd.Flags().GetInt32(name)
46 f.Set(reflect.ValueOf(v))
47 case reflect.Int64:
48 if tf.Type.AssignableTo(reflect.TypeOf(time.Duration(0))) { // time.Duration
49 v, _ := cmd.Flags().GetDuration(name)
50 f.Set(reflect.ValueOf(v))
51 } else {
52 v, _ := cmd.Flags().GetInt64(name)
53 f.Set(reflect.ValueOf(v))
54 }
55 case reflect.Uint:
56 v, _ := cmd.Flags().GetUint(name)
57 f.Set(reflect.ValueOf(v))
58 case reflect.Uint32:
59 v, _ := cmd.Flags().GetUint32(name)
60 f.Set(reflect.ValueOf(v))
61 case reflect.Uint64:
62 v, _ := cmd.Flags().GetUint64(name)
63 f.Set(reflect.ValueOf(v))
64 case reflect.Float32:
65 v, _ := cmd.Flags().GetFloat32(name)
66 f.Set(reflect.ValueOf(v))
67 case reflect.Float64:
68 v, _ := cmd.Flags().GetFloat64(name)
69 f.Set(reflect.ValueOf(v))
70 case reflect.Slice:
71 switch tf.Type.Elem().Kind() {
72 case reflect.String:
73 v, _ := cmd.Flags().GetStringSlice(name)
74 f.Set(reflect.ValueOf(v))
75 case reflect.Int:
76 v, _ := cmd.Flags().GetIntSlice(name)
77 f.Set(reflect.ValueOf(v))
78 case reflect.Int32:
79 v, _ := cmd.Flags().GetInt32Slice(name)
80 f.Set(reflect.ValueOf(v))
81 case reflect.Int64:
82 v, _ := cmd.Flags().GetInt64Slice(name)
83 f.Set(reflect.ValueOf(v))
84 case reflect.Uint:
85 v, _ := cmd.Flags().GetUintSlice(name)
86 f.Set(reflect.ValueOf(v))
87 case reflect.Float32:
88 v, _ := cmd.Flags().GetFloat32Slice(name)
89 f.Set(reflect.ValueOf(v))
90 case reflect.Float64:
91 v, _ := cmd.Flags().GetFloat64Slice(name)
92 f.Set(reflect.ValueOf(v))
93 default:
94 return fmt.Errorf("type []%s is not supported for field %s", tf.Type.Elem(), tf.Name)
95 }
96 case reflect.Struct:
97 if tf.Type.AssignableTo(reflect.TypeOf(VaultCredential{})) { // cli.VaultCredential
98 v, _ := cmd.Flags().GetString(name)
99 vk, err := vault.GetVaultKey(v)
100 if err != nil {
101 return fmt.Errorf("Error getting %s from vault: %w", name, err)
102 }
103 f.Set(reflect.ValueOf(VaultCredential{vk.Username, vk.Password}))
104 } else {
105 return fmt.Errorf("type %s is not supported for field %s", tf.Type, tf.Name)
106 }
107 default:
108 return fmt.Errorf("type %s is not supported for field %s", tf.Type, tf.Name)
109 }
110 }
111
112 return nil
113}
114
115func AddFlags(cmd *cobra.Command, cfg interface{}, def interface{}, scope string) error {
116 t := reflect.TypeOf(cfg).Elem()
117 d := reflect.ValueOf(def).Elem()
118
119 for i := 0; i < t.NumField(); i++ {
120 f := t.Field(i)
121
122 // Fields with no name are not considered flags
123 name := f.Tag.Get("flag")
124 if name == "" {
125 continue
126 }
127
128 // Non-matching scopes should not bind here (note root is "")
129 if f.Tag.Get("flag-scope") != scope {
130 continue
131 }
132
133 defV := d.FieldByName(f.Name).Interface()
134 help := f.Tag.Get("flag-help")
135
136 switch f.Type.Kind() {
137 case reflect.Bool:
138 cmd.PersistentFlags().Bool(name, defV.(bool), help)
139 case reflect.String:
140 cmd.PersistentFlags().String(name, defV.(string), help)
141 case reflect.Int:
142 cmd.PersistentFlags().Int(name, defV.(int), help)
143 case reflect.Int32:
144 cmd.PersistentFlags().Int32(name, defV.(int32), help)
145 case reflect.Int64:
146 if f.Type.AssignableTo(reflect.TypeOf(time.Duration(0))) { // time.Duration
147 cmd.PersistentFlags().Duration(name, defV.(time.Duration), help)
148 } else {
149 cmd.PersistentFlags().Int64(name, defV.(int64), help)
150 }
151 case reflect.Uint:
152 cmd.PersistentFlags().Uint(name, defV.(uint), help)
153 case reflect.Uint32:
154 cmd.PersistentFlags().Uint32(name, defV.(uint32), help)
155 case reflect.Uint64:
156 cmd.PersistentFlags().Uint64(name, defV.(uint64), help)
157 case reflect.Float32:
158 cmd.PersistentFlags().Float32(name, defV.(float32), help)
159 case reflect.Float64:
160 cmd.PersistentFlags().Float64(name, defV.(float64), help)
161 case reflect.Slice:
162 switch f.Type.Elem().Kind() {
163 case reflect.String:
164 cmd.PersistentFlags().StringSlice(name, defV.([]string), help)
165 case reflect.Int:
166 cmd.PersistentFlags().IntSlice(name, defV.([]int), help)
167 case reflect.Int32:
168 cmd.PersistentFlags().Int32Slice(name, defV.([]int32), help)
169 case reflect.Int64:
170 cmd.PersistentFlags().Int64Slice(name, defV.([]int64), help)
171 case reflect.Uint:
172 cmd.PersistentFlags().UintSlice(name, defV.([]uint), help)
173 case reflect.Float32:
174 cmd.PersistentFlags().Float32Slice(name, defV.([]float32), help)
175 case reflect.Float64:
176 cmd.PersistentFlags().Float64Slice(name, defV.([]float64), help)
177 default:
178 return fmt.Errorf("type []%s is not supported for field %s", f.Type.Elem(), f.Name)
179 }
180 case reflect.Struct:
181 if f.Type.AssignableTo(reflect.TypeOf(VaultCredential{})) { // cli.VaultCredential
182 cmd.PersistentFlags().String(name, "", help)
183 } else {
184 return fmt.Errorf("type %s is not supported for field %s", f.Type, f.Name)
185 }
186 default:
187 return fmt.Errorf("type %s is not supported for field %s", f.Type, f.Name)
188 }
189 }
190
191 return nil
192}