| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698 | //// Copyright (c) 2011-2019 Canonical Ltd//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at////     http://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// Package yaml implements YAML support for the Go language.//// Source code and other details for the project are available at GitHub:////   https://github.com/go-yaml/yaml//package yamlimport (	"errors"	"fmt"	"io"	"reflect"	"strings"	"sync"	"unicode/utf8")// The Unmarshaler interface may be implemented by types to customize their// behavior when being unmarshaled from a YAML document.type Unmarshaler interface {	UnmarshalYAML(value *Node) error}type obsoleteUnmarshaler interface {	UnmarshalYAML(unmarshal func(interface{}) error) error}// The Marshaler interface may be implemented by types to customize their// behavior when being marshaled into a YAML document. The returned value// is marshaled in place of the original value implementing Marshaler.//// If an error is returned by MarshalYAML, the marshaling procedure stops// and returns with the provided error.type Marshaler interface {	MarshalYAML() (interface{}, error)}// Unmarshal decodes the first document found within the in byte slice// and assigns decoded values into the out value.//// Maps and pointers (to a struct, string, int, etc) are accepted as out// values. If an internal pointer within a struct is not initialized,// the yaml package will initialize it if necessary for unmarshalling// the provided data. The out parameter must not be nil.//// The type of the decoded values should be compatible with the respective// values in out. If one or more values cannot be decoded due to a type// mismatches, decoding continues partially until the end of the YAML// content, and a *yaml.TypeError is returned with details for all// missed values.//// Struct fields are only unmarshalled if they are exported (have an// upper case first letter), and are unmarshalled using the field name// lowercased as the default key. Custom keys may be defined via the// "yaml" name in the field tag: the content preceding the first comma// is used as the key, and the following comma-separated options are// used to tweak the marshalling process (see Marshal).// Conflicting names result in a runtime error.//// For example:////     type T struct {//         F int `yaml:"a,omitempty"`//         B int//     }//     var t T//     yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)//// See the documentation of Marshal for the format of tags and a list of// supported tag options.//func Unmarshal(in []byte, out interface{}) (err error) {	return unmarshal(in, out, false)}// A Decoder reads and decodes YAML values from an input stream.type Decoder struct {	parser      *parser	knownFields bool}// NewDecoder returns a new decoder that reads from r.//// The decoder introduces its own buffering and may read// data from r beyond the YAML values requested.func NewDecoder(r io.Reader) *Decoder {	return &Decoder{		parser: newParserFromReader(r),	}}// KnownFields ensures that the keys in decoded mappings to// exist as fields in the struct being decoded into.func (dec *Decoder) KnownFields(enable bool) {	dec.knownFields = enable}// Decode reads the next YAML-encoded value from its input// and stores it in the value pointed to by v.//// See the documentation for Unmarshal for details about the// conversion of YAML into a Go value.func (dec *Decoder) Decode(v interface{}) (err error) {	d := newDecoder()	d.knownFields = dec.knownFields	defer handleErr(&err)	node := dec.parser.parse()	if node == nil {		return io.EOF	}	out := reflect.ValueOf(v)	if out.Kind() == reflect.Ptr && !out.IsNil() {		out = out.Elem()	}	d.unmarshal(node, out)	if len(d.terrors) > 0 {		return &TypeError{d.terrors}	}	return nil}// Decode decodes the node and stores its data into the value pointed to by v.//// See the documentation for Unmarshal for details about the// conversion of YAML into a Go value.func (n *Node) Decode(v interface{}) (err error) {	d := newDecoder()	defer handleErr(&err)	out := reflect.ValueOf(v)	if out.Kind() == reflect.Ptr && !out.IsNil() {		out = out.Elem()	}	d.unmarshal(n, out)	if len(d.terrors) > 0 {		return &TypeError{d.terrors}	}	return nil}func unmarshal(in []byte, out interface{}, strict bool) (err error) {	defer handleErr(&err)	d := newDecoder()	p := newParser(in)	defer p.destroy()	node := p.parse()	if node != nil {		v := reflect.ValueOf(out)		if v.Kind() == reflect.Ptr && !v.IsNil() {			v = v.Elem()		}		d.unmarshal(node, v)	}	if len(d.terrors) > 0 {		return &TypeError{d.terrors}	}	return nil}// Marshal serializes the value provided into a YAML document. The structure// of the generated document will reflect the structure of the value itself.// Maps and pointers (to struct, string, int, etc) are accepted as the in value.//// Struct fields are only marshalled if they are exported (have an upper case// first letter), and are marshalled using the field name lowercased as the// default key. Custom keys may be defined via the "yaml" name in the field// tag: the content preceding the first comma is used as the key, and the// following comma-separated options are used to tweak the marshalling process.// Conflicting names result in a runtime error.//// The field tag format accepted is:////     `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`//// The following flags are currently supported:////     omitempty    Only include the field if it's not set to the zero//                  value for the type or to empty slices or maps.//                  Zero valued structs will be omitted if all their public//                  fields are zero, unless they implement an IsZero//                  method (see the IsZeroer interface type), in which//                  case the field will be excluded if IsZero returns true.////     flow         Marshal using a flow style (useful for structs,//                  sequences and maps).////     inline       Inline the field, which must be a struct or a map,//                  causing all of its fields or keys to be processed as if//                  they were part of the outer struct. For maps, keys must//                  not conflict with the yaml keys of other struct fields.//// In addition, if the key is "-", the field is ignored.//// For example:////     type T struct {//         F int `yaml:"a,omitempty"`//         B int//     }//     yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"//     yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n"//func Marshal(in interface{}) (out []byte, err error) {	defer handleErr(&err)	e := newEncoder()	defer e.destroy()	e.marshalDoc("", reflect.ValueOf(in))	e.finish()	out = e.out	return}// An Encoder writes YAML values to an output stream.type Encoder struct {	encoder *encoder}// NewEncoder returns a new encoder that writes to w.// The Encoder should be closed after use to flush all data// to w.func NewEncoder(w io.Writer) *Encoder {	return &Encoder{		encoder: newEncoderWithWriter(w),	}}// Encode writes the YAML encoding of v to the stream.// If multiple items are encoded to the stream, the// second and subsequent document will be preceded// with a "---" document separator, but the first will not.//// See the documentation for Marshal for details about the conversion of Go// values to YAML.func (e *Encoder) Encode(v interface{}) (err error) {	defer handleErr(&err)	e.encoder.marshalDoc("", reflect.ValueOf(v))	return nil}// Encode encodes value v and stores its representation in n.//// See the documentation for Marshal for details about the// conversion of Go values into YAML.func (n *Node) Encode(v interface{}) (err error) {	defer handleErr(&err)	e := newEncoder()	defer e.destroy()	e.marshalDoc("", reflect.ValueOf(v))	e.finish()	p := newParser(e.out)	p.textless = true	defer p.destroy()	doc := p.parse()	*n = *doc.Content[0]	return nil}// SetIndent changes the used indentation used when encoding.func (e *Encoder) SetIndent(spaces int) {	if spaces < 0 {		panic("yaml: cannot indent to a negative number of spaces")	}	e.encoder.indent = spaces}// Close closes the encoder by writing any remaining data.// It does not write a stream terminating string "...".func (e *Encoder) Close() (err error) {	defer handleErr(&err)	e.encoder.finish()	return nil}func handleErr(err *error) {	if v := recover(); v != nil {		if e, ok := v.(yamlError); ok {			*err = e.err		} else {			panic(v)		}	}}type yamlError struct {	err error}func fail(err error) {	panic(yamlError{err})}func failf(format string, args ...interface{}) {	panic(yamlError{fmt.Errorf("yaml: "+format, args...)})}// A TypeError is returned by Unmarshal when one or more fields in// the YAML document cannot be properly decoded into the requested// types. When this error is returned, the value is still// unmarshaled partially.type TypeError struct {	Errors []string}func (e *TypeError) Error() string {	return fmt.Sprintf("yaml: unmarshal errors:\n  %s", strings.Join(e.Errors, "\n  "))}type Kind uint32const (	DocumentNode Kind = 1 << iota	SequenceNode	MappingNode	ScalarNode	AliasNode)type Style uint32const (	TaggedStyle Style = 1 << iota	DoubleQuotedStyle	SingleQuotedStyle	LiteralStyle	FoldedStyle	FlowStyle)// Node represents an element in the YAML document hierarchy. While documents// are typically encoded and decoded into higher level types, such as structs// and maps, Node is an intermediate representation that allows detailed// control over the content being decoded or encoded.//// It's worth noting that although Node offers access into details such as// line numbers, colums, and comments, the content when re-encoded will not// have its original textual representation preserved. An effort is made to// render the data plesantly, and to preserve comments near the data they// describe, though.//// Values that make use of the Node type interact with the yaml package in the// same way any other type would do, by encoding and decoding yaml data// directly or indirectly into them.//// For example:////     var person struct {//             Name    string//             Address yaml.Node//     }//     err := yaml.Unmarshal(data, &person)// // Or by itself:////     var person Node//     err := yaml.Unmarshal(data, &person)//type Node struct {	// Kind defines whether the node is a document, a mapping, a sequence,	// a scalar value, or an alias to another node. The specific data type of	// scalar nodes may be obtained via the ShortTag and LongTag methods.	Kind  Kind	// Style allows customizing the apperance of the node in the tree.	Style Style	// Tag holds the YAML tag defining the data type for the value.	// When decoding, this field will always be set to the resolved tag,	// even when it wasn't explicitly provided in the YAML content.	// When encoding, if this field is unset the value type will be	// implied from the node properties, and if it is set, it will only	// be serialized into the representation if TaggedStyle is used or	// the implicit tag diverges from the provided one.	Tag string	// Value holds the unescaped and unquoted represenation of the value.	Value string	// Anchor holds the anchor name for this node, which allows aliases to point to it.	Anchor string	// Alias holds the node that this alias points to. Only valid when Kind is AliasNode.	Alias *Node	// Content holds contained nodes for documents, mappings, and sequences.	Content []*Node	// HeadComment holds any comments in the lines preceding the node and	// not separated by an empty line.	HeadComment string	// LineComment holds any comments at the end of the line where the node is in.	LineComment string	// FootComment holds any comments following the node and before empty lines.	FootComment string	// Line and Column hold the node position in the decoded YAML text.	// These fields are not respected when encoding the node.	Line   int	Column int}// IsZero returns whether the node has all of its fields unset.func (n *Node) IsZero() bool {	return n.Kind == 0 && n.Style == 0 && n.Tag == "" && n.Value == "" && n.Anchor == "" && n.Alias == nil && n.Content == nil &&		n.HeadComment == "" && n.LineComment == "" && n.FootComment == "" && n.Line == 0 && n.Column == 0}// LongTag returns the long form of the tag that indicates the data type for// the node. If the Tag field isn't explicitly defined, one will be computed// based on the node properties.func (n *Node) LongTag() string {	return longTag(n.ShortTag())}// ShortTag returns the short form of the YAML tag that indicates data type for// the node. If the Tag field isn't explicitly defined, one will be computed// based on the node properties.func (n *Node) ShortTag() string {	if n.indicatedString() {		return strTag	}	if n.Tag == "" || n.Tag == "!" {		switch n.Kind {		case MappingNode:			return mapTag		case SequenceNode:			return seqTag		case AliasNode:			if n.Alias != nil {				return n.Alias.ShortTag()			}		case ScalarNode:			tag, _ := resolve("", n.Value)			return tag		case 0:			// Special case to make the zero value convenient.			if n.IsZero() {				return nullTag			}		}		return ""	}	return shortTag(n.Tag)}func (n *Node) indicatedString() bool {	return n.Kind == ScalarNode &&		(shortTag(n.Tag) == strTag ||			(n.Tag == "" || n.Tag == "!") && n.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0)}// SetString is a convenience function that sets the node to a string value// and defines its style in a pleasant way depending on its content.func (n *Node) SetString(s string) {	n.Kind = ScalarNode	if utf8.ValidString(s) {		n.Value = s		n.Tag = strTag	} else {		n.Value = encodeBase64(s)		n.Tag = binaryTag	}	if strings.Contains(n.Value, "\n") {		n.Style = LiteralStyle	}}// --------------------------------------------------------------------------// Maintain a mapping of keys to structure field indexes// The code in this section was copied from mgo/bson.// structInfo holds details for the serialization of fields of// a given struct.type structInfo struct {	FieldsMap  map[string]fieldInfo	FieldsList []fieldInfo	// InlineMap is the number of the field in the struct that	// contains an ,inline map, or -1 if there's none.	InlineMap int	// InlineUnmarshalers holds indexes to inlined fields that	// contain unmarshaler values.	InlineUnmarshalers [][]int}type fieldInfo struct {	Key       string	Num       int	OmitEmpty bool	Flow      bool	// Id holds the unique field identifier, so we can cheaply	// check for field duplicates without maintaining an extra map.	Id int	// Inline holds the field index if the field is part of an inlined struct.	Inline []int}var structMap = make(map[reflect.Type]*structInfo)var fieldMapMutex sync.RWMutexvar unmarshalerType reflect.Typefunc init() {	var v Unmarshaler	unmarshalerType = reflect.ValueOf(&v).Elem().Type()}func getStructInfo(st reflect.Type) (*structInfo, error) {	fieldMapMutex.RLock()	sinfo, found := structMap[st]	fieldMapMutex.RUnlock()	if found {		return sinfo, nil	}	n := st.NumField()	fieldsMap := make(map[string]fieldInfo)	fieldsList := make([]fieldInfo, 0, n)	inlineMap := -1	inlineUnmarshalers := [][]int(nil)	for i := 0; i != n; i++ {		field := st.Field(i)		if field.PkgPath != "" && !field.Anonymous {			continue // Private field		}		info := fieldInfo{Num: i}		tag := field.Tag.Get("yaml")		if tag == "" && strings.Index(string(field.Tag), ":") < 0 {			tag = string(field.Tag)		}		if tag == "-" {			continue		}		inline := false		fields := strings.Split(tag, ",")		if len(fields) > 1 {			for _, flag := range fields[1:] {				switch flag {				case "omitempty":					info.OmitEmpty = true				case "flow":					info.Flow = true				case "inline":					inline = true				default:					return nil, errors.New(fmt.Sprintf("unsupported flag %q in tag %q of type %s", flag, tag, st))				}			}			tag = fields[0]		}		if inline {			switch field.Type.Kind() {			case reflect.Map:				if inlineMap >= 0 {					return nil, errors.New("multiple ,inline maps in struct " + st.String())				}				if field.Type.Key() != reflect.TypeOf("") {					return nil, errors.New("option ,inline needs a map with string keys in struct " + st.String())				}				inlineMap = info.Num			case reflect.Struct, reflect.Ptr:				ftype := field.Type				for ftype.Kind() == reflect.Ptr {					ftype = ftype.Elem()				}				if ftype.Kind() != reflect.Struct {					return nil, errors.New("option ,inline may only be used on a struct or map field")				}				if reflect.PtrTo(ftype).Implements(unmarshalerType) {					inlineUnmarshalers = append(inlineUnmarshalers, []int{i})				} else {					sinfo, err := getStructInfo(ftype)					if err != nil {						return nil, err					}					for _, index := range sinfo.InlineUnmarshalers {						inlineUnmarshalers = append(inlineUnmarshalers, append([]int{i}, index...))					}					for _, finfo := range sinfo.FieldsList {						if _, found := fieldsMap[finfo.Key]; found {							msg := "duplicated key '" + finfo.Key + "' in struct " + st.String()							return nil, errors.New(msg)						}						if finfo.Inline == nil {							finfo.Inline = []int{i, finfo.Num}						} else {							finfo.Inline = append([]int{i}, finfo.Inline...)						}						finfo.Id = len(fieldsList)						fieldsMap[finfo.Key] = finfo						fieldsList = append(fieldsList, finfo)					}				}			default:				return nil, errors.New("option ,inline may only be used on a struct or map field")			}			continue		}		if tag != "" {			info.Key = tag		} else {			info.Key = strings.ToLower(field.Name)		}		if _, found = fieldsMap[info.Key]; found {			msg := "duplicated key '" + info.Key + "' in struct " + st.String()			return nil, errors.New(msg)		}		info.Id = len(fieldsList)		fieldsList = append(fieldsList, info)		fieldsMap[info.Key] = info	}	sinfo = &structInfo{		FieldsMap:          fieldsMap,		FieldsList:         fieldsList,		InlineMap:          inlineMap,		InlineUnmarshalers: inlineUnmarshalers,	}	fieldMapMutex.Lock()	structMap[st] = sinfo	fieldMapMutex.Unlock()	return sinfo, nil}// IsZeroer is used to check whether an object is zero to// determine whether it should be omitted when marshaling// with the omitempty flag. One notable implementation// is time.Time.type IsZeroer interface {	IsZero() bool}func isZero(v reflect.Value) bool {	kind := v.Kind()	if z, ok := v.Interface().(IsZeroer); ok {		if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() {			return true		}		return z.IsZero()	}	switch kind {	case reflect.String:		return len(v.String()) == 0	case reflect.Interface, reflect.Ptr:		return v.IsNil()	case reflect.Slice:		return v.Len() == 0	case reflect.Map:		return v.Len() == 0	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:		return v.Int() == 0	case reflect.Float32, reflect.Float64:		return v.Float() == 0	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:		return v.Uint() == 0	case reflect.Bool:		return !v.Bool()	case reflect.Struct:		vt := v.Type()		for i := v.NumField() - 1; i >= 0; i-- {			if vt.Field(i).PkgPath != "" {				continue // Private field			}			if !isZero(v.Field(i)) {				return false			}		}		return true	}	return false}
 |