github.com/flatt-online-training/libcompose@v0.4.0/yaml/types_yaml.go (about) 1 package yaml 2 3 import ( 4 "errors" 5 "fmt" 6 "strconv" 7 "strings" 8 9 "github.com/docker/docker/api/types/strslice" 10 "github.com/docker/go-units" 11 ) 12 13 // StringorInt represents a string or an integer. 14 type StringorInt int64 15 16 // UnmarshalYAML implements the Unmarshaller interface. 17 func (s *StringorInt) UnmarshalYAML(unmarshal func(interface{}) error) error { 18 var intType int64 19 if err := unmarshal(&intType); err == nil { 20 *s = StringorInt(intType) 21 return nil 22 } 23 24 var stringType string 25 if err := unmarshal(&stringType); err == nil { 26 intType, err := strconv.ParseInt(stringType, 10, 64) 27 28 if err != nil { 29 return err 30 } 31 *s = StringorInt(intType) 32 return nil 33 } 34 35 return errors.New("Failed to unmarshal StringorInt") 36 } 37 38 // MemStringorInt represents a string or an integer 39 // the String supports notations like 10m for then Megabyte of memory 40 type MemStringorInt int64 41 42 // UnmarshalYAML implements the Unmarshaller interface. 43 func (s *MemStringorInt) UnmarshalYAML(unmarshal func(interface{}) error) error { 44 var intType int64 45 if err := unmarshal(&intType); err == nil { 46 *s = MemStringorInt(intType) 47 return nil 48 } 49 50 var stringType string 51 if err := unmarshal(&stringType); err == nil { 52 intType, err := units.RAMInBytes(stringType) 53 54 if err != nil { 55 return err 56 } 57 *s = MemStringorInt(intType) 58 return nil 59 } 60 61 return errors.New("Failed to unmarshal MemStringorInt") 62 } 63 64 // Stringorslice represents 65 // Using engine-api Strslice and augment it with YAML marshalling stuff. a string or an array of strings. 66 type Stringorslice strslice.StrSlice 67 68 // UnmarshalYAML implements the Unmarshaller interface. 69 func (s *Stringorslice) UnmarshalYAML(unmarshal func(interface{}) error) error { 70 var stringType string 71 if err := unmarshal(&stringType); err == nil { 72 *s = []string{stringType} 73 return nil 74 } 75 76 var sliceType []interface{} 77 if err := unmarshal(&sliceType); err == nil { 78 parts, err := toStrings(sliceType) 79 if err != nil { 80 return err 81 } 82 *s = parts 83 return nil 84 } 85 86 return errors.New("Failed to unmarshal Stringorslice") 87 } 88 89 // SliceorMap represents a slice or a map of strings. 90 type SliceorMap map[string]string 91 92 // UnmarshalYAML implements the Unmarshaller interface. 93 func (s *SliceorMap) UnmarshalYAML(unmarshal func(interface{}) error) error { 94 95 var sliceType []interface{} 96 if err := unmarshal(&sliceType); err == nil { 97 parts := map[string]string{} 98 for _, s := range sliceType { 99 if str, ok := s.(string); ok { 100 str := strings.TrimSpace(str) 101 keyValueSlice := strings.SplitN(str, "=", 2) 102 103 key := keyValueSlice[0] 104 val := "" 105 if len(keyValueSlice) == 2 { 106 val = keyValueSlice[1] 107 } 108 parts[key] = val 109 } else { 110 return fmt.Errorf("Cannot unmarshal '%v' of type %T into a string value", s, s) 111 } 112 } 113 *s = parts 114 return nil 115 } 116 117 var mapType map[interface{}]interface{} 118 if err := unmarshal(&mapType); err == nil { 119 parts := map[string]string{} 120 for k, v := range mapType { 121 if sk, ok := k.(string); ok { 122 if sv, ok := v.(string); ok { 123 parts[sk] = sv 124 } else { 125 return fmt.Errorf("Cannot unmarshal '%v' of type %T into a string value", v, v) 126 } 127 } else { 128 return fmt.Errorf("Cannot unmarshal '%v' of type %T into a string value", k, k) 129 } 130 } 131 *s = parts 132 return nil 133 } 134 135 return errors.New("Failed to unmarshal SliceorMap") 136 } 137 138 // MaporEqualSlice represents a slice of strings that gets unmarshal from a 139 // YAML map into 'key=value' string. 140 type MaporEqualSlice []string 141 142 // UnmarshalYAML implements the Unmarshaller interface. 143 func (s *MaporEqualSlice) UnmarshalYAML(unmarshal func(interface{}) error) error { 144 parts, err := unmarshalToStringOrSepMapParts(unmarshal, "=") 145 if err != nil { 146 return err 147 } 148 *s = parts 149 return nil 150 } 151 152 // ToMap returns the list of string as a map splitting using = the key=value 153 func (s *MaporEqualSlice) ToMap() map[string]string { 154 return toMap(*s, "=") 155 } 156 157 // MaporColonSlice represents a slice of strings that gets unmarshal from a 158 // YAML map into 'key:value' string. 159 type MaporColonSlice []string 160 161 // UnmarshalYAML implements the Unmarshaller interface. 162 func (s *MaporColonSlice) UnmarshalYAML(unmarshal func(interface{}) error) error { 163 parts, err := unmarshalToStringOrSepMapParts(unmarshal, ":") 164 if err != nil { 165 return err 166 } 167 *s = parts 168 return nil 169 } 170 171 // ToMap returns the list of string as a map splitting using = the key=value 172 func (s *MaporColonSlice) ToMap() map[string]string { 173 return toMap(*s, ":") 174 } 175 176 // MaporSpaceSlice represents a slice of strings that gets unmarshal from a 177 // YAML map into 'key value' string. 178 type MaporSpaceSlice []string 179 180 // UnmarshalYAML implements the Unmarshaller interface. 181 func (s *MaporSpaceSlice) UnmarshalYAML(unmarshal func(interface{}) error) error { 182 parts, err := unmarshalToStringOrSepMapParts(unmarshal, " ") 183 if err != nil { 184 return err 185 } 186 *s = parts 187 return nil 188 } 189 190 // ToMap returns the list of string as a map splitting using = the key=value 191 func (s *MaporSpaceSlice) ToMap() map[string]string { 192 return toMap(*s, " ") 193 } 194 195 func unmarshalToStringOrSepMapParts(unmarshal func(interface{}) error, key string) ([]string, error) { 196 var sliceType []interface{} 197 if err := unmarshal(&sliceType); err == nil { 198 return toStrings(sliceType) 199 } 200 var mapType map[interface{}]interface{} 201 if err := unmarshal(&mapType); err == nil { 202 return toSepMapParts(mapType, key) 203 } 204 return nil, errors.New("Failed to unmarshal MaporSlice") 205 } 206 207 func toSepMapParts(value map[interface{}]interface{}, sep string) ([]string, error) { 208 if len(value) == 0 { 209 return nil, nil 210 } 211 parts := make([]string, 0, len(value)) 212 for k, v := range value { 213 if sk, ok := k.(string); ok { 214 if sv, ok := v.(string); ok { 215 parts = append(parts, sk+sep+sv) 216 } else if sv, ok := v.(int); ok { 217 parts = append(parts, sk+sep+strconv.Itoa(sv)) 218 } else if sv, ok := v.(int64); ok { 219 parts = append(parts, sk+sep+strconv.FormatInt(sv, 10)) 220 } else if v == nil { 221 parts = append(parts, sk) 222 } else { 223 return nil, fmt.Errorf("Cannot unmarshal '%v' of type %T into a string value", v, v) 224 } 225 } else { 226 return nil, fmt.Errorf("Cannot unmarshal '%v' of type %T into a string value", k, k) 227 } 228 } 229 return parts, nil 230 } 231 232 func toStrings(s []interface{}) ([]string, error) { 233 if len(s) == 0 { 234 return nil, nil 235 } 236 r := make([]string, len(s)) 237 for k, v := range s { 238 if sv, ok := v.(string); ok { 239 r[k] = sv 240 } else { 241 return nil, fmt.Errorf("Cannot unmarshal '%v' of type %T into a string value", v, v) 242 } 243 } 244 return r, nil 245 } 246 247 func toMap(s []string, sep string) map[string]string { 248 m := map[string]string{} 249 for _, v := range s { 250 values := strings.Split(v, sep) 251 m[values[0]] = values[1] 252 } 253 return m 254 }