1
1
/*
2
- Copyright 2016 The Kubernetes Authors All rights reserved .
2
+ Copyright The Helm Authors.
3
3
Licensed under the Apache License, Version 2.0 (the "License");
4
4
you may not use this file except in compliance with the License.
5
5
You may obtain a copy of the License at
@@ -36,7 +36,7 @@ func ToYAML(s string) (string, error) {
36
36
return "" , err
37
37
}
38
38
d , err := yaml .Marshal (m )
39
- return strings . TrimSuffix ( string (d ), " \n " ), err
39
+ return string (d ), err
40
40
}
41
41
42
42
// Parse parses a set line.
@@ -50,6 +50,20 @@ func Parse(s string) (map[string]interface{}, error) {
50
50
return vals , err
51
51
}
52
52
53
+ // ParseFile parses a set line, but its final value is loaded from the file at the path specified by the original value.
54
+ //
55
+ // A set line is of the form name1=path1,name2=path2
56
+ //
57
+ // When the files at path1 and path2 contained "val1" and "val2" respectively, the set line is consumed as
58
+ // name1=val1,name2=val2
59
+ func ParseFile (s string , runesToVal runesToVal ) (map [string ]interface {}, error ) {
60
+ vals := map [string ]interface {}{}
61
+ scanner := bytes .NewBufferString (s )
62
+ t := newFileParser (scanner , vals , runesToVal )
63
+ err := t .parse ()
64
+ return vals , err
65
+ }
66
+
53
67
// ParseString parses a set line and forces a string value.
54
68
//
55
69
// A set line is of the form name1=value1,name2=value2
@@ -71,7 +85,16 @@ func ParseInto(s string, dest map[string]interface{}) error {
71
85
return t .parse ()
72
86
}
73
87
74
- // ParseIntoString parses a strvals line nad merges the result into dest.
88
+ // ParseIntoFile parses a filevals line and merges the result into dest.
89
+ //
90
+ // This method always returns a string as the value.
91
+ func ParseIntoFile (s string , dest map [string ]interface {}, runesToVal runesToVal ) error {
92
+ scanner := bytes .NewBufferString (s )
93
+ t := newFileParser (scanner , dest , runesToVal )
94
+ return t .parse ()
95
+ }
96
+
97
+ // ParseIntoString parses a strvals line and merges the result into dest.
75
98
//
76
99
// This method always returns a string as the value.
77
100
func ParseIntoString (s string , dest map [string ]interface {}) error {
@@ -82,14 +105,27 @@ func ParseIntoString(s string, dest map[string]interface{}) error {
82
105
83
106
// parser is a simple parser that takes a strvals line and parses it into a
84
107
// map representation.
108
+ //
109
+ // where sc is the source of the original data being parsed
110
+ // where data is the final parsed data from the parses with correct types
111
+ // where st is a boolean to figure out if we're forcing it to parse values as string
85
112
type parser struct {
86
- sc * bytes.Buffer
87
- data map [string ]interface {}
88
- st bool
113
+ sc * bytes.Buffer
114
+ data map [string ]interface {}
115
+ runesToVal runesToVal
89
116
}
90
117
118
+ type runesToVal func ([]rune ) (interface {}, error )
119
+
91
120
func newParser (sc * bytes.Buffer , data map [string ]interface {}, stringBool bool ) * parser {
92
- return & parser {sc : sc , data : data , st : stringBool }
121
+ rs2v := func (rs []rune ) (interface {}, error ) {
122
+ return typedVal (rs , stringBool ), nil
123
+ }
124
+ return & parser {sc : sc , data : data , runesToVal : rs2v }
125
+ }
126
+
127
+ func newFileParser (sc * bytes.Buffer , data map [string ]interface {}, runesToVal runesToVal ) * parser {
128
+ return & parser {sc : sc , data : data , runesToVal : runesToVal }
93
129
}
94
130
95
131
func (t * parser ) parse () error {
@@ -153,8 +189,12 @@ func (t *parser) key(data map[string]interface{}) error {
153
189
set (data , string (k ), "" )
154
190
return e
155
191
case ErrNotList :
156
- v , e := t .val ()
157
- set (data , string (k ), typedVal (v , t .st ))
192
+ rs , e := t .val ()
193
+ if e != nil && e != io .EOF {
194
+ return e
195
+ }
196
+ v , e := t .runesToVal (rs )
197
+ set (data , string (k ), v )
158
198
return e
159
199
default :
160
200
return e
@@ -226,25 +266,43 @@ func (t *parser) listItem(list []interface{}, i int) ([]interface{}, error) {
226
266
case io .EOF :
227
267
return setIndex (list , i , "" ), err
228
268
case ErrNotList :
229
- v , e := t .val ()
230
- return setIndex (list , i , typedVal (v , t .st )), e
269
+ rs , e := t .val ()
270
+ if e != nil && e != io .EOF {
271
+ return list , e
272
+ }
273
+ v , e := t .runesToVal (rs )
274
+ return setIndex (list , i , v ), e
231
275
default :
232
276
return list , e
233
277
}
234
278
case last == '[' :
235
279
// now we have a nested list. Read the index and handle.
236
- i , err := t .keyIndex ()
280
+ nextI , err := t .keyIndex ()
237
281
if err != nil {
238
282
return list , fmt .Errorf ("error parsing index: %s" , err )
239
283
}
284
+ var crtList []interface {}
285
+ if len (list ) > i {
286
+ // If nested list already exists, take the value of list to next cycle.
287
+ existed := list [i ]
288
+ if existed != nil {
289
+ crtList = list [i ].([]interface {})
290
+ }
291
+ }
240
292
// Now we need to get the value after the ].
241
- list2 , err := t .listItem (list , i )
293
+ list2 , err := t .listItem (crtList , nextI )
242
294
return setIndex (list , i , list2 ), err
243
295
case last == '.' :
244
296
// We have a nested object. Send to t.key
245
297
inner := map [string ]interface {}{}
246
298
if len (list ) > i {
247
- inner = list [i ].(map [string ]interface {})
299
+ var ok bool
300
+ inner , ok = list [i ].(map [string ]interface {})
301
+ if ! ok {
302
+ // We have indices out of order. Initialize empty value.
303
+ list [i ] = map [string ]interface {}{}
304
+ inner = list [i ].(map [string ]interface {})
305
+ }
248
306
}
249
307
250
308
// Recurse
@@ -275,7 +333,7 @@ func (t *parser) valList() ([]interface{}, error) {
275
333
list := []interface {}{}
276
334
stop := runeSet ([]rune {',' , '}' })
277
335
for {
278
- switch v , last , err := runesUntil (t .sc , stop ); {
336
+ switch rs , last , err := runesUntil (t .sc , stop ); {
279
337
case err != nil :
280
338
if err == io .EOF {
281
339
err = errors .New ("list must terminate with '}'" )
@@ -286,10 +344,15 @@ func (t *parser) valList() ([]interface{}, error) {
286
344
if r , _ , e := t .sc .ReadRune (); e == nil && r != ',' {
287
345
t .sc .UnreadRune ()
288
346
}
289
- list = append (list , typedVal (v , t .st ))
290
- return list , nil
347
+ v , e := t .runesToVal (rs )
348
+ list = append (list , v )
349
+ return list , e
291
350
case last == ',' :
292
- list = append (list , typedVal (v , t .st ))
351
+ v , e := t .runesToVal (rs )
352
+ if e != nil {
353
+ return list , e
354
+ }
355
+ list = append (list , v )
293
356
}
294
357
}
295
358
}
@@ -321,6 +384,11 @@ func inMap(k rune, m map[rune]bool) bool {
321
384
322
385
func typedVal (v []rune , st bool ) interface {} {
323
386
val := string (v )
387
+
388
+ if st {
389
+ return val
390
+ }
391
+
324
392
if strings .EqualFold (val , "true" ) {
325
393
return true
326
394
}
@@ -329,8 +397,16 @@ func typedVal(v []rune, st bool) interface{} {
329
397
return false
330
398
}
331
399
332
- // If this value does not start with zero, and not returnString, try parsing it to an int
333
- if ! st && len (val ) != 0 && val [0 ] != '0' {
400
+ if strings .EqualFold (val , "null" ) {
401
+ return nil
402
+ }
403
+
404
+ if strings .EqualFold (val , "0" ) {
405
+ return int64 (0 )
406
+ }
407
+
408
+ // If this value does not start with zero, try parsing it to an int
409
+ if len (val ) != 0 && val [0 ] != '0' {
334
410
if iv , err := strconv .ParseInt (val , 10 , 64 ); err == nil {
335
411
return iv
336
412
}
0 commit comments