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 }