github.com/docker/app@v0.9.1-beta3.0.20210611140623-a48f773ab002/types/parameters/load.go (about) 1 package parameters 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "io/ioutil" 8 9 "github.com/docker/app/internal/yaml" 10 "github.com/pkg/errors" 11 ) 12 13 // Load loads the given data in parameters 14 func Load(data []byte, ops ...func(*Options)) (Parameters, error) { 15 options := &Options{} 16 for _, op := range ops { 17 op(options) 18 } 19 20 r := bytes.NewReader(data) 21 s := make(map[interface{}]interface{}) 22 decoder := yaml.NewDecoder(r) 23 if err := decoder.Decode(&s); err != nil { 24 if err == io.EOF { 25 return Parameters{}, nil 26 } 27 return nil, errors.Wrap(err, "failed to read parameters") 28 } 29 converted, err := convertToStringKeysRecursive(s, "") 30 if err != nil { 31 return nil, err 32 } 33 params := converted.(map[string]interface{}) 34 if options.prefix != "" { 35 params = map[string]interface{}{ 36 options.prefix: params, 37 } 38 } 39 // Make sure params are always loaded expanded 40 expandedParams, err := FromFlatten(flatten(params)) 41 if err != nil { 42 return nil, err 43 } 44 return expandedParams, nil 45 } 46 47 // LoadMultiple loads multiple data in parameters 48 func LoadMultiple(datas [][]byte, ops ...func(*Options)) (Parameters, error) { 49 m := Parameters(map[string]interface{}{}) 50 for _, data := range datas { 51 parameters, err := Load(data, ops...) 52 if err != nil { 53 return nil, err 54 } 55 m, err = Merge(m, parameters) 56 if err != nil { 57 return nil, err 58 } 59 } 60 return m, nil 61 } 62 63 // LoadFile loads a file (path) in parameters (i.e. flatten map) 64 func LoadFile(path string, ops ...func(*Options)) (Parameters, error) { 65 data, err := ioutil.ReadFile(path) 66 if err != nil { 67 return nil, err 68 } 69 return Load(data, ops...) 70 } 71 72 // LoadFiles loads multiple path in parameters, merging them. 73 func LoadFiles(paths []string, ops ...func(*Options)) (Parameters, error) { 74 m := Parameters(map[string]interface{}{}) 75 for _, path := range paths { 76 parameters, err := LoadFile(path, ops...) 77 if err != nil { 78 return nil, err 79 } 80 m, err = Merge(m, parameters) 81 if err != nil { 82 return nil, err 83 } 84 } 85 return m, nil 86 } 87 88 // from cli 89 func convertToStringKeysRecursive(value interface{}, keyPrefix string) (interface{}, error) { 90 if mapping, ok := value.(map[interface{}]interface{}); ok { 91 dict := make(map[string]interface{}) 92 for key, entry := range mapping { 93 str, ok := key.(string) 94 if !ok { 95 return nil, formatInvalidKeyError(keyPrefix, key) 96 } 97 var newKeyPrefix string 98 if keyPrefix == "" { 99 newKeyPrefix = str 100 } else { 101 newKeyPrefix = fmt.Sprintf("%s.%s", keyPrefix, str) 102 } 103 convertedEntry, err := convertToStringKeysRecursive(entry, newKeyPrefix) 104 if err != nil { 105 return nil, err 106 } 107 dict[str] = convertedEntry 108 } 109 return dict, nil 110 } 111 if list, ok := value.([]interface{}); ok { 112 var convertedList []interface{} 113 for index, entry := range list { 114 newKeyPrefix := fmt.Sprintf("%s[%d]", keyPrefix, index) 115 convertedEntry, err := convertToStringKeysRecursive(entry, newKeyPrefix) 116 if err != nil { 117 return nil, err 118 } 119 convertedList = append(convertedList, convertedEntry) 120 } 121 return convertedList, nil 122 } 123 return value, nil 124 } 125 126 func formatInvalidKeyError(keyPrefix string, key interface{}) error { 127 var location string 128 if keyPrefix == "" { 129 location = "at top level" 130 } else { 131 location = fmt.Sprintf("in %s", keyPrefix) 132 } 133 return errors.Errorf("Non-string key %s: %#v", location, key) 134 }