get.porter.sh/porter@v1.3.0/pkg/yaml/map.go (about) 1 // Copyright (c) 2015-2016 Michael Persson 2 // Copyright (c) 2012–2015 Elasticsearch <http://www.elastic.co> 3 // 4 // Originally distributed as part of "beats" repository (https://github.com/elastic/beats). 5 // Modified specifically for "iodatafmt" package. 6 // Modified to make UnmarshalYAML reusable by other types, turn null keys to "null" and be compatible with gopkg.in/yaml.v3 7 // 8 // Distributed underneath "Apache License, Version 2.0" which is compatible with the LICENSE for this package. 9 // see https://github.com/go-yaml/yaml/issues/139#issuecomment-220072190 10 11 package yaml 12 13 import ( 14 "fmt" 15 ) 16 17 // UnmarshalMap allows unmarshaling into types that are safe to then be marshaled to json. 18 // By default yaml serializer converts these to map[interface{}]interface which cannot be serialised as json 19 // see https://github.com/go-yaml/yaml/issues/139 20 // This is still required even with v3 because if any key isn't parsed as a string, e.g. you have a key named 1 or 2, then the bug is still triggered. 21 func UnmarshalMap(unmarshal func(interface{}) error) (map[string]interface{}, error) { 22 var raw map[string]interface{} 23 err := unmarshal(&raw) 24 if err != nil { 25 return nil, err 26 } 27 28 for k, v := range raw { 29 raw[stringKey(k)] = cleanupMapValue(v) 30 } 31 32 return raw, nil 33 } 34 35 func cleanupInterfaceArray(in []interface{}) []interface{} { 36 res := make([]interface{}, len(in)) 37 for i, v := range in { 38 res[i] = cleanupMapValue(v) 39 } 40 return res 41 } 42 43 func cleanupInterfaceMap(in map[interface{}]interface{}) map[string]interface{} { 44 res := make(map[string]interface{}) 45 for k, v := range in { 46 res[stringKey(k)] = cleanupMapValue(v) 47 } 48 return res 49 } 50 51 func cleanupStringMap(in map[string]interface{}) map[string]interface{} { 52 res := make(map[string]interface{}) 53 for k, v := range in { 54 res[stringKey(k)] = cleanupMapValue(v) 55 } 56 return res 57 } 58 59 func cleanupMapValue(v interface{}) interface{} { 60 switch v := v.(type) { 61 case []interface{}: 62 return cleanupInterfaceArray(v) 63 case map[interface{}]interface{}: 64 return cleanupInterfaceMap(v) 65 case map[string]interface{}: 66 return cleanupStringMap(v) 67 default: 68 return v 69 } 70 } 71 72 func stringKey(k interface{}) string { 73 switch k { 74 case nil: 75 return "null" 76 default: 77 return fmt.Sprintf("%v", k) 78 } 79 }