1 package altsrc
2
3 import (
4 "encoding/json"
5 "fmt"
6 "io"
7 "strings"
8 "time"
9
10 "github.com/urfave/cli/v2"
11 )
12
13
14
15
16
17 func NewJSONSourceFromFlagFunc(flag string) func(c *cli.Context) (InputSourceContext, error) {
18 return func(cCtx *cli.Context) (InputSourceContext, error) {
19 if cCtx.IsSet(flag) {
20 return NewJSONSourceFromFile(cCtx.String(flag))
21 }
22
23 return defaultInputSource()
24 }
25 }
26
27
28
29
30 func NewJSONSourceFromFile(f string) (InputSourceContext, error) {
31 data, err := loadDataFrom(f)
32 if err != nil {
33 return nil, err
34 }
35
36 return NewJSONSource(data)
37 }
38
39
40
41 func NewJSONSourceFromReader(r io.Reader) (InputSourceContext, error) {
42 data, err := io.ReadAll(r)
43 if err != nil {
44 return nil, err
45 }
46 return NewJSONSource(data)
47 }
48
49
50
51 func NewJSONSource(data []byte) (InputSourceContext, error) {
52 var deserialized map[string]interface{}
53 if err := json.Unmarshal(data, &deserialized); err != nil {
54 return nil, err
55 }
56 return &jsonSource{deserialized: deserialized}, nil
57 }
58
59 func (x *jsonSource) Source() string {
60 return x.file
61 }
62
63 func (x *jsonSource) Int(name string) (int, error) {
64 i, err := x.getValue(name)
65 if err != nil {
66 return 0, err
67 }
68 switch v := i.(type) {
69 default:
70 return 0, fmt.Errorf("unexpected type %T for %q", i, name)
71 case int:
72 return v, nil
73 case float32:
74 return int(v), nil
75 case float64:
76 return int(v), nil
77 }
78 }
79
80 func (x *jsonSource) Int64(name string) (int64, error) {
81 i, err := x.getValue(name)
82 if err != nil {
83 return 0, err
84 }
85 switch v := i.(type) {
86 default:
87 return 0, fmt.Errorf("unexpected type %T for %q", i, name)
88 case int64:
89 return v, nil
90 case int:
91 return int64(v), nil
92 case float32:
93 return int64(v), nil
94 case float64:
95 return int64(v), nil
96 }
97 }
98
99 func (x *jsonSource) Uint(name string) (uint, error) {
100 i, err := x.getValue(name)
101 if err != nil {
102 return 0, err
103 }
104 switch v := i.(type) {
105 default:
106 return 0, fmt.Errorf("unexpected type %T for %q", i, name)
107 case uint:
108 return v, nil
109 case uint64:
110 return uint(v), nil
111 case float32:
112 return uint(v), nil
113 case float64:
114 return uint(v), nil
115 }
116 }
117
118 func (x *jsonSource) Uint64(name string) (uint64, error) {
119 i, err := x.getValue(name)
120 if err != nil {
121 return 0, err
122 }
123 switch v := i.(type) {
124 default:
125 return 0, fmt.Errorf("unexpected type %T for %q", i, name)
126 case uint64:
127 return v, nil
128 case uint:
129 return uint64(v), nil
130 case float32:
131 return uint64(v), nil
132 case float64:
133 return uint64(v), nil
134 }
135 }
136
137 func (x *jsonSource) Duration(name string) (time.Duration, error) {
138 i, err := x.getValue(name)
139 if err != nil {
140 return 0, err
141 }
142 v, ok := i.(time.Duration)
143 if !ok {
144 return 0, fmt.Errorf("unexpected type %T for %q", i, name)
145 }
146 return v, nil
147 }
148
149 func (x *jsonSource) Float64(name string) (float64, error) {
150 i, err := x.getValue(name)
151 if err != nil {
152 return 0, err
153 }
154 v, ok := i.(float64)
155 if !ok {
156 return 0, fmt.Errorf("unexpected type %T for %q", i, name)
157 }
158 return v, nil
159 }
160
161 func (x *jsonSource) String(name string) (string, error) {
162 i, err := x.getValue(name)
163 if err != nil {
164 return "", err
165 }
166 v, ok := i.(string)
167 if !ok {
168 return "", fmt.Errorf("unexpected type %T for %q", i, name)
169 }
170 return v, nil
171 }
172
173 func (x *jsonSource) StringSlice(name string) ([]string, error) {
174 i, err := x.getValue(name)
175 if err != nil {
176 return nil, err
177 }
178 switch v := i.(type) {
179 default:
180 return nil, fmt.Errorf("unexpected type %T for %q", i, name)
181 case []string:
182 return v, nil
183 case []interface{}:
184 c := []string{}
185 for _, s := range v {
186 if str, ok := s.(string); ok {
187 c = append(c, str)
188 } else {
189 return c, fmt.Errorf("unexpected item type %T in %T for %q", s, c, name)
190 }
191 }
192 return c, nil
193 }
194 }
195
196 func (x *jsonSource) IntSlice(name string) ([]int, error) {
197 i, err := x.getValue(name)
198 if err != nil {
199 return nil, err
200 }
201 switch v := i.(type) {
202 default:
203 return nil, fmt.Errorf("unexpected type %T for %q", i, name)
204 case []int:
205 return v, nil
206 case []interface{}:
207 c := []int{}
208 for _, s := range v {
209 if i2, ok := s.(int); ok {
210 c = append(c, i2)
211 } else {
212 return c, fmt.Errorf("unexpected item type %T in %T for %q", s, c, name)
213 }
214 }
215 return c, nil
216 }
217 }
218
219 func (x *jsonSource) Int64Slice(name string) ([]int64, error) {
220 i, err := x.getValue(name)
221 if err != nil {
222 return nil, err
223 }
224 switch v := i.(type) {
225 default:
226 return nil, fmt.Errorf("unexpected type %T for %q", i, name)
227 case []int64:
228 return v, nil
229 case []interface{}:
230 c := []int64{}
231 for _, s := range v {
232 if i2, ok := s.(int64); ok {
233 c = append(c, i2)
234 } else {
235 return c, fmt.Errorf("unexpected item type %T in %T for %q", s, c, name)
236 }
237 }
238 return c, nil
239 }
240 }
241
242 func (x *jsonSource) Float64Slice(name string) ([]float64, error) {
243 i, err := x.getValue(name)
244 if err != nil {
245 return nil, err
246 }
247 switch v := i.(type) {
248 default:
249 return nil, fmt.Errorf("unexpected type %T for %q", i, name)
250 case []float64:
251 return v, nil
252 case []interface{}:
253 c := []float64{}
254 for _, s := range v {
255 if i2, ok := s.(float64); ok {
256 c = append(c, i2)
257 } else {
258 return c, fmt.Errorf("unexpected item type %T in %T for %q", s, c, name)
259 }
260 }
261 return c, nil
262 }
263 }
264
265 func (x *jsonSource) Generic(name string) (cli.Generic, error) {
266 i, err := x.getValue(name)
267 if err != nil {
268 return nil, err
269 }
270 v, ok := i.(cli.Generic)
271 if !ok {
272 return nil, fmt.Errorf("unexpected type %T for %q", i, name)
273 }
274 return v, nil
275 }
276
277 func (x *jsonSource) Bool(name string) (bool, error) {
278 i, err := x.getValue(name)
279 if err != nil {
280 return false, err
281 }
282 v, ok := i.(bool)
283 if !ok {
284 return false, fmt.Errorf("unexpected type %T for %q", i, name)
285 }
286 return v, nil
287 }
288
289 func (x *jsonSource) isSet(name string) bool {
290 _, err := x.getValue(name)
291 return err == nil
292 }
293
294 func (x *jsonSource) getValue(key string) (interface{}, error) {
295 return jsonGetValue(key, x.deserialized)
296 }
297
298 func jsonGetValue(key string, m map[string]interface{}) (interface{}, error) {
299 var ret interface{}
300 var ok bool
301 working := m
302 keys := strings.Split(key, ".")
303 for ix, k := range keys {
304 if ret, ok = working[k]; !ok {
305 return ret, fmt.Errorf("missing key %q", key)
306 }
307 if working, ok = ret.(map[string]interface{}); !ok {
308 if ix < len(keys)-1 {
309 return ret, fmt.Errorf("unexpected intermediate value at %q segment of %q: %T", k, key, ret)
310 }
311 }
312 }
313 return ret, nil
314 }
315
316 type jsonSource struct {
317 file string
318 deserialized map[string]interface{}
319 }
320
View as plain text