本站源代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

467 lines
13KB

  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. "io"
  12. "reflect"
  13. "strings"
  14. "sync"
  15. )
  16. // MapSlice encodes and decodes as a YAML map.
  17. // The order of keys is preserved when encoding and decoding.
  18. type MapSlice []MapItem
  19. // MapItem is an item in a MapSlice.
  20. type MapItem struct {
  21. Key, Value interface{}
  22. }
  23. // The Unmarshaler interface may be implemented by types to customize their
  24. // behavior when being unmarshaled from a YAML document. The UnmarshalYAML
  25. // method receives a function that may be called to unmarshal the original
  26. // YAML value into a field or variable. It is safe to call the unmarshal
  27. // function parameter more than once if necessary.
  28. type Unmarshaler interface {
  29. UnmarshalYAML(unmarshal func(interface{}) error) error
  30. }
  31. // The Marshaler interface may be implemented by types to customize their
  32. // behavior when being marshaled into a YAML document. The returned value
  33. // is marshaled in place of the original value implementing Marshaler.
  34. //
  35. // If an error is returned by MarshalYAML, the marshaling procedure stops
  36. // and returns with the provided error.
  37. type Marshaler interface {
  38. MarshalYAML() (interface{}, error)
  39. }
  40. // Unmarshal decodes the first document found within the in byte slice
  41. // and assigns decoded values into the out value.
  42. //
  43. // Maps and pointers (to a struct, string, int, etc) are accepted as out
  44. // values. If an internal pointer within a struct is not initialized,
  45. // the yaml package will initialize it if necessary for unmarshalling
  46. // the provided data. The out parameter must not be nil.
  47. //
  48. // The type of the decoded values should be compatible with the respective
  49. // values in out. If one or more values cannot be decoded due to a type
  50. // mismatches, decoding continues partially until the end of the YAML
  51. // content, and a *yaml.TypeError is returned with details for all
  52. // missed values.
  53. //
  54. // Struct fields are only unmarshalled if they are exported (have an
  55. // upper case first letter), and are unmarshalled using the field name
  56. // lowercased as the default key. Custom keys may be defined via the
  57. // "yaml" name in the field tag: the content preceding the first comma
  58. // is used as the key, and the following comma-separated options are
  59. // used to tweak the marshalling process (see Marshal).
  60. // Conflicting names result in a runtime error.
  61. //
  62. // For example:
  63. //
  64. // type T struct {
  65. // F int `yaml:"a,omitempty"`
  66. // B int
  67. // }
  68. // var t T
  69. // yaml.Unmarshal([]byte("a: 1\nb: 2"), &t)
  70. //
  71. // See the documentation of Marshal for the format of tags and a list of
  72. // supported tag options.
  73. //
  74. func Unmarshal(in []byte, out interface{}) (err error) {
  75. return unmarshal(in, out, false)
  76. }
  77. // UnmarshalStrict is like Unmarshal except that any fields that are found
  78. // in the data that do not have corresponding struct members, or mapping
  79. // keys that are duplicates, will result in
  80. // an error.
  81. func UnmarshalStrict(in []byte, out interface{}) (err error) {
  82. return unmarshal(in, out, true)
  83. }
  84. // A Decorder reads and decodes YAML values from an input stream.
  85. type Decoder struct {
  86. strict bool
  87. parser *parser
  88. }
  89. // NewDecoder returns a new decoder that reads from r.
  90. //
  91. // The decoder introduces its own buffering and may read
  92. // data from r beyond the YAML values requested.
  93. func NewDecoder(r io.Reader) *Decoder {
  94. return &Decoder{
  95. parser: newParserFromReader(r),
  96. }
  97. }
  98. // SetStrict sets whether strict decoding behaviour is enabled when
  99. // decoding items in the data (see UnmarshalStrict). By default, decoding is not strict.
  100. func (dec *Decoder) SetStrict(strict bool) {
  101. dec.strict = strict
  102. }
  103. // Decode reads the next YAML-encoded value from its input
  104. // and stores it in the value pointed to by v.
  105. //
  106. // See the documentation for Unmarshal for details about the
  107. // conversion of YAML into a Go value.
  108. func (dec *Decoder) Decode(v interface{}) (err error) {
  109. d := newDecoder(dec.strict)
  110. defer handleErr(&err)
  111. node := dec.parser.parse()
  112. if node == nil {
  113. return io.EOF
  114. }
  115. out := reflect.ValueOf(v)
  116. if out.Kind() == reflect.Ptr && !out.IsNil() {
  117. out = out.Elem()
  118. }
  119. d.unmarshal(node, out)
  120. if len(d.terrors) > 0 {
  121. return &TypeError{d.terrors}
  122. }
  123. return nil
  124. }
  125. func unmarshal(in []byte, out interface{}, strict bool) (err error) {
  126. defer handleErr(&err)
  127. d := newDecoder(strict)
  128. p := newParser(in)
  129. defer p.destroy()
  130. node := p.parse()
  131. if node != nil {
  132. v := reflect.ValueOf(out)
  133. if v.Kind() == reflect.Ptr && !v.IsNil() {
  134. v = v.Elem()
  135. }
  136. d.unmarshal(node, v)
  137. }
  138. if len(d.terrors) > 0 {
  139. return &TypeError{d.terrors}
  140. }
  141. return nil
  142. }
  143. // Marshal serializes the value provided into a YAML document. The structure
  144. // of the generated document will reflect the structure of the value itself.
  145. // Maps and pointers (to struct, string, int, etc) are accepted as the in value.
  146. //
  147. // Struct fields are only marshalled if they are exported (have an upper case
  148. // first letter), and are marshalled using the field name lowercased as the
  149. // default key. Custom keys may be defined via the "yaml" name in the field
  150. // tag: the content preceding the first comma is used as the key, and the
  151. // following comma-separated options are used to tweak the marshalling process.
  152. // Conflicting names result in a runtime error.
  153. //
  154. // The field tag format accepted is:
  155. //
  156. // `(...) yaml:"[<key>][,<flag1>[,<flag2>]]" (...)`
  157. //
  158. // The following flags are currently supported:
  159. //
  160. // omitempty Only include the field if it's not set to the zero
  161. // value for the type or to empty slices or maps.
  162. // Zero valued structs will be omitted if all their public
  163. // fields are zero, unless they implement an IsZero
  164. // method (see the IsZeroer interface type), in which
  165. // case the field will be included if that method returns true.
  166. //
  167. // flow Marshal using a flow style (useful for structs,
  168. // sequences and maps).
  169. //
  170. // inline Inline the field, which must be a struct or a map,
  171. // causing all of its fields or keys to be processed as if
  172. // they were part of the outer struct. For maps, keys must
  173. // not conflict with the yaml keys of other struct fields.
  174. //
  175. // In addition, if the key is "-", the field is ignored.
  176. //
  177. // For example:
  178. //
  179. // type T struct {
  180. // F int `yaml:"a,omitempty"`
  181. // B int
  182. // }
  183. // yaml.Marshal(&T{B: 2}) // Returns "b: 2\n"
  184. // yaml.Marshal(&T{F: 1}} // Returns "a: 1\nb: 0\n"
  185. //
  186. func Marshal(in interface{}) (out []byte, err error) {
  187. defer handleErr(&err)
  188. e := newEncoder()
  189. defer e.destroy()
  190. e.marshalDoc("", reflect.ValueOf(in))
  191. e.finish()
  192. out = e.out
  193. return
  194. }
  195. // An Encoder writes YAML values to an output stream.
  196. type Encoder struct {
  197. encoder *encoder
  198. }
  199. // NewEncoder returns a new encoder that writes to w.
  200. // The Encoder should be closed after use to flush all data
  201. // to w.
  202. func NewEncoder(w io.Writer) *Encoder {
  203. return &Encoder{
  204. encoder: newEncoderWithWriter(w),
  205. }
  206. }
  207. // Encode writes the YAML encoding of v to the stream.
  208. // If multiple items are encoded to the stream, the
  209. // second and subsequent document will be preceded
  210. // with a "---" document separator, but the first will not.
  211. //
  212. // See the documentation for Marshal for details about the conversion of Go
  213. // values to YAML.
  214. func (e *Encoder) Encode(v interface{}) (err error) {
  215. defer handleErr(&err)
  216. e.encoder.marshalDoc("", reflect.ValueOf(v))
  217. return nil
  218. }
  219. // Close closes the encoder by writing any remaining data.
  220. // It does not write a stream terminating string "...".
  221. func (e *Encoder) Close() (err error) {
  222. defer handleErr(&err)
  223. e.encoder.finish()
  224. return nil
  225. }
  226. func handleErr(err *error) {
  227. if v := recover(); v != nil {
  228. if e, ok := v.(yamlError); ok {
  229. *err = e.err
  230. } else {
  231. panic(v)
  232. }
  233. }
  234. }
  235. type yamlError struct {
  236. err error
  237. }
  238. func fail(err error) {
  239. panic(yamlError{err})
  240. }
  241. func failf(format string, args ...interface{}) {
  242. panic(yamlError{fmt.Errorf("yaml: "+format, args...)})
  243. }
  244. // A TypeError is returned by Unmarshal when one or more fields in
  245. // the YAML document cannot be properly decoded into the requested
  246. // types. When this error is returned, the value is still
  247. // unmarshaled partially.
  248. type TypeError struct {
  249. Errors []string
  250. }
  251. func (e *TypeError) Error() string {
  252. return fmt.Sprintf("yaml: unmarshal errors:\n %s", strings.Join(e.Errors, "\n "))
  253. }
  254. // --------------------------------------------------------------------------
  255. // Maintain a mapping of keys to structure field indexes
  256. // The code in this section was copied from mgo/bson.
  257. // structInfo holds details for the serialization of fields of
  258. // a given struct.
  259. type structInfo struct {
  260. FieldsMap map[string]fieldInfo
  261. FieldsList []fieldInfo
  262. // InlineMap is the number of the field in the struct that
  263. // contains an ,inline map, or -1 if there's none.
  264. InlineMap int
  265. }
  266. type fieldInfo struct {
  267. Key string
  268. Num int
  269. OmitEmpty bool
  270. Flow bool
  271. // Id holds the unique field identifier, so we can cheaply
  272. // check for field duplicates without maintaining an extra map.
  273. Id int
  274. // Inline holds the field index if the field is part of an inlined struct.
  275. Inline []int
  276. }
  277. var structMap = make(map[reflect.Type]*structInfo)
  278. var fieldMapMutex sync.RWMutex
  279. func getStructInfo(st reflect.Type) (*structInfo, error) {
  280. fieldMapMutex.RLock()
  281. sinfo, found := structMap[st]
  282. fieldMapMutex.RUnlock()
  283. if found {
  284. return sinfo, nil
  285. }
  286. n := st.NumField()
  287. fieldsMap := make(map[string]fieldInfo)
  288. fieldsList := make([]fieldInfo, 0, n)
  289. inlineMap := -1
  290. for i := 0; i != n; i++ {
  291. field := st.Field(i)
  292. if field.PkgPath != "" && !field.Anonymous {
  293. continue // Private field
  294. }
  295. info := fieldInfo{Num: i}
  296. tag := field.Tag.Get("yaml")
  297. if tag == "" && strings.Index(string(field.Tag), ":") < 0 {
  298. tag = string(field.Tag)
  299. }
  300. if tag == "-" {
  301. continue
  302. }
  303. inline := false
  304. fields := strings.Split(tag, ",")
  305. if len(fields) > 1 {
  306. for _, flag := range fields[1:] {
  307. switch flag {
  308. case "omitempty":
  309. info.OmitEmpty = true
  310. case "flow":
  311. info.Flow = true
  312. case "inline":
  313. inline = true
  314. default:
  315. return nil, errors.New(fmt.Sprintf("Unsupported flag %q in tag %q of type %s", flag, tag, st))
  316. }
  317. }
  318. tag = fields[0]
  319. }
  320. if inline {
  321. switch field.Type.Kind() {
  322. case reflect.Map:
  323. if inlineMap >= 0 {
  324. return nil, errors.New("Multiple ,inline maps in struct " + st.String())
  325. }
  326. if field.Type.Key() != reflect.TypeOf("") {
  327. return nil, errors.New("Option ,inline needs a map with string keys in struct " + st.String())
  328. }
  329. inlineMap = info.Num
  330. case reflect.Struct:
  331. sinfo, err := getStructInfo(field.Type)
  332. if err != nil {
  333. return nil, err
  334. }
  335. for _, finfo := range sinfo.FieldsList {
  336. if _, found := fieldsMap[finfo.Key]; found {
  337. msg := "Duplicated key '" + finfo.Key + "' in struct " + st.String()
  338. return nil, errors.New(msg)
  339. }
  340. if finfo.Inline == nil {
  341. finfo.Inline = []int{i, finfo.Num}
  342. } else {
  343. finfo.Inline = append([]int{i}, finfo.Inline...)
  344. }
  345. finfo.Id = len(fieldsList)
  346. fieldsMap[finfo.Key] = finfo
  347. fieldsList = append(fieldsList, finfo)
  348. }
  349. default:
  350. //return nil, errors.New("Option ,inline needs a struct value or map field")
  351. return nil, errors.New("Option ,inline needs a struct value field")
  352. }
  353. continue
  354. }
  355. if tag != "" {
  356. info.Key = tag
  357. } else {
  358. info.Key = strings.ToLower(field.Name)
  359. }
  360. if _, found = fieldsMap[info.Key]; found {
  361. msg := "Duplicated key '" + info.Key + "' in struct " + st.String()
  362. return nil, errors.New(msg)
  363. }
  364. info.Id = len(fieldsList)
  365. fieldsList = append(fieldsList, info)
  366. fieldsMap[info.Key] = info
  367. }
  368. sinfo = &structInfo{
  369. FieldsMap: fieldsMap,
  370. FieldsList: fieldsList,
  371. InlineMap: inlineMap,
  372. }
  373. fieldMapMutex.Lock()
  374. structMap[st] = sinfo
  375. fieldMapMutex.Unlock()
  376. return sinfo, nil
  377. }
  378. // IsZeroer is used to check whether an object is zero to
  379. // determine whether it should be omitted when marshaling
  380. // with the omitempty flag. One notable implementation
  381. // is time.Time.
  382. type IsZeroer interface {
  383. IsZero() bool
  384. }
  385. func isZero(v reflect.Value) bool {
  386. kind := v.Kind()
  387. if z, ok := v.Interface().(IsZeroer); ok {
  388. if (kind == reflect.Ptr || kind == reflect.Interface) && v.IsNil() {
  389. return true
  390. }
  391. return z.IsZero()
  392. }
  393. switch kind {
  394. case reflect.String:
  395. return len(v.String()) == 0
  396. case reflect.Interface, reflect.Ptr:
  397. return v.IsNil()
  398. case reflect.Slice:
  399. return v.Len() == 0
  400. case reflect.Map:
  401. return v.Len() == 0
  402. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  403. return v.Int() == 0
  404. case reflect.Float32, reflect.Float64:
  405. return v.Float() == 0
  406. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  407. return v.Uint() == 0
  408. case reflect.Bool:
  409. return !v.Bool()
  410. case reflect.Struct:
  411. vt := v.Type()
  412. for i := v.NumField() - 1; i >= 0; i-- {
  413. if vt.Field(i).PkgPath != "" {
  414. continue // Private field
  415. }
  416. if !isZero(v.Field(i)) {
  417. return false
  418. }
  419. }
  420. return true
  421. }
  422. return false
  423. }
上海开阖软件有限公司 沪ICP备12045867号-1