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