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