github.com/valdemarpavesi/helm@v2.9.1+incompatible/pkg/strvals/parser.go (about)

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