-
Notifications
You must be signed in to change notification settings - Fork 0
/
sources.go
117 lines (100 loc) · 2.55 KB
/
sources.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
108
109
110
111
112
113
114
115
116
117
package revip
import (
"io"
"io/ioutil"
"net/url"
"os"
"path"
"reflect"
"syscall"
json "encoding/json"
yaml "gopkg.in/yaml.v2"
env "github.com/kelseyhightower/envconfig"
toml "github.com/pelletier/go-toml"
)
type SourceOption func(c Config) error
// Unmarshaler describes a generic unmarshal interface for data decoding
// which could be used to extend supported formats by defining new `SourceOption`
// implementations.
type Unmarshaler = func(in []byte, v interface{}) error
var (
JsonUnmarshaler Unmarshaler = json.Unmarshal
YamlUnmarshaler Unmarshaler = yaml.Unmarshal
TomlUnmarshaler Unmarshaler = toml.Unmarshal
)
// FromReader is an `SourceOption` constructor which creates a thunk
// to read configuration from `r` and decode it with `f` unmarshaler.
// Current implementation buffers all data in memory.
func FromReader(r io.Reader, f Unmarshaler) SourceOption {
return func(c Config) error {
err := expectKind(reflect.TypeOf(c), reflect.Ptr)
if err != nil {
return err
}
buf, err := ioutil.ReadAll(r)
if err != nil {
return err
}
return f(buf, c)
}
}
// FromFile is an `SourceOption` constructor which creates a thunk
// to read configuration from file addressable by `path` with
// content decoded with `f` unmarshaler.
func FromFile(path string, f Unmarshaler) SourceOption {
return func(c Config) error {
err := expectKind(reflect.TypeOf(c), reflect.Ptr)
if err != nil {
return err
}
r, err := os.Open(path)
switch e := err.(type) {
case *os.PathError:
if e.Err == syscall.ENOENT {
return &ErrFileNotFound{
Path: path,
Err: err,
}
}
case nil:
default:
return err
}
defer r.Close()
return FromReader(r, f)(c)
}
}
// FromEnviron is an `SourceOption` constructor which creates a thunk
// to read configuration from environment.
// It uses `github.com/kelseyhightower/envconfig` underneath.
func FromEnviron(prefix string) SourceOption {
return func(c Config) error {
err := expectKind(reflect.TypeOf(c), reflect.Ptr)
if err != nil {
return err
}
return env.Process(prefix, c)
}
}
//
// FromURL creates a source from URL.
// Example URL's:
// - file://./config.yml
// - env://prefix
func FromURL(u string, d Unmarshaler) (SourceOption, error) {
uu, err := url.Parse(u)
if err != nil {
return nil, err
}
switch uu.Scheme {
case SchemeFile, SchemeEmpty:
return FromFile(path.Join(uu.Host, uu.Path), d), nil
case SchemeEnviron:
return FromEnviron(uu.Host), nil
default:
return nil, &ErrUnexpectedScheme{
Got: uu.Scheme,
Expected: FromSchemes,
}
}
}