github.com/amtisyAts/helm@v2.17.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 nextI, err := t.keyIndex() 281 if err != nil { 282 return list, fmt.Errorf("error parsing index: %s", err) 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 } 292 // Now we need to get the value after the ]. 293 list2, err := t.listItem(crtList, nextI) 294 return setIndex(list, i, list2), err 295 case last == '.': 296 // We have a nested object. Send to t.key 297 inner := map[string]interface{}{} 298 if len(list) > i { 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 } 306 } 307 308 // Recurse 309 e := t.key(inner) 310 return setIndex(list, i, inner), e 311 default: 312 return nil, fmt.Errorf("parse error: unexpected token %v", last) 313 } 314 } 315 316 func (t *parser) val() ([]rune, error) { 317 stop := runeSet([]rune{','}) 318 v, _, err := runesUntil(t.sc, stop) 319 return v, err 320 } 321 322 func (t *parser) valList() ([]interface{}, error) { 323 r, _, e := t.sc.ReadRune() 324 if e != nil { 325 return []interface{}{}, e 326 } 327 328 if r != '{' { 329 t.sc.UnreadRune() 330 return []interface{}{}, ErrNotList 331 } 332 333 list := []interface{}{} 334 stop := runeSet([]rune{',', '}'}) 335 for { 336 switch rs, last, err := runesUntil(t.sc, stop); { 337 case err != nil: 338 if err == io.EOF { 339 err = errors.New("list must terminate with '}'") 340 } 341 return list, err 342 case last == '}': 343 // If this is followed by ',', consume it. 344 if r, _, e := t.sc.ReadRune(); e == nil && r != ',' { 345 t.sc.UnreadRune() 346 } 347 v, e := t.runesToVal(rs) 348 list = append(list, v) 349 return list, e 350 case last == ',': 351 v, e := t.runesToVal(rs) 352 if e != nil { 353 return list, e 354 } 355 list = append(list, v) 356 } 357 } 358 } 359 360 func runesUntil(in io.RuneReader, stop map[rune]bool) ([]rune, rune, error) { 361 v := []rune{} 362 for { 363 switch r, _, e := in.ReadRune(); { 364 case e != nil: 365 return v, r, e 366 case inMap(r, stop): 367 return v, r, nil 368 case r == '\\': 369 next, _, e := in.ReadRune() 370 if e != nil { 371 return v, next, e 372 } 373 v = append(v, next) 374 default: 375 v = append(v, r) 376 } 377 } 378 } 379 380 func inMap(k rune, m map[rune]bool) bool { 381 _, ok := m[k] 382 return ok 383 } 384 385 func typedVal(v []rune, st bool) interface{} { 386 val := string(v) 387 388 if st { 389 return val 390 } 391 392 if strings.EqualFold(val, "true") { 393 return true 394 } 395 396 if strings.EqualFold(val, "false") { 397 return false 398 } 399 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' { 410 if iv, err := strconv.ParseInt(val, 10, 64); err == nil { 411 return iv 412 } 413 } 414 415 return val 416 }