github.com/latiif/helm@v2.15.0+incompatible/pkg/strvals/parser.go (about) 1 /* 2 Copyright The Helm Authors. 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 */ 15 16 package strvals 17 18 import ( 19 "bytes" 20 "errors" 21 "fmt" 22 "io" 23 "strconv" 24 "strings" 25 26 "github.com/ghodss/yaml" 27 ) 28 29 // ErrNotList indicates that a non-list was treated as a list. 30 var ErrNotList = errors.New("not a list") 31 32 // ToYAML takes a string of arguments and converts to a YAML document. 33 func ToYAML(s string) (string, error) { 34 m, err := Parse(s) 35 if err != nil { 36 return "", err 37 } 38 d, err := yaml.Marshal(m) 39 return string(d), err 40 } 41 42 // Parse parses a set line. 43 // 44 // A set line is of the form name1=value1,name2=value2 45 func Parse(s string) (map[string]interface{}, error) { 46 vals := map[string]interface{}{} 47 scanner := bytes.NewBufferString(s) 48 t := newParser(scanner, vals, false) 49 err := t.parse() 50 return vals, err 51 } 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 67 // ParseString parses a set line and forces a string value. 68 // 69 // A set line is of the form name1=value1,name2=value2 70 func ParseString(s string) (map[string]interface{}, error) { 71 vals := map[string]interface{}{} 72 scanner := bytes.NewBufferString(s) 73 t := newParser(scanner, vals, true) 74 err := t.parse() 75 return vals, err 76 } 77 78 // ParseInto parses a strvals line and merges the result into dest. 79 // 80 // If the strval string has a key that exists in dest, it overwrites the 81 // dest version. 82 func ParseInto(s string, dest map[string]interface{}) error { 83 scanner := bytes.NewBufferString(s) 84 t := newParser(scanner, dest, false) 85 return t.parse() 86 } 87 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. 98 // 99 // This method always returns a string as the value. 100 func ParseIntoString(s string, dest map[string]interface{}) error { 101 scanner := bytes.NewBufferString(s) 102 t := newParser(scanner, dest, true) 103 return t.parse() 104 } 105 106 // parser is a simple parser that takes a strvals line and parses it into a 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 112 type parser struct { 113 sc *bytes.Buffer 114 data map[string]interface{} 115 runesToVal runesToVal 116 } 117 118 type runesToVal func([]rune) (interface{}, error) 119 120 func newParser(sc *bytes.Buffer, data map[string]interface{}, stringBool bool) *parser { 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} 129 } 130 131 func (t *parser) parse() error { 132 for { 133 err := t.key(t.data) 134 if err == nil { 135 continue 136 } 137 if err == io.EOF { 138 return nil 139 } 140 return err 141 } 142 } 143 144 func runeSet(r []rune) map[rune]bool { 145 s := make(map[rune]bool, len(r)) 146 for _, rr := range r { 147 s[rr] = true 148 } 149 return s 150 } 151 152 func (t *parser) key(data map[string]interface{}) error { 153 stop := runeSet([]rune{'=', '[', ',', '.'}) 154 for { 155 switch k, last, err := runesUntil(t.sc, stop); { 156 case err != nil: 157 if len(k) == 0 { 158 return err 159 } 160 return fmt.Errorf("key %q has no value", string(k)) 161 //set(data, string(k), "") 162 //return err 163 case last == '[': 164 // We are in a list index context, so we need to set an index. 165 i, err := t.keyIndex() 166 if err != nil { 167 return fmt.Errorf("error parsing index: %s", err) 168 } 169 kk := string(k) 170 // Find or create target list 171 list := []interface{}{} 172 if _, ok := data[kk]; ok { 173 list = data[kk].([]interface{}) 174 } 175 176 // Now we need to get the value after the ]. 177 list, err = t.listItem(list, i) 178 set(data, kk, list) 179 return err 180 case last == '=': 181 //End of key. Consume =, Get value. 182 // FIXME: Get value list first 183 vl, e := t.valList() 184 switch e { 185 case nil: 186 set(data, string(k), vl) 187 return nil 188 case io.EOF: 189 set(data, string(k), "") 190 return e 191 case ErrNotList: 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) 198 return e 199 default: 200 return e 201 } 202 203 case last == ',': 204 // No value given. Set the value to empty string. Return error. 205 set(data, string(k), "") 206 return fmt.Errorf("key %q has no value (cannot end with ,)", string(k)) 207 case last == '.': 208 // First, create or find the target map. 209 inner := map[string]interface{}{} 210 if _, ok := data[string(k)]; ok { 211 inner = data[string(k)].(map[string]interface{}) 212 } 213 214 // Recurse 215 e := t.key(inner) 216 if len(inner) == 0 { 217 return fmt.Errorf("key map %q has no value", string(k)) 218 } 219 set(data, string(k), inner) 220 return e 221 } 222 } 223 } 224 225 func set(data map[string]interface{}, key string, val interface{}) { 226 // If key is empty, don't set it. 227 if len(key) == 0 { 228 return 229 } 230 data[key] = val 231 } 232 233 func setIndex(list []interface{}, index int, val interface{}) []interface{} { 234 if len(list) <= index { 235 newlist := make([]interface{}, index+1) 236 copy(newlist, list) 237 list = newlist 238 } 239 list[index] = val 240 return list 241 } 242 243 func (t *parser) keyIndex() (int, error) { 244 // First, get the key. 245 stop := runeSet([]rune{']'}) 246 v, _, err := runesUntil(t.sc, stop) 247 if err != nil { 248 return 0, err 249 } 250 // v should be the index 251 return strconv.Atoi(string(v)) 252 253 } 254 func (t *parser) listItem(list []interface{}, i int) ([]interface{}, error) { 255 stop := runeSet([]rune{'[', '.', '='}) 256 switch k, last, err := runesUntil(t.sc, stop); { 257 case len(k) > 0: 258 return list, fmt.Errorf("unexpected data at end of array index: %q", k) 259 case err != nil: 260 return list, err 261 case last == '=': 262 vl, e := t.valList() 263 switch e { 264 case nil: 265 return setIndex(list, i, vl), nil 266 case io.EOF: 267 return setIndex(list, i, ""), err 268 case ErrNotList: 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 275 default: 276 return list, e 277 } 278 case last == '[': 279 // now we have a nested list. Read the index and handle. 280 i, err := t.keyIndex() 281 if err != nil { 282 return list, fmt.Errorf("error parsing index: %s", err) 283 } 284 // Now we need to get the value after the ]. 285 list2, err := t.listItem(list, i) 286 return setIndex(list, i, list2), err 287 case last == '.': 288 // We have a nested object. Send to t.key 289 inner := map[string]interface{}{} 290 if len(list) > i { 291 var ok bool 292 inner, ok = list[i].(map[string]interface{}) 293 if !ok { 294 // We have indices out of order. Initialize empty value. 295 list[i] = map[string]interface{}{} 296 inner = list[i].(map[string]interface{}) 297 } 298 } 299 300 // Recurse 301 e := t.key(inner) 302 return setIndex(list, i, inner), e 303 default: 304 return nil, fmt.Errorf("parse error: unexpected token %v", last) 305 } 306 } 307 308 func (t *parser) val() ([]rune, error) { 309 stop := runeSet([]rune{','}) 310 v, _, err := runesUntil(t.sc, stop) 311 return v, err 312 } 313 314 func (t *parser) valList() ([]interface{}, error) { 315 r, _, e := t.sc.ReadRune() 316 if e != nil { 317 return []interface{}{}, e 318 } 319 320 if r != '{' { 321 t.sc.UnreadRune() 322 return []interface{}{}, ErrNotList 323 } 324 325 list := []interface{}{} 326 stop := runeSet([]rune{',', '}'}) 327 for { 328 switch rs, last, err := runesUntil(t.sc, stop); { 329 case err != nil: 330 if err == io.EOF { 331 err = errors.New("list must terminate with '}'") 332 } 333 return list, err 334 case last == '}': 335 // If this is followed by ',', consume it. 336 if r, _, e := t.sc.ReadRune(); e == nil && r != ',' { 337 t.sc.UnreadRune() 338 } 339 v, e := t.runesToVal(rs) 340 list = append(list, v) 341 return list, e 342 case last == ',': 343 v, e := t.runesToVal(rs) 344 if e != nil { 345 return list, e 346 } 347 list = append(list, v) 348 } 349 } 350 } 351 352 func runesUntil(in io.RuneReader, stop map[rune]bool) ([]rune, rune, error) { 353 v := []rune{} 354 for { 355 switch r, _, e := in.ReadRune(); { 356 case e != nil: 357 return v, r, e 358 case inMap(r, stop): 359 return v, r, nil 360 case r == '\\': 361 next, _, e := in.ReadRune() 362 if e != nil { 363 return v, next, e 364 } 365 v = append(v, next) 366 default: 367 v = append(v, r) 368 } 369 } 370 } 371 372 func inMap(k rune, m map[rune]bool) bool { 373 _, ok := m[k] 374 return ok 375 } 376 377 func typedVal(v []rune, st bool) interface{} { 378 val := string(v) 379 380 if st { 381 return val 382 } 383 384 if strings.EqualFold(val, "true") { 385 return true 386 } 387 388 if strings.EqualFold(val, "false") { 389 return false 390 } 391 392 if strings.EqualFold(val, "null") { 393 return nil 394 } 395 396 if strings.EqualFold(val, "0") { 397 return int64(0) 398 } 399 400 // If this value does not start with zero, try parsing it to an int 401 if len(val) != 0 && val[0] != '0' { 402 if iv, err := strconv.ParseInt(val, 10, 64); err == nil { 403 return iv 404 } 405 } 406 407 return val 408 }