yaml.go 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. // Package yaml implements YAML support for the Go language.
  2. //
  3. // Source code and other details for the project are available at GitHub:
  4. //
  5. // https://github.com/go-yaml/yaml
  6. //
  7. package yaml
  8. import (
  9. "errors"
  10. "fmt"
  11. "reflect"
  12. "runtime"
  13. "strings"
  14. "sync"
  15. )
  16. func handleErr(err *error) {
  17. if r := recover(); r != nil {
  18. if _, ok := r.(runtime.Error); ok {
  19. panic(r)
  20. } else if _, ok := r.(*reflect.ValueError); ok {
  21. panic(r)
  22. } else if _, ok := r.(externalPanic); ok {
  23. panic(r)
  24. } else if s, ok := r.(string); ok {
  25. *err = errors.New("YAML error: " + s)
  26. } else if e, ok := r.(error); ok {
  27. *err = e
  28. } else {
  29. panic(r)
  30. }
  31. }
  32. }
  33. // The Setter interface may be implemented by types to do their own custom
  34. // unmarshalling of YAML values, rather than being implicitly assigned by
  35. // the yaml package machinery. If setting the value works, the method should
  36. // return true. If it returns false, the value is considered unsupported
  37. // and is omitted from maps and slices.
  38. type Setter interface {
  39. SetYAML(tag string, value interface{}) bool
  40. }
  41. // The Setter interface is implemented by types to do their own custom
  42. // marshalling into a YAML tag and value.
  43. type Getter interface {
  44. GetYAML() (tag string, value interface{})
  45. }
  46. // Unmarshal decodes the first document found within the in byte slice
  47. // and assigns decoded values into the out value.
  48. //
  49. // Maps and pointers (to a struct, string, int, etc) are accepted as out
  50. // values. If an internal pointer within a struct is not initialized,
  51. // the yaml package will initialize it if necessary for unmarshalling
  52. // the provided data. The out parameter must not be nil.
  53. //
  54. // The type of the decoded values and the type of out will be considered,
  55. // and Unmarshal will do the best possible job to unmarshal values
  56. // appropriately. It is NOT considered an error, though, to skip values
  57. // because they are not available in the decoded YAML, or if they are not
  58. // compatible with the out value. To ensure something was properly
  59. // unmarshaled use a map or compare against the previous value for the
  60. // field (usually the zero value).
  61. //
  62. // Struct fields are only unmarshalled if they are exported (have an
  63. // upper case first letter), and are unmarshalled using the field name
  64. // lowercased as the default key. Custom keys may be defined via the
  65. // "yaml" name in the field tag: the content preceding the first comma
  66. // is used as the key, and the following comma-separated options are
  67. // used to tweak the marshalling process (see Marshal).
  68. // Conflicting names result in a runtime error.
  69. //
  70. // For example:
  71. //
  72. // type T struct {
  73. // F int `yaml:"a,omitempty"`
  74. // B int
  75. // }
  76. // var T t
  77. // yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
  78. //
  79. // See the documentation of Marshal for the format of tags and a list of
  80. // supported tag options.
  81. //
  82. func Unmarshal(in []byte, out interface{}) (err error) {
  83. defer handleErr(&err)
  84. d := newDecoder()
  85. p := newParser(in)
  86. defer p.destroy()
  87. node := p.parse()
  88. if node != nil {
  89. d.unmarshal(node, reflect.ValueOf(out))
  90. }
  91. return nil
  92. }
  93. // Marshal serializes the value provided into a YAML document. The structure
  94. // of the generated document will reflect the structure of the value itself.
  95. // Maps and pointers (to struct, string, int, etc) are accepted as the in value.
  96. //
  97. // Struct fields are only unmarshalled if they are exported (have an upper case
  98. // first letter), and are unmarshalled using the field name lowercased as the
  99. // default key. Custom keys may be defined via the "yaml" name in the field
  100. // tag: the content preceding the first comma is used as the key, and the
  101. // following comma-separated options are used to tweak the marshalling process.
  102. // Conflicting names result in a runtime error.
  103. //
  104. // The field tag format accepted is:
  105. //
  106. // `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
  107. //
  108. // The following flags are currently supported:
  109. //
  110. // omitempty Only include the field if it's not set to the zero
  111. // value for the type or to empty slices or maps.
  112. // Does not apply to zero valued structs.
  113. //
  114. // flow Marshal using a flow style (useful for structs,
  115. // sequences and maps.
  116. //
  117. // inline Inline the struct it's applied to, so its fields
  118. // are processed as if they were part of the outer
  119. // struct.
  120. //
  121. // In addition, if the key is "-", the field is ignored.
  122. //
  123. // For example:
  124. //
  125. // type T struct {
  126. // F int "a,omitempty"
  127. // B int
  128. // }
  129. // yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
  130. // yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n"
  131. //
  132. func Marshal(in interface{}) (out []byte, err error) {
  133. defer handleErr(&err)
  134. e := newEncoder()
  135. defer e.destroy()
  136. e.marshal("", reflect.ValueOf(in))
  137. e.finish()
  138. out = e.out
  139. return
  140. }
  141. // --------------------------------------------------------------------------
  142. // Maintain a mapping of keys to structure field indexes
  143. // The code in this section was copied from mgo/bson.
  144. // structInfo holds details for the serialization of fields of
  145. // a given struct.
  146. type structInfo struct {
  147. FieldsMap map[string]fieldInfo
  148. FieldsList []fieldInfo
  149. // InlineMap is the number of the field in the struct that
  150. // contains an ,inline map, or -1 if there's none.
  151. InlineMap int
  152. }
  153. type fieldInfo struct {
  154. Key string
  155. Num int
  156. OmitEmpty bool
  157. Flow bool
  158. // Inline holds the field index if the field is part of an inlined struct.
  159. Inline []int
  160. }
  161. var structMap = make(map[reflect.Type]*structInfo)
  162. var fieldMapMutex sync.RWMutex
  163. type externalPanic string
  164. func (e externalPanic) String() string {
  165. return string(e)
  166. }
  167. func getStructInfo(st reflect.Type) (*structInfo, error) {
  168. fieldMapMutex.RLock()
  169. sinfo, found := structMap[st]
  170. fieldMapMutex.RUnlock()
  171. if found {
  172. return sinfo, nil
  173. }
  174. n := st.NumField()
  175. fieldsMap := make(map[string]fieldInfo)
  176. fieldsList := make([]fieldInfo, 0, n)
  177. inlineMap := -1
  178. for i := 0; i != n; i++ {
  179. field := st.Field(i)
  180. if field.PkgPath != "" {
  181. continue // Private field
  182. }
  183. info := fieldInfo{Num: i}
  184. tag := field.Tag.Get("yaml")
  185. if tag == "" && strings.Index(string(field.Tag), ":") < 0 {
  186. tag = string(field.Tag)
  187. }
  188. if tag == "-" {
  189. continue
  190. }
  191. inline := false
  192. fields := strings.Split(tag, ",")
  193. if len(fields) > 1 {
  194. for _, flag := range fields[1:] {
  195. switch flag {
  196. case "omitempty":
  197. info.OmitEmpty = true
  198. case "flow":
  199. info.Flow = true
  200. case "inline":
  201. inline = true
  202. default:
  203. msg := fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st)
  204. panic(externalPanic(msg))
  205. }
  206. }
  207. tag = fields[0]
  208. }
  209. if inline {
  210. switch field.Type.Kind() {
  211. //case reflect.Map:
  212. // if inlineMap >= 0 {
  213. // return nil, errors.New("Multiple ,inline maps in struct " + st.String())
  214. // }
  215. // if field.Type.Key() != reflect.TypeOf("") {
  216. // return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String())
  217. // }
  218. // inlineMap = info.Num
  219. case reflect.Struct:
  220. sinfo, err := getStructInfo(field.Type)
  221. if err != nil {
  222. return nil, err
  223. }
  224. for _, finfo := range sinfo.FieldsList {
  225. if _, found := fieldsMap[finfo.Key]; found {
  226. msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String()
  227. return nil, errors.New(msg)
  228. }
  229. if finfo.Inline == nil {
  230. finfo.Inline = []int{i, finfo.Num}
  231. } else {
  232. finfo.Inline = append([]int{i}, finfo.Inline...)
  233. }
  234. fieldsMap[finfo.Key] = finfo
  235. fieldsList = append(fieldsList, finfo)
  236. }
  237. default:
  238. //panic("Option ,inline needs a struct value or map field")
  239. panic("Option ,inline needs a struct value field")
  240. }
  241. continue
  242. }
  243. if tag != "" {
  244. info.Key = tag
  245. } else {
  246. info.Key = strings.ToLower(field.Name)
  247. }
  248. if _, found = fieldsMap[info.Key]; found {
  249. msg := "Duplicated key '" + info.Key + "' in struct " + st.String()
  250. return nil, errors.New(msg)
  251. }
  252. fieldsList = append(fieldsList, info)
  253. fieldsMap[info.Key] = info
  254. }
  255. sinfo = &structInfo{fieldsMap, fieldsList, inlineMap}
  256. fieldMapMutex.Lock()
  257. structMap[st] = sinfo
  258. fieldMapMutex.Unlock()
  259. return sinfo, nil
  260. }
  261. func isZero(v reflect.Value) bool {
  262. switch v.Kind() {
  263. case reflect.String:
  264. return len(v.String()) == 0
  265. case reflect.Interface, reflect.Ptr:
  266. return v.IsNil()
  267. case reflect.Slice:
  268. return v.Len() == 0
  269. case reflect.Map:
  270. return v.Len() == 0
  271. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  272. return v.Int() == 0
  273. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  274. return v.Uint() == 0
  275. case reflect.Bool:
  276. return !v.Bool()
  277. }
  278. return false
  279. }