github.com/ssube/gitlab-ci-multi-runner@v1.2.1-0.20160607142738-b8d1285632e6/Godeps/_workspace/src/gopkg.in/yaml.v1/yaml.go (about)

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