github.com/hairyhenderson/templater@v3.5.0+incompatible/data/datasource_merge.go (about)

     1  package data
     2  
     3  import (
     4  	"strings"
     5  
     6  	"github.com/hairyhenderson/gomplate/coll"
     7  
     8  	"github.com/pkg/errors"
     9  )
    10  
    11  // readMerge demultiplexes a `merge:` datasource. The 'args' parameter currently
    12  // has no meaning for this source.
    13  //
    14  // URI format is 'merge:<source 1>|<source 2>[|<source n>...]' where `<source #>`
    15  // is a supported URI or a pre-defined alias name.
    16  //
    17  // Query strings and fragments are interpreted relative to the merged data, not
    18  // the source data. To merge datasources with query strings or fragments, define
    19  // separate sources first and specify the alias names. HTTP headers are also not
    20  // supported directly.
    21  func (d *Data) readMerge(source *Source, args ...string) ([]byte, error) {
    22  	opaque := source.URL.Opaque
    23  	parts := strings.Split(opaque, "|")
    24  	if len(parts) < 2 {
    25  		return nil, errors.New("need at least 2 datasources to merge")
    26  	}
    27  	data := make([]map[string]interface{}, len(parts))
    28  	for i, part := range parts {
    29  		// supports either URIs or aliases
    30  		subSource, err := d.lookupSource(part)
    31  		if err != nil {
    32  			// maybe it's a relative filename?
    33  			subSource, err = parseSource(part + "=" + part)
    34  			if err != nil {
    35  				return nil, err
    36  			}
    37  		}
    38  		subSource.inherit(source)
    39  
    40  		b, err := d.readSource(subSource)
    41  		if err != nil {
    42  			return nil, errors.Wrapf(err, "Couldn't read datasource '%s'", part)
    43  		}
    44  
    45  		mimeType, err := subSource.mimeType()
    46  		if err != nil {
    47  			return nil, errors.Wrapf(err, "failed to read datasource %s", subSource.URL)
    48  		}
    49  
    50  		data[i], err = parseMap(mimeType, string(b))
    51  		if err != nil {
    52  			return nil, err
    53  		}
    54  	}
    55  
    56  	// Merge the data together
    57  	b, err := mergeData(data)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  
    62  	source.mediaType = yamlMimetype
    63  	return b, nil
    64  }
    65  
    66  func mergeData(data []map[string]interface{}) (out []byte, err error) {
    67  	dst := data[0]
    68  	data = data[1:]
    69  
    70  	dst, err = coll.Merge(dst, data...)
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  
    75  	s, err := ToYAML(dst)
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  	return []byte(s), nil
    80  }
    81  
    82  func parseMap(mimeType, data string) (map[string]interface{}, error) {
    83  	datum, err := parseData(mimeType, data)
    84  	if err != nil {
    85  		return nil, err
    86  	}
    87  	var m map[string]interface{}
    88  	switch datum := datum.(type) {
    89  	case map[string]interface{}:
    90  		m = datum
    91  	default:
    92  		return nil, errors.Errorf("unexpected data type '%T' for datasource (type %s); merge: can only merge maps", datum, mimeType)
    93  	}
    94  	return m, nil
    95  }