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  }