github.com/spotmaxtech/k8s-apimachinery-v0260@v0.0.1/pkg/util/yaml/decoder.go (about)

     1  /*
     2  Copyright 2014 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package yaml
    18  
    19  import (
    20  	"bufio"
    21  	"bytes"
    22  	"encoding/json"
    23  	"fmt"
    24  	"io"
    25  	"strings"
    26  	"unicode"
    27  
    28  	jsonutil "github.com/spotmaxtech/k8s-apimachinery-v0260/pkg/util/json"
    29  
    30  	"sigs.k8s.io/yaml"
    31  )
    32  
    33  // Unmarshal unmarshals the given data
    34  // If v is a *map[string]interface{}, *[]interface{}, or *interface{} numbers
    35  // are converted to int64 or float64
    36  func Unmarshal(data []byte, v interface{}) error {
    37  	preserveIntFloat := func(d *json.Decoder) *json.Decoder {
    38  		d.UseNumber()
    39  		return d
    40  	}
    41  	switch v := v.(type) {
    42  	case *map[string]interface{}:
    43  		if err := yaml.Unmarshal(data, v, preserveIntFloat); err != nil {
    44  			return err
    45  		}
    46  		return jsonutil.ConvertMapNumbers(*v, 0)
    47  	case *[]interface{}:
    48  		if err := yaml.Unmarshal(data, v, preserveIntFloat); err != nil {
    49  			return err
    50  		}
    51  		return jsonutil.ConvertSliceNumbers(*v, 0)
    52  	case *interface{}:
    53  		if err := yaml.Unmarshal(data, v, preserveIntFloat); err != nil {
    54  			return err
    55  		}
    56  		return jsonutil.ConvertInterfaceNumbers(v, 0)
    57  	default:
    58  		return yaml.Unmarshal(data, v)
    59  	}
    60  }
    61  
    62  // UnmarshalStrict unmarshals the given data
    63  // strictly (erroring when there are duplicate fields).
    64  func UnmarshalStrict(data []byte, v interface{}) error {
    65  	preserveIntFloat := func(d *json.Decoder) *json.Decoder {
    66  		d.UseNumber()
    67  		return d
    68  	}
    69  	switch v := v.(type) {
    70  	case *map[string]interface{}:
    71  		if err := yaml.UnmarshalStrict(data, v, preserveIntFloat); err != nil {
    72  			return err
    73  		}
    74  		return jsonutil.ConvertMapNumbers(*v, 0)
    75  	case *[]interface{}:
    76  		if err := yaml.UnmarshalStrict(data, v, preserveIntFloat); err != nil {
    77  			return err
    78  		}
    79  		return jsonutil.ConvertSliceNumbers(*v, 0)
    80  	case *interface{}:
    81  		if err := yaml.UnmarshalStrict(data, v, preserveIntFloat); err != nil {
    82  			return err
    83  		}
    84  		return jsonutil.ConvertInterfaceNumbers(v, 0)
    85  	default:
    86  		return yaml.UnmarshalStrict(data, v)
    87  	}
    88  }
    89  
    90  // ToJSON converts a single YAML document into a JSON document
    91  // or returns an error. If the document appears to be JSON the
    92  // YAML decoding path is not used (so that error messages are
    93  // JSON specific).
    94  func ToJSON(data []byte) ([]byte, error) {
    95  	if hasJSONPrefix(data) {
    96  		return data, nil
    97  	}
    98  	return yaml.YAMLToJSON(data)
    99  }
   100  
   101  // YAMLToJSONDecoder decodes YAML documents from an io.Reader by
   102  // separating individual documents. It first converts the YAML
   103  // body to JSON, then unmarshals the JSON.
   104  type YAMLToJSONDecoder struct {
   105  	reader Reader
   106  }
   107  
   108  // NewYAMLToJSONDecoder decodes YAML documents from the provided
   109  // stream in chunks by converting each document (as defined by
   110  // the YAML spec) into its own chunk, converting it to JSON via
   111  // yaml.YAMLToJSON, and then passing it to json.Decoder.
   112  func NewYAMLToJSONDecoder(r io.Reader) *YAMLToJSONDecoder {
   113  	reader := bufio.NewReader(r)
   114  	return &YAMLToJSONDecoder{
   115  		reader: NewYAMLReader(reader),
   116  	}
   117  }
   118  
   119  // Decode reads a YAML document as JSON from the stream or returns
   120  // an error. The decoding rules match json.Unmarshal, not
   121  // yaml.Unmarshal.
   122  func (d *YAMLToJSONDecoder) Decode(into interface{}) error {
   123  	bytes, err := d.reader.Read()
   124  	if err != nil && err != io.EOF {
   125  		return err
   126  	}
   127  
   128  	if len(bytes) != 0 {
   129  		err := yaml.Unmarshal(bytes, into)
   130  		if err != nil {
   131  			return YAMLSyntaxError{err}
   132  		}
   133  	}
   134  	return err
   135  }
   136  
   137  // YAMLDecoder reads chunks of objects and returns ErrShortBuffer if
   138  // the data is not sufficient.
   139  type YAMLDecoder struct {
   140  	r         io.ReadCloser
   141  	scanner   *bufio.Scanner
   142  	remaining []byte
   143  }
   144  
   145  // NewDocumentDecoder decodes YAML documents from the provided
   146  // stream in chunks by converting each document (as defined by
   147  // the YAML spec) into its own chunk. io.ErrShortBuffer will be
   148  // returned if the entire buffer could not be read to assist
   149  // the caller in framing the chunk.
   150  func NewDocumentDecoder(r io.ReadCloser) io.ReadCloser {
   151  	scanner := bufio.NewScanner(r)
   152  	// the size of initial allocation for buffer 4k
   153  	buf := make([]byte, 4*1024)
   154  	// the maximum size used to buffer a token 5M
   155  	scanner.Buffer(buf, 5*1024*1024)
   156  	scanner.Split(splitYAMLDocument)
   157  	return &YAMLDecoder{
   158  		r:       r,
   159  		scanner: scanner,
   160  	}
   161  }
   162  
   163  // Read reads the previous slice into the buffer, or attempts to read
   164  // the next chunk.
   165  // TODO: switch to readline approach.
   166  func (d *YAMLDecoder) Read(data []byte) (n int, err error) {
   167  	left := len(d.remaining)
   168  	if left == 0 {
   169  		// return the next chunk from the stream
   170  		if !d.scanner.Scan() {
   171  			err := d.scanner.Err()
   172  			if err == nil {
   173  				err = io.EOF
   174  			}
   175  			return 0, err
   176  		}
   177  		out := d.scanner.Bytes()
   178  		d.remaining = out
   179  		left = len(out)
   180  	}
   181  
   182  	// fits within data
   183  	if left <= len(data) {
   184  		copy(data, d.remaining)
   185  		d.remaining = nil
   186  		return left, nil
   187  	}
   188  
   189  	// caller will need to reread
   190  	copy(data, d.remaining[:len(data)])
   191  	d.remaining = d.remaining[len(data):]
   192  	return len(data), io.ErrShortBuffer
   193  }
   194  
   195  func (d *YAMLDecoder) Close() error {
   196  	return d.r.Close()
   197  }
   198  
   199  const yamlSeparator = "\n---"
   200  const separator = "---"
   201  
   202  // splitYAMLDocument is a bufio.SplitFunc for splitting YAML streams into individual documents.
   203  func splitYAMLDocument(data []byte, atEOF bool) (advance int, token []byte, err error) {
   204  	if atEOF && len(data) == 0 {
   205  		return 0, nil, nil
   206  	}
   207  	sep := len([]byte(yamlSeparator))
   208  	if i := bytes.Index(data, []byte(yamlSeparator)); i >= 0 {
   209  		// We have a potential document terminator
   210  		i += sep
   211  		after := data[i:]
   212  		if len(after) == 0 {
   213  			// we can't read any more characters
   214  			if atEOF {
   215  				return len(data), data[:len(data)-sep], nil
   216  			}
   217  			return 0, nil, nil
   218  		}
   219  		if j := bytes.IndexByte(after, '\n'); j >= 0 {
   220  			return i + j + 1, data[0 : i-sep], nil
   221  		}
   222  		return 0, nil, nil
   223  	}
   224  	// If we're at EOF, we have a final, non-terminated line. Return it.
   225  	if atEOF {
   226  		return len(data), data, nil
   227  	}
   228  	// Request more data.
   229  	return 0, nil, nil
   230  }
   231  
   232  // decoder is a convenience interface for Decode.
   233  type decoder interface {
   234  	Decode(into interface{}) error
   235  }
   236  
   237  // YAMLOrJSONDecoder attempts to decode a stream of JSON documents or
   238  // YAML documents by sniffing for a leading { character.
   239  type YAMLOrJSONDecoder struct {
   240  	r          io.Reader
   241  	bufferSize int
   242  
   243  	decoder decoder
   244  }
   245  
   246  type JSONSyntaxError struct {
   247  	Offset int64
   248  	Err    error
   249  }
   250  
   251  func (e JSONSyntaxError) Error() string {
   252  	return fmt.Sprintf("json: offset %d: %s", e.Offset, e.Err.Error())
   253  }
   254  
   255  type YAMLSyntaxError struct {
   256  	err error
   257  }
   258  
   259  func (e YAMLSyntaxError) Error() string {
   260  	return e.err.Error()
   261  }
   262  
   263  // NewYAMLOrJSONDecoder returns a decoder that will process YAML documents
   264  // or JSON documents from the given reader as a stream. bufferSize determines
   265  // how far into the stream the decoder will look to figure out whether this
   266  // is a JSON stream (has whitespace followed by an open brace).
   267  func NewYAMLOrJSONDecoder(r io.Reader, bufferSize int) *YAMLOrJSONDecoder {
   268  	return &YAMLOrJSONDecoder{
   269  		r:          r,
   270  		bufferSize: bufferSize,
   271  	}
   272  }
   273  
   274  // Decode unmarshals the next object from the underlying stream into the
   275  // provide object, or returns an error.
   276  func (d *YAMLOrJSONDecoder) Decode(into interface{}) error {
   277  	if d.decoder == nil {
   278  		buffer, _, isJSON := GuessJSONStream(d.r, d.bufferSize)
   279  		if isJSON {
   280  			d.decoder = json.NewDecoder(buffer)
   281  		} else {
   282  			d.decoder = NewYAMLToJSONDecoder(buffer)
   283  		}
   284  	}
   285  	err := d.decoder.Decode(into)
   286  	if syntax, ok := err.(*json.SyntaxError); ok {
   287  		return JSONSyntaxError{
   288  			Offset: syntax.Offset,
   289  			Err:    syntax,
   290  		}
   291  	}
   292  	return err
   293  }
   294  
   295  type Reader interface {
   296  	Read() ([]byte, error)
   297  }
   298  
   299  type YAMLReader struct {
   300  	reader Reader
   301  }
   302  
   303  func NewYAMLReader(r *bufio.Reader) *YAMLReader {
   304  	return &YAMLReader{
   305  		reader: &LineReader{reader: r},
   306  	}
   307  }
   308  
   309  // Read returns a full YAML document.
   310  func (r *YAMLReader) Read() ([]byte, error) {
   311  	var buffer bytes.Buffer
   312  	for {
   313  		line, err := r.reader.Read()
   314  		if err != nil && err != io.EOF {
   315  			return nil, err
   316  		}
   317  
   318  		sep := len([]byte(separator))
   319  		if i := bytes.Index(line, []byte(separator)); i == 0 {
   320  			// We have a potential document terminator
   321  			i += sep
   322  			trimmed := strings.TrimSpace(string(line[i:]))
   323  			// We only allow comments and spaces following the yaml doc separator, otherwise we'll return an error
   324  			if len(trimmed) > 0 && string(trimmed[0]) != "#" {
   325  				return nil, YAMLSyntaxError{
   326  					err: fmt.Errorf("invalid Yaml document separator: %s", trimmed),
   327  				}
   328  			}
   329  			if buffer.Len() != 0 {
   330  				return buffer.Bytes(), nil
   331  			}
   332  			if err == io.EOF {
   333  				return nil, err
   334  			}
   335  		}
   336  		if err == io.EOF {
   337  			if buffer.Len() != 0 {
   338  				// If we're at EOF, we have a final, non-terminated line. Return it.
   339  				return buffer.Bytes(), nil
   340  			}
   341  			return nil, err
   342  		}
   343  		buffer.Write(line)
   344  	}
   345  }
   346  
   347  type LineReader struct {
   348  	reader *bufio.Reader
   349  }
   350  
   351  // Read returns a single line (with '\n' ended) from the underlying reader.
   352  // An error is returned iff there is an error with the underlying reader.
   353  func (r *LineReader) Read() ([]byte, error) {
   354  	var (
   355  		isPrefix bool  = true
   356  		err      error = nil
   357  		line     []byte
   358  		buffer   bytes.Buffer
   359  	)
   360  
   361  	for isPrefix && err == nil {
   362  		line, isPrefix, err = r.reader.ReadLine()
   363  		buffer.Write(line)
   364  	}
   365  	buffer.WriteByte('\n')
   366  	return buffer.Bytes(), err
   367  }
   368  
   369  // GuessJSONStream scans the provided reader up to size, looking
   370  // for an open brace indicating this is JSON. It will return the
   371  // bufio.Reader it creates for the consumer.
   372  func GuessJSONStream(r io.Reader, size int) (io.Reader, []byte, bool) {
   373  	buffer := bufio.NewReaderSize(r, size)
   374  	b, _ := buffer.Peek(size)
   375  	return buffer, b, hasJSONPrefix(b)
   376  }
   377  
   378  // IsJSONBuffer scans the provided buffer, looking
   379  // for an open brace indicating this is JSON.
   380  func IsJSONBuffer(buf []byte) bool {
   381  	return hasJSONPrefix(buf)
   382  }
   383  
   384  var jsonPrefix = []byte("{")
   385  
   386  // hasJSONPrefix returns true if the provided buffer appears to start with
   387  // a JSON open brace.
   388  func hasJSONPrefix(buf []byte) bool {
   389  	return hasPrefix(buf, jsonPrefix)
   390  }
   391  
   392  // Return true if the first non-whitespace bytes in buf is
   393  // prefix.
   394  func hasPrefix(buf []byte, prefix []byte) bool {
   395  	trim := bytes.TrimLeftFunc(buf, unicode.IsSpace)
   396  	return bytes.HasPrefix(trim, prefix)
   397  }