yaml.go (20084B)
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 // 22 package yaml 23 24 import ( 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. 36 type Unmarshaler interface { 37 UnmarshalYAML(value *Node) error 38 } 39 40 type 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. 50 type 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 // 88 func Unmarshal(in []byte, out interface{}) (err error) { 89 return unmarshal(in, out, false) 90 } 91 92 // A Decoder reads and decodes YAML values from an input stream. 93 type 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. 102 func 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. 110 func (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. 119 func (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. 142 func (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 156 func 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 excluded if IsZero 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 // 218 func 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. 229 type 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. 236 func 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. 249 func (e *Encoder) Encode(v interface{}) (err error) { 250 defer handleErr(&err) 251 e.encoder.marshalDoc("", reflect.ValueOf(v)) 252 return nil 253 } 254 255 // Encode encodes value v and stores its representation in n. 256 // 257 // See the documentation for Marshal for details about the 258 // conversion of Go values into YAML. 259 func (n *Node) Encode(v interface{}) (err error) { 260 defer handleErr(&err) 261 e := newEncoder() 262 defer e.destroy() 263 e.marshalDoc("", reflect.ValueOf(v)) 264 e.finish() 265 p := newParser(e.out) 266 p.textless = true 267 defer p.destroy() 268 doc := p.parse() 269 *n = *doc.Content[0] 270 return nil 271 } 272 273 // SetIndent changes the used indentation used when encoding. 274 func (e *Encoder) SetIndent(spaces int) { 275 if spaces < 0 { 276 panic("yaml: cannot indent to a negative number of spaces") 277 } 278 e.encoder.indent = spaces 279 } 280 281 // Close closes the encoder by writing any remaining data. 282 // It does not write a stream terminating string "...". 283 func (e *Encoder) Close() (err error) { 284 defer handleErr(&err) 285 e.encoder.finish() 286 return nil 287 } 288 289 func handleErr(err *error) { 290 if v := recover(); v != nil { 291 if e, ok := v.(yamlError); ok { 292 *err = e.err 293 } else { 294 panic(v) 295 } 296 } 297 } 298 299 type yamlError struct { 300 err error 301 } 302 303 func fail(err error) { 304 panic(yamlError{err}) 305 } 306 307 func failf(format string, args ...interface{}) { 308 panic(yamlError{fmt.Errorf("yaml: "+format, args...)}) 309 } 310 311 // A TypeError is returned by Unmarshal when one or more fields in 312 // the YAML document cannot be properly decoded into the requested 313 // types. When this error is returned, the value is still 314 // unmarshaled partially. 315 type TypeError struct { 316 Errors []string 317 } 318 319 func (e *TypeError) Error() string { 320 return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(e.Errors, "\n ")) 321 } 322 323 type Kind uint32 324 325 const ( 326 DocumentNode Kind = 1 << iota 327 SequenceNode 328 MappingNode 329 ScalarNode 330 AliasNode 331 ) 332 333 type Style uint32 334 335 const ( 336 TaggedStyle Style = 1 << iota 337 DoubleQuotedStyle 338 SingleQuotedStyle 339 LiteralStyle 340 FoldedStyle 341 FlowStyle 342 ) 343 344 // Node represents an element in the YAML document hierarchy. While documents 345 // are typically encoded and decoded into higher level types, such as structs 346 // and maps, Node is an intermediate representation that allows detailed 347 // control over the content being decoded or encoded. 348 // 349 // It's worth noting that although Node offers access into details such as 350 // line numbers, colums, and comments, the content when re-encoded will not 351 // have its original textual representation preserved. An effort is made to 352 // render the data plesantly, and to preserve comments near the data they 353 // describe, though. 354 // 355 // Values that make use of the Node type interact with the yaml package in the 356 // same way any other type would do, by encoding and decoding yaml data 357 // directly or indirectly into them. 358 // 359 // For example: 360 // 361 // var person struct { 362 // Name string 363 // Address yaml.Node 364 // } 365 // err := yaml.Unmarshal(data, &person) 366 // 367 // Or by itself: 368 // 369 // var person Node 370 // err := yaml.Unmarshal(data, &person) 371 // 372 type Node struct { 373 // Kind defines whether the node is a document, a mapping, a sequence, 374 // a scalar value, or an alias to another node. The specific data type of 375 // scalar nodes may be obtained via the ShortTag and LongTag methods. 376 Kind Kind 377 378 // Style allows customizing the apperance of the node in the tree. 379 Style Style 380 381 // Tag holds the YAML tag defining the data type for the value. 382 // When decoding, this field will always be set to the resolved tag, 383 // even when it wasn't explicitly provided in the YAML content. 384 // When encoding, if this field is unset the value type will be 385 // implied from the node properties, and if it is set, it will only 386 // be serialized into the representation if TaggedStyle is used or 387 // the implicit tag diverges from the provided one. 388 Tag string 389 390 // Value holds the unescaped and unquoted represenation of the value. 391 Value string 392 393 // Anchor holds the anchor name for this node, which allows aliases to point to it. 394 Anchor string 395 396 // Alias holds the node that this alias points to. Only valid when Kind is AliasNode. 397 Alias *Node 398 399 // Content holds contained nodes for documents, mappings, and sequences. 400 Content []*Node 401 402 // HeadComment holds any comments in the lines preceding the node and 403 // not separated by an empty line. 404 HeadComment string 405 406 // LineComment holds any comments at the end of the line where the node is in. 407 LineComment string 408 409 // FootComment holds any comments following the node and before empty lines. 410 FootComment string 411 412 // Line and Column hold the node position in the decoded YAML text. 413 // These fields are not respected when encoding the node. 414 Line int 415 Column int 416 } 417 418 // IsZero returns whether the node has all of its fields unset. 419 func (n *Node) IsZero() bool { 420 return n.Kind == 0 && n.Style == 0 && n.Tag == "" && n.Value == "" && n.Anchor == "" && n.Alias == nil && n.Content == nil && 421 n.HeadComment == "" && n.LineComment == "" && n.FootComment == "" && n.Line == 0 && n.Column == 0 422 } 423 424 425 // LongTag returns the long form of the tag that indicates the data type for 426 // the node. If the Tag field isn't explicitly defined, one will be computed 427 // based on the node properties. 428 func (n *Node) LongTag() string { 429 return longTag(n.ShortTag()) 430 } 431 432 // ShortTag returns the short form of the YAML tag that indicates data type for 433 // the node. If the Tag field isn't explicitly defined, one will be computed 434 // based on the node properties. 435 func (n *Node) ShortTag() string { 436 if n.indicatedString() { 437 return strTag 438 } 439 if n.Tag == "" || n.Tag == "!" { 440 switch n.Kind { 441 case MappingNode: 442 return mapTag 443 case SequenceNode: 444 return seqTag 445 case AliasNode: 446 if n.Alias != nil { 447 return n.Alias.ShortTag() 448 } 449 case ScalarNode: 450 tag, _ := resolve("", n.Value) 451 return tag 452 case 0: 453 // Special case to make the zero value convenient. 454 if n.IsZero() { 455 return nullTag 456 } 457 } 458 return "" 459 } 460 return shortTag(n.Tag) 461 } 462 463 func (n *Node) indicatedString() bool { 464 return n.Kind == ScalarNode && 465 (shortTag(n.Tag) == strTag || 466 (n.Tag == "" || n.Tag == "!") && n.Style&(SingleQuotedStyle|DoubleQuotedStyle|LiteralStyle|FoldedStyle) != 0) 467 } 468 469 // SetString is a convenience function that sets the node to a string value 470 // and defines its style in a pleasant way depending on its content. 471 func (n *Node) SetString(s string) { 472 n.Kind = ScalarNode 473 if utf8.ValidString(s) { 474 n.Value = s 475 n.Tag = strTag 476 } else { 477 n.Value = encodeBase64(s) 478 n.Tag = binaryTag 479 } 480 if strings.Contains(n.Value, "\n") { 481 n.Style = LiteralStyle 482 } 483 } 484 485 // -------------------------------------------------------------------------- 486 // Maintain a mapping of keys to structure field indexes 487 488 // The code in this section was copied from mgo/bson. 489 490 // structInfo holds details for the serialization of fields of 491 // a given struct. 492 type structInfo struct { 493 FieldsMap map[string]fieldInfo 494 FieldsList []fieldInfo 495 496 // InlineMap is the number of the field in the struct that 497 // contains an ,inline map, or -1 if there's none. 498 InlineMap int 499 500 // InlineUnmarshalers holds indexes to inlined fields that 501 // contain unmarshaler values. 502 InlineUnmarshalers [][]int 503 } 504 505 type fieldInfo struct { 506 Key string 507 Num int 508 OmitEmpty bool 509 Flow bool 510 // Id holds the unique field identifier, so we can cheaply 511 // check for field duplicates without maintaining an extra map. 512 Id int 513 514 // Inline holds the field index if the field is part of an inlined struct. 515 Inline []int 516 } 517 518 var structMap = make(map[reflect.Type]*structInfo) 519 var fieldMapMutex sync.RWMutex 520 var unmarshalerType reflect.Type 521 522 func init() { 523 var v Unmarshaler 524 unmarshalerType = reflect.ValueOf(&v).Elem().Type() 525 } 526 527 func getStructInfo(st reflect.Type) (*structInfo, error) { 528 fieldMapMutex.RLock() 529 sinfo, found := structMap[st] 530 fieldMapMutex.RUnlock() 531 if found { 532 return sinfo, nil 533 } 534 535 n := st.NumField() 536 fieldsMap := make(map[string]fieldInfo) 537 fieldsList := make([]fieldInfo, 0, n) 538 inlineMap := -1 539 inlineUnmarshalers := [][]int(nil) 540 for i := 0; i != n; i++ { 541 field := st.Field(i) 542 if field.PkgPath != "" && !field.Anonymous { 543 continue // Private field 544 } 545 546 info := fieldInfo{Num: i} 547 548 tag := field.Tag.Get("yaml") 549 if tag == "" && strings.Index(string(field.Tag), ":") < 0 { 550 tag = string(field.Tag) 551 } 552 if tag == "-" { 553 continue 554 } 555 556 inline := false 557 fields := strings.Split(tag, ",") 558 if len(fields) > 1 { 559 for _, flag := range fields[1:] { 560 switch flag { 561 case "omitempty": 562 info.OmitEmpty = true 563 case "flow": 564 info.Flow = true 565 case "inline": 566 inline = true 567 default: 568 return nil, errors.New(fmt.Sprintf("unsupported flag %q in tag %q of type %s", flag, tag, st)) 569 } 570 } 571 tag = fields[0] 572 } 573 574 if inline { 575 switch field.Type.Kind() { 576 case reflect.Map: 577 if inlineMap >= 0 { 578 return nil, errors.New("multiple ,inline maps in struct " + st.String()) 579 } 580 if field.Type.Key() != reflect.TypeOf("") { 581 return nil, errors.New("option ,inline needs a map with string keys in struct " + st.String()) 582 } 583 inlineMap = info.Num 584 case reflect.Struct, reflect.Ptr: 585 ftype := field.Type 586 for ftype.Kind() == reflect.Ptr { 587 ftype = ftype.Elem() 588 } 589 if ftype.Kind() != reflect.Struct { 590 return nil, errors.New("option ,inline may only be used on a struct or map field") 591 } 592 if reflect.PtrTo(ftype).Implements(unmarshalerType) { 593 inlineUnmarshalers = append(inlineUnmarshalers, []int{i}) 594 } else { 595 sinfo, err := getStructInfo(ftype) 596 if err != nil { 597 return nil, err 598 } 599 for _, index := range sinfo.InlineUnmarshalers { 600 inlineUnmarshalers = append(inlineUnmarshalers, append([]int{i}, index...)) 601 } 602 for _, finfo := range sinfo.FieldsList { 603 if _, found := fieldsMap[finfo.Key]; found { 604 msg := "duplicated key '" + finfo.Key + "' in struct " + st.String() 605 return nil, errors.New(msg) 606 } 607 if finfo.Inline == nil { 608 finfo.Inline = []int{i, finfo.Num} 609 } else { 610 finfo.Inline = append([]int{i}, finfo.Inline...) 611 } 612 finfo.Id = len(fieldsList) 613 fieldsMap[finfo.Key] = finfo 614 fieldsList = append(fieldsList, finfo) 615 } 616 } 617 default: 618 return nil, errors.New("option ,inline may only be used on a struct or map field") 619 } 620 continue 621 } 622 623 if tag != "" { 624 info.Key = tag 625 } else { 626 info.Key = strings.ToLower(field.Name) 627 } 628 629 if _, found = fieldsMap[info.Key]; found { 630 msg := "duplicated key '" + info.Key + "' in struct " + st.String() 631 return nil, errors.New(msg) 632 } 633 634 info.Id = len(fieldsList) 635 fieldsList = append(fieldsList, info) 636 fieldsMap[info.Key] = info 637 } 638 639 sinfo = &structInfo{ 640 FieldsMap: fieldsMap, 641 FieldsList: fieldsList, 642 InlineMap: inlineMap, 643 InlineUnmarshalers: inlineUnmarshalers, 644 } 645 646 fieldMapMutex.Lock() 647 structMap[st] = sinfo 648 fieldMapMutex.Unlock() 649 return sinfo, nil 650 } 651 652 // IsZeroer is used to check whether an object is zero to 653 // determine whether it should be omitted when marshaling 654 // with the omitempty flag. One notable implementation 655 // is time.Time. 656 type IsZeroer interface { 657 IsZero() bool 658 } 659 660 func isZero(v reflect.Value) bool { 661 kind := v.Kind() 662 if z, ok := v.Interface().(IsZeroer); ok { 663 if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() { 664 return true 665 } 666 return z.IsZero() 667 } 668 switch kind { 669 case reflect.String: 670 return len(v.String()) == 0 671 case reflect.Interface, reflect.Ptr: 672 return v.IsNil() 673 case reflect.Slice: 674 return v.Len() == 0 675 case reflect.Map: 676 return v.Len() == 0 677 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 678 return v.Int() == 0 679 case reflect.Float32, reflect.Float64: 680 return v.Float() == 0 681 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 682 return v.Uint() == 0 683 case reflect.Bool: 684 return !v.Bool() 685 case reflect.Struct: 686 vt := v.Type() 687 for i := v.NumField() - 1; i >= 0; i-- { 688 if vt.Field(i).PkgPath != "" { 689 continue // Private field 690 } 691 if !isZero(v.Field(i)) { 692 return false 693 } 694 } 695 return true 696 } 697 return false 698 }