-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
value_source.go
145 lines (113 loc) · 3.25 KB
/
value_source.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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package cli
import (
"fmt"
"os"
"strings"
)
// ValueSource is a source which can be used to look up a value,
// typically for use with a cli.Flag
type ValueSource interface {
fmt.Stringer
fmt.GoStringer
// Lookup returns the value from the source and if it was found
// or returns an empty string and false
Lookup() (string, bool)
}
// ValueSourceChain contains an ordered series of ValueSource that
// allows for lookup where the first ValueSource to resolve is
// returned
type ValueSourceChain struct {
Chain []ValueSource
}
func NewValueSourceChain(src ...ValueSource) ValueSourceChain {
return ValueSourceChain{
Chain: src,
}
}
func (vsc *ValueSourceChain) Append(other ValueSourceChain) {
vsc.Chain = append(vsc.Chain, other.Chain...)
}
func (vsc *ValueSourceChain) EnvKeys() []string {
vals := []string{}
for _, src := range vsc.Chain {
if v, ok := src.(*envVarValueSource); ok {
vals = append(vals, v.Key)
}
}
return vals
}
func (vsc *ValueSourceChain) String() string {
s := []string{}
for _, vs := range vsc.Chain {
s = append(s, vs.String())
}
return strings.Join(s, ",")
}
func (vsc *ValueSourceChain) GoString() string {
s := []string{}
for _, vs := range vsc.Chain {
s = append(s, vs.GoString())
}
return fmt.Sprintf("&ValueSourceChain{Chain:{%[1]s}}", strings.Join(s, ","))
}
func (vsc *ValueSourceChain) Lookup() (string, bool) {
s, _, ok := vsc.LookupWithSource()
return s, ok
}
func (vsc *ValueSourceChain) LookupWithSource() (string, ValueSource, bool) {
for _, src := range vsc.Chain {
if value, found := src.Lookup(); found {
return value, src, true
}
}
return "", nil, false
}
// envVarValueSource encapsulates a ValueSource from an environment variable
type envVarValueSource struct {
Key string
}
func (e *envVarValueSource) Lookup() (string, bool) {
return os.LookupEnv(strings.TrimSpace(string(e.Key)))
}
func (e *envVarValueSource) String() string { return fmt.Sprintf("environment variable %[1]q", e.Key) }
func (e *envVarValueSource) GoString() string {
return fmt.Sprintf("&envVarValueSource{Key:%[1]q}", e.Key)
}
func EnvVar(key string) ValueSource {
return &envVarValueSource{
Key: key,
}
}
// EnvVars is a helper function to encapsulate a number of
// envVarValueSource together as a ValueSourceChain
func EnvVars(keys ...string) ValueSourceChain {
vsc := ValueSourceChain{Chain: []ValueSource{}}
for _, key := range keys {
vsc.Chain = append(vsc.Chain, &envVarValueSource{Key: key})
}
return vsc
}
// fileValueSource encapsulates a ValueSource from a file
type fileValueSource struct {
Path string
}
func (f *fileValueSource) Lookup() (string, bool) {
data, err := os.ReadFile(f.Path)
return string(data), err == nil
}
func (f *fileValueSource) String() string { return fmt.Sprintf("file %[1]q", f.Path) }
func (f *fileValueSource) GoString() string {
return fmt.Sprintf("&fileValueSource{Path:%[1]q}", f.Path)
}
func File(path string) ValueSource {
return &fileValueSource{Path: path}
}
// Files is a helper function to encapsulate a number of
// fileValueSource together as a ValueSourceChain
func Files(paths ...string) ValueSourceChain {
vsc := ValueSourceChain{Chain: []ValueSource{}}
for _, path := range paths {
vsc.Chain = append(vsc.Chain, &fileValueSource{Path: path})
}
return vsc
}