github.com/stefanmcshane/helm@v0.0.0-20221213002717-88a4a2c6e77d/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  	"encoding/json"
    21  	"fmt"
    22  	"io"
    23  	"io/ioutil"
    24  	"strconv"
    25  	"strings"
    26  	"unicode"
    27  
    28  	"github.com/pkg/errors"
    29  	"sigs.k8s.io/yaml"
    30  )
    31  
    32  // ErrNotList indicates that a non-list was treated as a list.
    33  var ErrNotList = errors.New("not a list")
    34  
    35  // MaxIndex is the maximum index that will be allowed by setIndex.
    36  // The default value 65536 = 1024 * 64
    37  var MaxIndex = 65536
    38  
    39  // ToYAML takes a string of arguments and converts to a YAML document.
    40  func ToYAML(s string) (string, error) {
    41  	m, err := Parse(s)
    42  	if err != nil {
    43  		return "", err
    44  	}
    45  	d, err := yaml.Marshal(m)
    46  	return strings.TrimSuffix(string(d), "\n"), err
    47  }
    48  
    49  // Parse parses a set line.
    50  //
    51  // A set line is of the form name1=value1,name2=value2
    52  func Parse(s string) (map[string]interface{}, error) {
    53  	vals := map[string]interface{}{}
    54  	scanner := bytes.NewBufferString(s)
    55  	t := newParser(scanner, vals, false)
    56  	err := t.parse()
    57  	return vals, err
    58  }
    59  
    60  // ParseString parses a set line and forces a string value.
    61  //
    62  // A set line is of the form name1=value1,name2=value2
    63  func ParseString(s string) (map[string]interface{}, error) {
    64  	vals := map[string]interface{}{}
    65  	scanner := bytes.NewBufferString(s)
    66  	t := newParser(scanner, vals, true)
    67  	err := t.parse()
    68  	return vals, err
    69  }
    70  
    71  // ParseInto parses a strvals line and merges the result into dest.
    72  //
    73  // If the strval string has a key that exists in dest, it overwrites the
    74  // dest version.
    75  func ParseInto(s string, dest map[string]interface{}) error {
    76  	scanner := bytes.NewBufferString(s)
    77  	t := newParser(scanner, dest, false)
    78  	return t.parse()
    79  }
    80  
    81  // ParseFile parses a set line, but its final value is loaded from the file at the path specified by the original value.
    82  //
    83  // A set line is of the form name1=path1,name2=path2
    84  //
    85  // When the files at path1 and path2 contained "val1" and "val2" respectively, the set line is consumed as
    86  // name1=val1,name2=val2
    87  func ParseFile(s string, reader RunesValueReader) (map[string]interface{}, error) {
    88  	vals := map[string]interface{}{}
    89  	scanner := bytes.NewBufferString(s)
    90  	t := newFileParser(scanner, vals, reader)
    91  	err := t.parse()
    92  	return vals, err
    93  }
    94  
    95  // ParseIntoString parses a strvals line and merges the result into dest.
    96  //
    97  // This method always returns a string as the value.
    98  func ParseIntoString(s string, dest map[string]interface{}) error {
    99  	scanner := bytes.NewBufferString(s)
   100  	t := newParser(scanner, dest, true)
   101  	return t.parse()
   102  }
   103  
   104  // ParseJSON parses a string with format key1=val1, key2=val2, ...
   105  // where values are json strings (null, or scalars, or arrays, or objects).
   106  // An empty val is treated as null.
   107  //
   108  // If a key exists in dest, the new value overwrites the dest version.
   109  //
   110  func ParseJSON(s string, dest map[string]interface{}) error {
   111  	scanner := bytes.NewBufferString(s)
   112  	t := newJSONParser(scanner, dest)
   113  	return t.parse()
   114  }
   115  
   116  // ParseIntoFile parses a filevals line and merges the result into dest.
   117  //
   118  // This method always returns a string as the value.
   119  func ParseIntoFile(s string, dest map[string]interface{}, reader RunesValueReader) error {
   120  	scanner := bytes.NewBufferString(s)
   121  	t := newFileParser(scanner, dest, reader)
   122  	return t.parse()
   123  }
   124  
   125  // RunesValueReader is a function that takes the given value (a slice of runes)
   126  // and returns the parsed value
   127  type RunesValueReader func([]rune) (interface{}, error)
   128  
   129  // parser is a simple parser that takes a strvals line and parses it into a
   130  // map representation.
   131  //
   132  // where sc is the source of the original data being parsed
   133  // where data is the final parsed data from the parses with correct types
   134  type parser struct {
   135  	sc        *bytes.Buffer
   136  	data      map[string]interface{}
   137  	reader    RunesValueReader
   138  	isjsonval bool
   139  }
   140  
   141  func newParser(sc *bytes.Buffer, data map[string]interface{}, stringBool bool) *parser {
   142  	stringConverter := func(rs []rune) (interface{}, error) {
   143  		return typedVal(rs, stringBool), nil
   144  	}
   145  	return &parser{sc: sc, data: data, reader: stringConverter}
   146  }
   147  
   148  func newJSONParser(sc *bytes.Buffer, data map[string]interface{}) *parser {
   149  	return &parser{sc: sc, data: data, reader: nil, isjsonval: true}
   150  }
   151  
   152  func newFileParser(sc *bytes.Buffer, data map[string]interface{}, reader RunesValueReader) *parser {
   153  	return &parser{sc: sc, data: data, reader: reader}
   154  }
   155  
   156  func (t *parser) parse() error {
   157  	for {
   158  		err := t.key(t.data)
   159  		if err == nil {
   160  			continue
   161  		}
   162  		if err == io.EOF {
   163  			return nil
   164  		}
   165  		return err
   166  	}
   167  }
   168  
   169  func runeSet(r []rune) map[rune]bool {
   170  	s := make(map[rune]bool, len(r))
   171  	for _, rr := range r {
   172  		s[rr] = true
   173  	}
   174  	return s
   175  }
   176  
   177  func (t *parser) key(data map[string]interface{}) (reterr error) {
   178  	defer func() {
   179  		if r := recover(); r != nil {
   180  			reterr = fmt.Errorf("unable to parse key: %s", r)
   181  		}
   182  	}()
   183  	stop := runeSet([]rune{'=', '[', ',', '.'})
   184  	for {
   185  		switch k, last, err := runesUntil(t.sc, stop); {
   186  		case err != nil:
   187  			if len(k) == 0 {
   188  				return err
   189  			}
   190  			return errors.Errorf("key %q has no value", string(k))
   191  			//set(data, string(k), "")
   192  			//return err
   193  		case last == '[':
   194  			// We are in a list index context, so we need to set an index.
   195  			i, err := t.keyIndex()
   196  			if err != nil {
   197  				return errors.Wrap(err, "error parsing index")
   198  			}
   199  			kk := string(k)
   200  			// Find or create target list
   201  			list := []interface{}{}
   202  			if _, ok := data[kk]; ok {
   203  				list = data[kk].([]interface{})
   204  			}
   205  
   206  			// Now we need to get the value after the ].
   207  			list, err = t.listItem(list, i)
   208  			set(data, kk, list)
   209  			return err
   210  		case last == '=':
   211  			if t.isjsonval {
   212  				empval, err := t.emptyVal()
   213  				if err != nil {
   214  					return err
   215  				}
   216  				if empval {
   217  					set(data, string(k), nil)
   218  					return nil
   219  				}
   220  				// parse jsonvals by using Go’s JSON standard library
   221  				// Decode is preferred to Unmarshal in order to parse just the json parts of the list key1=jsonval1,key2=jsonval2,...
   222  				// Since Decode has its own buffer that consumes more characters (from underlying t.sc) than the ones actually decoded,
   223  				// we invoke Decode on a separate reader built with a copy of what is left in t.sc. After Decode is executed, we
   224  				// discard in t.sc the chars of the decoded json value (the number of those characters is returned by InputOffset).
   225  				var jsonval interface{}
   226  				dec := json.NewDecoder(strings.NewReader(t.sc.String()))
   227  				if err = dec.Decode(&jsonval); err != nil {
   228  					return err
   229  				}
   230  				set(data, string(k), jsonval)
   231  				if _, err = io.CopyN(ioutil.Discard, t.sc, dec.InputOffset()); err != nil {
   232  					return err
   233  				}
   234  				// skip possible blanks and comma
   235  				_, err = t.emptyVal()
   236  				return err
   237  			}
   238  			//End of key. Consume =, Get value.
   239  			// FIXME: Get value list first
   240  			vl, e := t.valList()
   241  			switch e {
   242  			case nil:
   243  				set(data, string(k), vl)
   244  				return nil
   245  			case io.EOF:
   246  				set(data, string(k), "")
   247  				return e
   248  			case ErrNotList:
   249  				rs, e := t.val()
   250  				if e != nil && e != io.EOF {
   251  					return e
   252  				}
   253  				v, e := t.reader(rs)
   254  				set(data, string(k), v)
   255  				return e
   256  			default:
   257  				return e
   258  			}
   259  		case last == ',':
   260  			// No value given. Set the value to empty string. Return error.
   261  			set(data, string(k), "")
   262  			return errors.Errorf("key %q has no value (cannot end with ,)", string(k))
   263  		case last == '.':
   264  			// First, create or find the target map.
   265  			inner := map[string]interface{}{}
   266  			if _, ok := data[string(k)]; ok {
   267  				inner = data[string(k)].(map[string]interface{})
   268  			}
   269  
   270  			// Recurse
   271  			e := t.key(inner)
   272  			if len(inner) == 0 {
   273  				return errors.Errorf("key map %q has no value", string(k))
   274  			}
   275  			set(data, string(k), inner)
   276  			return e
   277  		}
   278  	}
   279  }
   280  
   281  func set(data map[string]interface{}, key string, val interface{}) {
   282  	// If key is empty, don't set it.
   283  	if len(key) == 0 {
   284  		return
   285  	}
   286  	data[key] = val
   287  }
   288  
   289  func setIndex(list []interface{}, index int, val interface{}) (l2 []interface{}, err error) {
   290  	// There are possible index values that are out of range on a target system
   291  	// causing a panic. This will catch the panic and return an error instead.
   292  	// The value of the index that causes a panic varies from system to system.
   293  	defer func() {
   294  		if r := recover(); r != nil {
   295  			err = fmt.Errorf("error processing index %d: %s", index, r)
   296  		}
   297  	}()
   298  
   299  	if index < 0 {
   300  		return list, fmt.Errorf("negative %d index not allowed", index)
   301  	}
   302  	if index > MaxIndex {
   303  		return list, fmt.Errorf("index of %d is greater than maximum supported index of %d", index, MaxIndex)
   304  	}
   305  	if len(list) <= index {
   306  		newlist := make([]interface{}, index+1)
   307  		copy(newlist, list)
   308  		list = newlist
   309  	}
   310  	list[index] = val
   311  	return list, nil
   312  }
   313  
   314  func (t *parser) keyIndex() (int, error) {
   315  	// First, get the key.
   316  	stop := runeSet([]rune{']'})
   317  	v, _, err := runesUntil(t.sc, stop)
   318  	if err != nil {
   319  		return 0, err
   320  	}
   321  	// v should be the index
   322  	return strconv.Atoi(string(v))
   323  
   324  }
   325  func (t *parser) listItem(list []interface{}, i int) ([]interface{}, error) {
   326  	if i < 0 {
   327  		return list, fmt.Errorf("negative %d index not allowed", i)
   328  	}
   329  	stop := runeSet([]rune{'[', '.', '='})
   330  	switch k, last, err := runesUntil(t.sc, stop); {
   331  	case len(k) > 0:
   332  		return list, errors.Errorf("unexpected data at end of array index: %q", k)
   333  	case err != nil:
   334  		return list, err
   335  	case last == '=':
   336  		if t.isjsonval {
   337  			empval, err := t.emptyVal()
   338  			if err != nil {
   339  				return list, err
   340  			}
   341  			if empval {
   342  				return setIndex(list, i, nil)
   343  			}
   344  			// parse jsonvals by using Go’s JSON standard library
   345  			// Decode is preferred to Unmarshal in order to parse just the json parts of the list key1=jsonval1,key2=jsonval2,...
   346  			// Since Decode has its own buffer that consumes more characters (from underlying t.sc) than the ones actually decoded,
   347  			// we invoke Decode on a separate reader built with a copy of what is left in t.sc. After Decode is executed, we
   348  			// discard in t.sc the chars of the decoded json value (the number of those characters is returned by InputOffset).
   349  			var jsonval interface{}
   350  			dec := json.NewDecoder(strings.NewReader(t.sc.String()))
   351  			if err = dec.Decode(&jsonval); err != nil {
   352  				return list, err
   353  			}
   354  			if list, err = setIndex(list, i, jsonval); err != nil {
   355  				return list, err
   356  			}
   357  			if _, err = io.CopyN(ioutil.Discard, t.sc, dec.InputOffset()); err != nil {
   358  				return list, err
   359  			}
   360  			// skip possible blanks and comma
   361  			_, err = t.emptyVal()
   362  			return list, err
   363  		}
   364  		vl, e := t.valList()
   365  		switch e {
   366  		case nil:
   367  			return setIndex(list, i, vl)
   368  		case io.EOF:
   369  			return setIndex(list, i, "")
   370  		case ErrNotList:
   371  			rs, e := t.val()
   372  			if e != nil && e != io.EOF {
   373  				return list, e
   374  			}
   375  			v, e := t.reader(rs)
   376  			if e != nil {
   377  				return list, e
   378  			}
   379  			return setIndex(list, i, v)
   380  		default:
   381  			return list, e
   382  		}
   383  	case last == '[':
   384  		// now we have a nested list. Read the index and handle.
   385  		nextI, err := t.keyIndex()
   386  		if err != nil {
   387  			return list, errors.Wrap(err, "error parsing index")
   388  		}
   389  		var crtList []interface{}
   390  		if len(list) > i {
   391  			// If nested list already exists, take the value of list to next cycle.
   392  			existed := list[i]
   393  			if existed != nil {
   394  				crtList = list[i].([]interface{})
   395  			}
   396  		}
   397  		// Now we need to get the value after the ].
   398  		list2, err := t.listItem(crtList, nextI)
   399  		if err != nil {
   400  			return list, err
   401  		}
   402  		return setIndex(list, i, list2)
   403  	case last == '.':
   404  		// We have a nested object. Send to t.key
   405  		inner := map[string]interface{}{}
   406  		if len(list) > i {
   407  			var ok bool
   408  			inner, ok = list[i].(map[string]interface{})
   409  			if !ok {
   410  				// We have indices out of order. Initialize empty value.
   411  				list[i] = map[string]interface{}{}
   412  				inner = list[i].(map[string]interface{})
   413  			}
   414  		}
   415  
   416  		// Recurse
   417  		e := t.key(inner)
   418  		if e != nil {
   419  			return list, e
   420  		}
   421  		return setIndex(list, i, inner)
   422  	default:
   423  		return nil, errors.Errorf("parse error: unexpected token %v", last)
   424  	}
   425  }
   426  
   427  // check for an empty value
   428  // read and consume optional spaces until comma or EOF (empty val) or any other char (not empty val)
   429  // comma and spaces are consumed, while any other char is not cosumed
   430  func (t *parser) emptyVal() (bool, error) {
   431  	for {
   432  		r, _, e := t.sc.ReadRune()
   433  		if e == io.EOF {
   434  			return true, nil
   435  		}
   436  		if e != nil {
   437  			return false, e
   438  		}
   439  		if r == ',' {
   440  			return true, nil
   441  		}
   442  		if !unicode.IsSpace(r) {
   443  			t.sc.UnreadRune()
   444  			return false, nil
   445  		}
   446  	}
   447  }
   448  
   449  func (t *parser) val() ([]rune, error) {
   450  	stop := runeSet([]rune{','})
   451  	v, _, err := runesUntil(t.sc, stop)
   452  	return v, err
   453  }
   454  
   455  func (t *parser) valList() ([]interface{}, error) {
   456  	r, _, e := t.sc.ReadRune()
   457  	if e != nil {
   458  		return []interface{}{}, e
   459  	}
   460  
   461  	if r != '{' {
   462  		t.sc.UnreadRune()
   463  		return []interface{}{}, ErrNotList
   464  	}
   465  
   466  	list := []interface{}{}
   467  	stop := runeSet([]rune{',', '}'})
   468  	for {
   469  		switch rs, last, err := runesUntil(t.sc, stop); {
   470  		case err != nil:
   471  			if err == io.EOF {
   472  				err = errors.New("list must terminate with '}'")
   473  			}
   474  			return list, err
   475  		case last == '}':
   476  			// If this is followed by ',', consume it.
   477  			if r, _, e := t.sc.ReadRune(); e == nil && r != ',' {
   478  				t.sc.UnreadRune()
   479  			}
   480  			v, e := t.reader(rs)
   481  			list = append(list, v)
   482  			return list, e
   483  		case last == ',':
   484  			v, e := t.reader(rs)
   485  			if e != nil {
   486  				return list, e
   487  			}
   488  			list = append(list, v)
   489  		}
   490  	}
   491  }
   492  
   493  func runesUntil(in io.RuneReader, stop map[rune]bool) ([]rune, rune, error) {
   494  	v := []rune{}
   495  	for {
   496  		switch r, _, e := in.ReadRune(); {
   497  		case e != nil:
   498  			return v, r, e
   499  		case inMap(r, stop):
   500  			return v, r, nil
   501  		case r == '\\':
   502  			next, _, e := in.ReadRune()
   503  			if e != nil {
   504  				return v, next, e
   505  			}
   506  			v = append(v, next)
   507  		default:
   508  			v = append(v, r)
   509  		}
   510  	}
   511  }
   512  
   513  func inMap(k rune, m map[rune]bool) bool {
   514  	_, ok := m[k]
   515  	return ok
   516  }
   517  
   518  func typedVal(v []rune, st bool) interface{} {
   519  	val := string(v)
   520  
   521  	if st {
   522  		return val
   523  	}
   524  
   525  	if strings.EqualFold(val, "true") {
   526  		return true
   527  	}
   528  
   529  	if strings.EqualFold(val, "false") {
   530  		return false
   531  	}
   532  
   533  	if strings.EqualFold(val, "null") {
   534  		return nil
   535  	}
   536  
   537  	if strings.EqualFold(val, "0") {
   538  		return int64(0)
   539  	}
   540  
   541  	// If this value does not start with zero, try parsing it to an int
   542  	if len(val) != 0 && val[0] != '0' {
   543  		if iv, err := strconv.ParseInt(val, 10, 64); err == nil {
   544  			return iv
   545  		}
   546  	}
   547  
   548  	return val
   549  }