...

Source file src/helm.sh/helm/v3/pkg/strvals/parser.go

Documentation: helm.sh/helm/v3/pkg/strvals

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

View as plain text