auto-update-daily-20260202
1//
2// Copyright (c) 2011-2019 Canonical Ltd
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// Package yaml implements YAML support for the Go language.
17//
18// Source code and other details for the project are available at GitHub:
19//
20// https://github.com/go-yaml/yaml
21package yaml
22
23import (
24 "errors"
25 "fmt"
26 "io"
27 "reflect"
28 "strings"
29 "sync"
30 "unicode/utf8"
31)
32
33// The Unmarshaler interface may be implemented by types to customize their
34// behavior when being unmarshaled from a YAML document.
35type Unmarshaler interface {
36 UnmarshalYAML(value *Node) error
37}
38
39type obsoleteUnmarshaler interface {
40 UnmarshalYAML(unmarshal func(interface{}) error) error
41}
42
43// The Marshaler interface may be implemented by types to customize their
44// behavior when being marshaled into a YAML document. The returned value
45// is marshaled in place of the original value implementing Marshaler.
46//
47// If an error is returned by MarshalYAML, the marshaling procedure stops
48// and returns with the provided error.
49type Marshaler interface {
50 MarshalYAML() (interface{}, error)
51}
52
53// Unmarshal decodes the first document found within the in byte slice
54// and assigns decoded values into the out value.
55//
56// Maps and pointers (to a struct, string, int, etc) are accepted as out
57// values. If an internal pointer within a struct is not initialized,
58// the yaml package will initialize it if necessary for unmarshalling
59// the provided data. The out parameter must not be nil.
60//
61// The type of the decoded values should be compatible with the respective
62// values in out. If one or more values cannot be decoded due to a type
63// mismatches, decoding continues partially until the end of the YAML
64// content, and a *yaml.TypeError is returned with details for all
65// missed values.
66//
67// Struct fields are only unmarshalled if they are exported (have an
68// upper case first letter), and are unmarshalled using the field name
69// lowercased as the default key. Custom keys may be defined via the
70// "yaml" name in the field tag: the content preceding the first comma
71// is used as the key, and the following comma-separated options are
72// used to tweak the marshalling process (see Marshal).
73// Conflicting names result in a runtime error.
74//
75// For example:
76//
77// type T struct {
78// F int `yaml:"a,omitempty"`
79// B int
80// }
81// var t T
82// yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
83//
84// See the documentation of Marshal for the format of tags and a list of
85// supported tag options.
86func Unmarshal(in []byte, out interface{}) (err error) {
87 return unmarshal(in, out, false)
88}
89
90// A Decoder reads and decodes YAML values from an input stream.
91type Decoder struct {
92 parser *parser
93 knownFields bool
94}
95
96// NewDecoder returns a new decoder that reads from r.
97//
98// The decoder introduces its own buffering and may read
99// data from r beyond the YAML values requested.
100func NewDecoder(r io.Reader) *Decoder {
101 return &Decoder{
102 parser: newParserFromReader(r),
103 }
104}
105
106// KnownFields ensures that the keys in decoded mappings to
107// exist as fields in the struct being decoded into.
108func (dec *Decoder) KnownFields(enable bool) {
109 dec.knownFields = enable
110}
111
112// Decode reads the next YAML-encoded value from its input
113// and stores it in the value pointed to by v.
114//
115// See the documentation for Unmarshal for details about the
116// conversion of YAML into a Go value.
117func (dec *Decoder) Decode(v interface{}) (err error) {
118 d := newDecoder()
119 d.knownFields = dec.knownFields
120 defer handleErr(&err)
121 node := dec.parser.parse()
122 if node == nil {
123 return io.EOF
124 }
125 out := reflect.ValueOf(v)
126 if out.Kind() == reflect.Ptr && !out.IsNil() {
127 out = out.Elem()
128 }
129 d.unmarshal(node, out)
130 if len(d.terrors) > 0 {
131 return &TypeError{d.terrors}
132 }
133 return nil
134}
135
136// Decode decodes the node and stores its data into the value pointed to by v.
137//
138// See the documentation for Unmarshal for details about the
139// conversion of YAML into a Go value.
140func (n *Node) Decode(v interface{}) (err error) {
141 d := newDecoder()
142 defer handleErr(&err)
143 out := reflect.ValueOf(v)
144 if out.Kind() == reflect.Ptr && !out.IsNil() {
145 out = out.Elem()
146 }
147 d.unmarshal(n, out)
148 if len(d.terrors) > 0 {
149 return &TypeError{d.terrors}
150 }
151 return nil
152}
153
154func unmarshal(in []byte, out interface{}, strict bool) (err error) {
155 defer handleErr(&err)
156 d := newDecoder()
157 p := newParser(in)
158 defer p.destroy()
159 node := p.parse()
160 if node != nil {
161 v := reflect.ValueOf(out)
162 if v.Kind() == reflect.Ptr && !v.IsNil() {
163 v = v.Elem()
164 }
165 d.unmarshal(node, v)
166 }
167 if len(d.terrors) > 0 {
168 return &TypeError{d.terrors}
169 }
170 return nil
171}
172
173// Marshal serializes the value provided into a YAML document. The structure
174// of the generated document will reflect the structure of the value itself.
175// Maps and pointers (to struct, string, int, etc) are accepted as the in value.
176//
177// Struct fields are only marshalled if they are exported (have an upper case
178// first letter), and are marshalled using the field name lowercased as the
179// default key. Custom keys may be defined via the "yaml" name in the field
180// tag: the content preceding the first comma is used as the key, and the
181// following comma-separated options are used to tweak the marshalling process.
182// Conflicting names result in a runtime error.
183//
184// The field tag format accepted is:
185//
186// `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
187//
188// The following flags are currently supported:
189//
190// omitempty Only include the field if it's not set to the zero
191// value for the type or to empty slices or maps.
192// Zero valued structs will be omitted if all their public
193// fields are zero, unless they implement an IsZero
194// method (see the IsZeroer interface type), in which
195// case the field will be excluded if IsZero returns true.
196//
197// flow Marshal using a flow style (useful for structs,
198// sequences and maps).
199//
200// inline Inline the field, which must be a struct or a map,
201// causing all of its fields or keys to be processed as if
202// they were part of the outer struct. For maps, keys must
203// not conflict with the yaml keys of other struct fields.
204//
205// In addition, if the key is "-", the field is ignored.
206//
207// For example:
208//
209// type T struct {
210// F int `yaml:"a,omitempty"`
211// B int
212// }
213// yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
214// yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n"
215func Marshal(in interface{}) (out []byte, err error) {
216 defer handleErr(&err)
217 e := newEncoder()
218 defer e.destroy()
219 e.marshalDoc("", reflect.ValueOf(in))
220 e.finish()
221 out = e.out
222 return
223}
224
225// An Encoder writes YAML values to an output stream.
226type Encoder struct {
227 encoder *encoder
228}
229
230// NewEncoder returns a new encoder that writes to w.
231// The Encoder should be closed after use to flush all data
232// to w.
233func NewEncoder(w io.Writer) *Encoder {
234 return &Encoder{
235 encoder: newEncoderWithWriter(w),
236 }
237}
238
239// Encode writes the YAML encoding of v to the stream.
240// If multiple items are encoded to the stream, the
241// second and subsequent document will be preceded
242// with a "---" document separator, but the first will not.
243//
244// See the documentation for Marshal for details about the conversion of Go
245// values to YAML.
246func (e *Encoder) Encode(v interface{}) (err error) {
247 defer handleErr(&err)
248 e.encoder.marshalDoc("", reflect.ValueOf(v))
249 return nil
250}
251
252// Encode encodes value v and stores its representation in n.
253//
254// See the documentation for Marshal for details about the
255// conversion of Go values into YAML.
256func (n *Node) Encode(v interface{}) (err error) {
257 defer handleErr(&err)
258 e := newEncoder()
259 defer e.destroy()
260 e.marshalDoc("", reflect.ValueOf(v))
261 e.finish()
262 p := newParser(e.out)
263 p.textless = true
264 defer p.destroy()
265 doc := p.parse()
266 *n = *doc.Content[0]
267 return nil
268}
269
270// SetIndent changes the used indentation used when encoding.
271func (e *Encoder) SetIndent(spaces int) {
272 if spaces < 0 {
273 panic("yaml: cannot indent to a negative number of spaces")
274 }
275 e.encoder.indent = spaces
276}
277
278// Close closes the encoder by writing any remaining data.
279// It does not write a stream terminating string "...".
280func (e *Encoder) Close() (err error) {
281 defer handleErr(&err)
282 e.encoder.finish()
283 return nil
284}
285
286func handleErr(err *error) {
287 if v := recover(); v != nil {
288 if e, ok := v.(yamlError); ok {
289 *err = e.err
290 } else {
291 panic(v)
292 }
293 }
294}
295
296type yamlError struct {
297 err error
298}
299
300func fail(err error) {
301 panic(yamlError{err})
302}
303
304func failf(format string, args ...interface{}) {
305 panic(yamlError{fmt.Errorf("yaml: "+format, args...)})
306}
307
308// A TypeError is returned by Unmarshal when one or more fields in
309// the YAML document cannot be properly decoded into the requested
310// types. When this error is returned, the value is still
311// unmarshaled partially.
312type TypeError struct {
313 Errors []string
314}
315
316func (e *TypeError) Error() string {
317 return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(e.Errors, "\n "))
318}
319
320type Kind uint32
321
322const (
323 DocumentNode Kind = 1 << iota
324 SequenceNode
325 MappingNode
326 ScalarNode
327 AliasNode
328)
329
330type Style uint32
331
332const (
333 TaggedStyle Style = 1 << iota
334 DoubleQuotedStyle
335 SingleQuotedStyle
336 LiteralStyle
337 FoldedStyle
338 FlowStyle
339)
340
341// Node represents an element in the YAML document hierarchy. While documents
342// are typically encoded and decoded into higher level types, such as structs
343// and maps, Node is an intermediate representation that allows detailed
344// control over the content being decoded or encoded.
345//
346// It's worth noting that although Node offers access into details such as
347// line numbers, colums, and comments, the content when re-encoded will not
348// have its original textual representation preserved. An effort is made to
349// render the data plesantly, and to preserve comments near the data they
350// describe, though.
351//
352// Values that make use of the Node type interact with the yaml package in the
353// same way any other type would do, by encoding and decoding yaml data
354// directly or indirectly into them.
355//
356// For example:
357//
358// var person struct {
359// Name string
360// Address yaml.Node
361// }
362// err := yaml.Unmarshal(data, &person)
363//
364// Or by itself:
365//
366// var person Node
367// err := yaml.Unmarshal(data, &person)
368type Node struct {
369 // Kind defines whether the node is a document, a mapping, a sequence,
370 // a scalar value, or an alias to another node. The specific data type of
371 // scalar nodes may be obtained via the ShortTag and LongTag methods.
372 Kind Kind
373
374 // Style allows customizing the apperance of the node in the tree.
375 Style Style
376
377 // Tag holds the YAML tag defining the data type for the value.
378 // When decoding, this field will always be set to the resolved tag,
379 // even when it wasn't explicitly provided in the YAML content.
380 // When encoding, if this field is unset the value type will be
381 // implied from the node properties, and if it is set, it will only
382 // be serialized into the representation if TaggedStyle is used or
383 // the implicit tag diverges from the provided one.
384 Tag string
385
386 // Value holds the unescaped and unquoted represenation of the value.
387 Value string
388
389 // Anchor holds the anchor name for this node, which allows aliases to point to it.
390 Anchor string
391
392 // Alias holds the node that this alias points to. Only valid when Kind is AliasNode.
393 Alias *Node
394
395 // Content holds contained nodes for documents, mappings, and sequences.
396 Content []*Node
397
398 // HeadComment holds any comments in the lines preceding the node and
399 // not separated by an empty line.
400 HeadComment string
401
402 // LineComment holds any comments at the end of the line where the node is in.
403 LineComment string
404
405 // FootComment holds any comments following the node and before empty lines.
406 FootComment string
407
408 // Line and Column hold the node position in the decoded YAML text.
409 // These fields are not respected when encoding the node.
410 Line int
411 Column int
412}
413
414// IsZero returns whether the node has all of its fields unset.
415func (n *Node) IsZero() bool {
416 return n.Kind == 0 && n.Style == 0 && n.Tag == "" && n.Value == "" && n.Anchor == "" && n.Alias == nil && n.Content == nil &&
417 n.HeadComment == "" && n.LineComment == "" && n.FootComment == "" && n.Line == 0 && n.Column == 0
418}
419
420// LongTag returns the long form of the tag that indicates the data type for
421// the node. If the Tag field isn't explicitly defined, one will be computed
422// based on the node properties.
423func (n *Node) LongTag() string {
424 return longTag(n.ShortTag())
425}
426
427// ShortTag returns the short form of the YAML tag that indicates data type for
428// the node. If the Tag field isn't explicitly defined, one will be computed
429// based on the node properties.
430func (n *Node) ShortTag() string {
431 if n.indicatedString() {
432 return strTag
433 }
434 if n.Tag == "" || n.Tag == "!" {
435 switch n.Kind {
436 case MappingNode:
437 return mapTag
438 case SequenceNode:
439 return seqTag
440 case AliasNode:
441 if n.Alias != nil {
442 return n.Alias.ShortTag()
443 }
444 case ScalarNode:
445 tag, _ := resolve("", n.Value)
446 return tag
447 case 0:
448 // Special case to make the zero value convenient.
449 if n.IsZero() {
450 return nullTag
451 }
452 }
453 return ""
454 }
455 return shortTag(n.Tag)
456}
457
458func (n *Node) indicatedString() bool {
459 return n.Kind == ScalarNode &&
460 (shortTag(n.Tag) == strTag ||
461 (n.Tag == "" || n.Tag == "!") && n.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0)
462}
463
464// SetString is a convenience function that sets the node to a string value
465// and defines its style in a pleasant way depending on its content.
466func (n *Node) SetString(s string) {
467 n.Kind = ScalarNode
468 if utf8.ValidString(s) {
469 n.Value = s
470 n.Tag = strTag
471 } else {
472 n.Value = encodeBase64(s)
473 n.Tag = binaryTag
474 }
475 if strings.Contains(n.Value, "\n") {
476 n.Style = LiteralStyle
477 }
478}
479
480// --------------------------------------------------------------------------
481// Maintain a mapping of keys to structure field indexes
482
483// The code in this section was copied from mgo/bson.
484
485// structInfo holds details for the serialization of fields of
486// a given struct.
487type structInfo struct {
488 FieldsMap map[string]fieldInfo
489 FieldsList []fieldInfo
490
491 // InlineMap is the number of the field in the struct that
492 // contains an ,inline map, or -1 if there's none.
493 InlineMap int
494
495 // InlineUnmarshalers holds indexes to inlined fields that
496 // contain unmarshaler values.
497 InlineUnmarshalers [][]int
498}
499
500type fieldInfo struct {
501 Key string
502 Num int
503 OmitEmpty bool
504 Flow bool
505 // Id holds the unique field identifier, so we can cheaply
506 // check for field duplicates without maintaining an extra map.
507 Id int
508
509 // Inline holds the field index if the field is part of an inlined struct.
510 Inline []int
511}
512
513var structMap = make(map[reflect.Type]*structInfo)
514var fieldMapMutex sync.RWMutex
515var unmarshalerType reflect.Type
516
517func init() {
518 var v Unmarshaler
519 unmarshalerType = reflect.ValueOf(&v).Elem().Type()
520}
521
522func getStructInfo(st reflect.Type) (*structInfo, error) {
523 fieldMapMutex.RLock()
524 sinfo, found := structMap[st]
525 fieldMapMutex.RUnlock()
526 if found {
527 return sinfo, nil
528 }
529
530 n := st.NumField()
531 fieldsMap := make(map[string]fieldInfo)
532 fieldsList := make([]fieldInfo, 0, n)
533 inlineMap := -1
534 inlineUnmarshalers := [][]int(nil)
535 for i := 0; i != n; i++ {
536 field := st.Field(i)
537 if field.PkgPath != "" && !field.Anonymous {
538 continue // Private field
539 }
540
541 info := fieldInfo{Num: i}
542
543 tag := field.Tag.Get("yaml")
544 if tag == "" && strings.Index(string(field.Tag), ":") < 0 {
545 tag = string(field.Tag)
546 }
547 if tag == "-" {
548 continue
549 }
550
551 inline := false
552 fields := strings.Split(tag, ",")
553 if len(fields) > 1 {
554 for _, flag := range fields[1:] {
555 switch flag {
556 case "omitempty":
557 info.OmitEmpty = true
558 case "flow":
559 info.Flow = true
560 case "inline":
561 inline = true
562 default:
563 return nil, errors.New(fmt.Sprintf("unsupported flag %q in tag %q of type %s", flag, tag, st))
564 }
565 }
566 tag = fields[0]
567 }
568
569 if inline {
570 switch field.Type.Kind() {
571 case reflect.Map:
572 if inlineMap >= 0 {
573 return nil, errors.New("multiple ,inline maps in struct " + st.String())
574 }
575 if field.Type.Key() != reflect.TypeOf("") {
576 return nil, errors.New("option ,inline needs a map with string keys in struct " + st.String())
577 }
578 inlineMap = info.Num
579 case reflect.Struct, reflect.Ptr:
580 ftype := field.Type
581 for ftype.Kind() == reflect.Ptr {
582 ftype = ftype.Elem()
583 }
584 if ftype.Kind() != reflect.Struct {
585 return nil, errors.New("option ,inline may only be used on a struct or map field")
586 }
587 if reflect.PtrTo(ftype).Implements(unmarshalerType) {
588 inlineUnmarshalers = append(inlineUnmarshalers, []int{i})
589 } else {
590 sinfo, err := getStructInfo(ftype)
591 if err != nil {
592 return nil, err
593 }
594 for _, index := range sinfo.InlineUnmarshalers {
595 inlineUnmarshalers = append(inlineUnmarshalers, append([]int{i}, index...))
596 }
597 for _, finfo := range sinfo.FieldsList {
598 if _, found := fieldsMap[finfo.Key]; found {
599 msg := "duplicated key '" + finfo.Key + "' in struct " + st.String()
600 return nil, errors.New(msg)
601 }
602 if finfo.Inline == nil {
603 finfo.Inline = []int{i, finfo.Num}
604 } else {
605 finfo.Inline = append([]int{i}, finfo.Inline...)
606 }
607 finfo.Id = len(fieldsList)
608 fieldsMap[finfo.Key] = finfo
609 fieldsList = append(fieldsList, finfo)
610 }
611 }
612 default:
613 return nil, errors.New("option ,inline may only be used on a struct or map field")
614 }
615 continue
616 }
617
618 if tag != "" {
619 info.Key = tag
620 } else {
621 info.Key = strings.ToLower(field.Name)
622 }
623
624 if _, found = fieldsMap[info.Key]; found {
625 msg := "duplicated key '" + info.Key + "' in struct " + st.String()
626 return nil, errors.New(msg)
627 }
628
629 info.Id = len(fieldsList)
630 fieldsList = append(fieldsList, info)
631 fieldsMap[info.Key] = info
632 }
633
634 sinfo = &structInfo{
635 FieldsMap: fieldsMap,
636 FieldsList: fieldsList,
637 InlineMap: inlineMap,
638 InlineUnmarshalers: inlineUnmarshalers,
639 }
640
641 fieldMapMutex.Lock()
642 structMap[st] = sinfo
643 fieldMapMutex.Unlock()
644 return sinfo, nil
645}
646
647// IsZeroer is used to check whether an object is zero to
648// determine whether it should be omitted when marshaling
649// with the omitempty flag. One notable implementation
650// is time.Time.
651type IsZeroer interface {
652 IsZero() bool
653}
654
655func isZero(v reflect.Value) bool {
656 kind := v.Kind()
657 if z, ok := v.Interface().(IsZeroer); ok {
658 if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() {
659 return true
660 }
661 return z.IsZero()
662 }
663 switch kind {
664 case reflect.String:
665 return len(v.String()) == 0
666 case reflect.Interface, reflect.Ptr:
667 return v.IsNil()
668 case reflect.Slice:
669 return v.Len() == 0
670 case reflect.Map:
671 return v.Len() == 0
672 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
673 return v.Int() == 0
674 case reflect.Float32, reflect.Float64:
675 return v.Float() == 0
676 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
677 return v.Uint() == 0
678 case reflect.Bool:
679 return !v.Bool()
680 case reflect.Struct:
681 vt := v.Type()
682 for i := v.NumField() - 1; i >= 0; i-- {
683 if vt.Field(i).PkgPath != "" {
684 continue // Private field
685 }
686 if !isZero(v.Field(i)) {
687 return false
688 }
689 }
690 return true
691 }
692 return false
693}