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  }