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  }