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