/
filedata.go
107 lines (93 loc) · 2.52 KB
/
filedata.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
96
97
98
99
100
101
102
103
104
105
106
107
package conflate
import (
pkgurl "net/url"
"os"
"path/filepath"
"strings"
)
type filedata struct {
url pkgurl.URL
bytes []byte
obj map[string]interface{}
includes []string
}
type filedatas []filedata
// UnmarshallerFunc defines the type of function used for unmarshalling data
type UnmarshallerFunc func([]byte, interface{}) error
// UnmarshallerFuncs defines the type for a slice of UnmarshallerFunc
type UnmarshallerFuncs []UnmarshallerFunc
// UnmarshallerMap defines the type of a map of string to UnmarshallerFuncs
type UnmarshallerMap map[string]UnmarshallerFuncs
// Unmarshallers is a list of unmarshalling functions to be used for given file extensions. The unmarshaller slice for the blank file extension is used when no match is found.
var Unmarshallers = UnmarshallerMap{
".json": {JSONUnmarshal},
".jsn": {JSONUnmarshal},
".yaml": {YAMLUnmarshal},
".yml": {YAMLUnmarshal},
".toml": {TOMLUnmarshal},
".tml": {TOMLUnmarshal},
"": {JSONUnmarshal, YAMLUnmarshal, TOMLUnmarshal},
}
func newFiledata(bytes []byte, url pkgurl.URL) (filedata, error) {
fd := filedata{bytes: bytes, url: url}
err := fd.unmarshal()
if err != nil {
return fd, fd.wrapError(err)
}
err = fd.extractIncludes()
return fd, fd.wrapError(err)
}
func newExpandedFiledata(bytes []byte, url pkgurl.URL) (filedata, error) {
expBytes := []byte(os.Expand(string(bytes),
func(name string) string {
val, ok := os.LookupEnv(name)
if ok {
return val
}
return "$" + name
}))
return newFiledata(expBytes, url)
}
func (fd *filedata) wrapError(err error) error {
if fd.url == emptyURL {
return err
}
return wrapError(err, "Error processing %v", fd.url.String())
}
func (fd *filedata) unmarshal() error {
ext := strings.ToLower(filepath.Ext(fd.url.Path))
unmarshallers, ok := Unmarshallers[ext]
if !ok {
unmarshallers = Unmarshallers[""]
}
err := makeError("Could not unmarshal data")
for _, unmarshal := range unmarshallers {
uerr := unmarshal(fd.bytes, &fd.obj)
if uerr == nil {
return nil
}
err = wrapError(uerr, err.Error())
}
return err
}
func (fd *filedata) extractIncludes() error {
if Includes == "" {
return nil
}
err := jsonMarshalUnmarshal(fd.obj[Includes], &fd.includes)
if err != nil {
return wrapError(err, "Could not extract includes")
}
delete(fd.obj, Includes)
return nil
}
func (fds filedatas) objs() []interface{} {
var objs []interface{}
for _, fd := range fds {
objs = append(objs, fd.obj)
}
return objs
}
func (fd *filedata) isEmpty() bool {
return fd == nil || fd.obj == nil
}