github.com/migueleliasweb/helm@v2.6.1+incompatible/pkg/strvals/parser.go (about) 1 /* 2 Copyright 2016 The Kubernetes Authors All rights reserved. 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) 49 err := t.parse() 50 return vals, err 51 } 52 53 //ParseInto parses a strvals line and merges the result into dest. 54 // 55 // If the strval string has a key that exists in dest, it overwrites the 56 // dest version. 57 func ParseInto(s string, dest map[string]interface{}) error { 58 scanner := bytes.NewBufferString(s) 59 t := newParser(scanner, dest) 60 return t.parse() 61 } 62 63 // parser is a simple parser that takes a strvals line and parses it into a 64 // map representation. 65 type parser struct { 66 sc *bytes.Buffer 67 data map[string]interface{} 68 } 69 70 func newParser(sc *bytes.Buffer, data map[string]interface{}) *parser { 71 return &parser{sc: sc, data: data} 72 } 73 74 func (t *parser) parse() error { 75 for { 76 err := t.key(t.data) 77 if err == nil { 78 continue 79 } 80 if err == io.EOF { 81 return nil 82 } 83 return err 84 } 85 } 86 87 func runeSet(r []rune) map[rune]bool { 88 s := make(map[rune]bool, len(r)) 89 for _, rr := range r { 90 s[rr] = true 91 } 92 return s 93 } 94 95 func (t *parser) key(data map[string]interface{}) error { 96 stop := runeSet([]rune{'=', '[', ',', '.'}) 97 for { 98 switch k, last, err := runesUntil(t.sc, stop); { 99 case err != nil: 100 if len(k) == 0 { 101 return err 102 } 103 return fmt.Errorf("key %q has no value", string(k)) 104 //set(data, string(k), "") 105 //return err 106 case last == '[': 107 // We are in a list index context, so we need to set an index. 108 i, err := t.keyIndex() 109 if err != nil { 110 return fmt.Errorf("error parsing index: %s", err) 111 } 112 kk := string(k) 113 // Find or create target list 114 list := []interface{}{} 115 if _, ok := data[kk]; ok { 116 list = data[kk].([]interface{}) 117 } 118 119 // Now we need to get the value after the ]. 120 list, err = t.listItem(list, i) 121 set(data, kk, list) 122 return err 123 case last == '=': 124 //End of key. Consume =, Get value. 125 // FIXME: Get value list first 126 vl, e := t.valList() 127 switch e { 128 case nil: 129 set(data, string(k), vl) 130 return nil 131 case io.EOF: 132 set(data, string(k), "") 133 return e 134 case ErrNotList: 135 v, e := t.val() 136 set(data, string(k), typedVal(v)) 137 return e 138 default: 139 return e 140 } 141 142 case last == ',': 143 // No value given. Set the value to empty string. Return error. 144 set(data, string(k), "") 145 return fmt.Errorf("key %q has no value (cannot end with ,)", string(k)) 146 case last == '.': 147 // First, create or find the target map. 148 inner := map[string]interface{}{} 149 if _, ok := data[string(k)]; ok { 150 inner = data[string(k)].(map[string]interface{}) 151 } 152 153 // Recurse 154 e := t.key(inner) 155 if len(inner) == 0 { 156 return fmt.Errorf("key map %q has no value", string(k)) 157 } 158 set(data, string(k), inner) 159 return e 160 } 161 } 162 } 163 164 func set(data map[string]interface{}, key string, val interface{}) { 165 // If key is empty, don't set it. 166 if len(key) == 0 { 167 return 168 } 169 data[key] = val 170 } 171 172 func setIndex(list []interface{}, index int, val interface{}) []interface{} { 173 if len(list) <= index { 174 newlist := make([]interface{}, index+1) 175 copy(newlist, list) 176 list = newlist 177 } 178 list[index] = val 179 return list 180 } 181 182 func (t *parser) keyIndex() (int, error) { 183 // First, get the key. 184 stop := runeSet([]rune{']'}) 185 v, _, err := runesUntil(t.sc, stop) 186 if err != nil { 187 return 0, err 188 } 189 // v should be the index 190 return strconv.Atoi(string(v)) 191 192 } 193 func (t *parser) listItem(list []interface{}, i int) ([]interface{}, error) { 194 stop := runeSet([]rune{'[', '.', '='}) 195 switch k, last, err := runesUntil(t.sc, stop); { 196 case len(k) > 0: 197 return list, fmt.Errorf("unexpected data at end of array index: %q", k) 198 case err != nil: 199 return list, err 200 case last == '=': 201 vl, e := t.valList() 202 switch e { 203 case nil: 204 return setIndex(list, i, vl), nil 205 case io.EOF: 206 return setIndex(list, i, ""), err 207 case ErrNotList: 208 v, e := t.val() 209 return setIndex(list, i, typedVal(v)), e 210 default: 211 return list, e 212 } 213 case last == '[': 214 // now we have a nested list. Read the index and handle. 215 i, err := t.keyIndex() 216 if err != nil { 217 return list, fmt.Errorf("error parsing index: %s", err) 218 } 219 // Now we need to get the value after the ]. 220 list2, err := t.listItem(list, i) 221 return setIndex(list, i, list2), err 222 case last == '.': 223 // We have a nested object. Send to t.key 224 inner := map[string]interface{}{} 225 if len(list) > i { 226 inner = list[i].(map[string]interface{}) 227 } 228 229 // Recurse 230 e := t.key(inner) 231 return setIndex(list, i, inner), e 232 default: 233 return nil, fmt.Errorf("parse error: unexpected token %v", last) 234 } 235 } 236 237 func (t *parser) val() ([]rune, error) { 238 stop := runeSet([]rune{','}) 239 v, _, err := runesUntil(t.sc, stop) 240 return v, err 241 } 242 243 func (t *parser) valList() ([]interface{}, error) { 244 r, _, e := t.sc.ReadRune() 245 if e != nil { 246 return []interface{}{}, e 247 } 248 249 if r != '{' { 250 t.sc.UnreadRune() 251 return []interface{}{}, ErrNotList 252 } 253 254 list := []interface{}{} 255 stop := runeSet([]rune{',', '}'}) 256 for { 257 switch v, last, err := runesUntil(t.sc, stop); { 258 case err != nil: 259 if err == io.EOF { 260 err = errors.New("list must terminate with '}'") 261 } 262 return list, err 263 case last == '}': 264 // If this is followed by ',', consume it. 265 if r, _, e := t.sc.ReadRune(); e == nil && r != ',' { 266 t.sc.UnreadRune() 267 } 268 list = append(list, typedVal(v)) 269 return list, nil 270 case last == ',': 271 list = append(list, typedVal(v)) 272 } 273 } 274 } 275 276 func runesUntil(in io.RuneReader, stop map[rune]bool) ([]rune, rune, error) { 277 v := []rune{} 278 for { 279 switch r, _, e := in.ReadRune(); { 280 case e != nil: 281 return v, r, e 282 case inMap(r, stop): 283 return v, r, nil 284 case r == '\\': 285 next, _, e := in.ReadRune() 286 if e != nil { 287 return v, next, e 288 } 289 v = append(v, next) 290 default: 291 v = append(v, r) 292 } 293 } 294 } 295 296 func inMap(k rune, m map[rune]bool) bool { 297 _, ok := m[k] 298 return ok 299 } 300 301 func typedVal(v []rune) interface{} { 302 val := string(v) 303 if strings.EqualFold(val, "true") { 304 return true 305 } 306 307 if strings.EqualFold(val, "false") { 308 return false 309 } 310 311 // If this value does not start with zero, try parsing it to an int 312 if len(val) != 0 && val[0] != '0' { 313 if iv, err := strconv.ParseInt(val, 10, 64); err == nil { 314 return iv 315 } 316 } 317 318 return val 319 }