@@ -17,6 +17,11 @@ type ValueSource interface {
17
17
Lookup () (string , bool )
18
18
}
19
19
20
+ type EnvValueSource interface {
21
+ IsFromEnv () bool
22
+ Key () string
23
+ }
24
+
20
25
// ValueSourceChain contains an ordered series of ValueSource that
21
26
// allows for lookup where the first ValueSource to resolve is
22
27
// returned
@@ -38,8 +43,8 @@ func (vsc *ValueSourceChain) EnvKeys() []string {
38
43
vals := []string {}
39
44
40
45
for _ , src := range vsc .Chain {
41
- if v , ok := src .(* envVarValueSource ); ok {
42
- vals = append (vals , v .Key )
46
+ if v , ok := src .(EnvValueSource ); ok {
47
+ vals = append (vals , v .Key () )
43
48
}
44
49
}
45
50
@@ -83,21 +88,29 @@ func (vsc *ValueSourceChain) LookupWithSource() (string, ValueSource, bool) {
83
88
84
89
// envVarValueSource encapsulates a ValueSource from an environment variable
85
90
type envVarValueSource struct {
86
- Key string
91
+ key string
87
92
}
88
93
89
94
func (e * envVarValueSource ) Lookup () (string , bool ) {
90
- return os .LookupEnv (strings .TrimSpace (string (e .Key )))
95
+ return os .LookupEnv (strings .TrimSpace (string (e .key )))
96
+ }
97
+
98
+ func (e * envVarValueSource ) IsFromEnv () bool {
99
+ return true
91
100
}
92
101
93
- func (e * envVarValueSource ) String () string { return fmt .Sprintf ("environment variable %[1]q" , e .Key ) }
102
+ func (e * envVarValueSource ) Key () string {
103
+ return e .key
104
+ }
105
+
106
+ func (e * envVarValueSource ) String () string { return fmt .Sprintf ("environment variable %[1]q" , e .key ) }
94
107
func (e * envVarValueSource ) GoString () string {
95
- return fmt .Sprintf ("&envVarValueSource{Key:%[1]q}" , e .Key )
108
+ return fmt .Sprintf ("&envVarValueSource{Key:%[1]q}" , e .key )
96
109
}
97
110
98
111
func EnvVar (key string ) ValueSource {
99
112
return & envVarValueSource {
100
- Key : key ,
113
+ key : key ,
101
114
}
102
115
}
103
116
@@ -107,7 +120,7 @@ func EnvVars(keys ...string) ValueSourceChain {
107
120
vsc := ValueSourceChain {Chain : []ValueSource {}}
108
121
109
122
for _ , key := range keys {
110
- vsc .Chain = append (vsc .Chain , & envVarValueSource { Key : key } )
123
+ vsc .Chain = append (vsc .Chain , EnvVar ( key ) )
111
124
}
112
125
113
126
return vsc
@@ -138,8 +151,80 @@ func Files(paths ...string) ValueSourceChain {
138
151
vsc := ValueSourceChain {Chain : []ValueSource {}}
139
152
140
153
for _ , path := range paths {
141
- vsc .Chain = append (vsc .Chain , & fileValueSource { Path : path } )
154
+ vsc .Chain = append (vsc .Chain , File ( path ) )
142
155
}
143
156
144
157
return vsc
145
158
}
159
+
160
+ type MapSource struct {
161
+ name string
162
+ m map [any ]any
163
+ }
164
+
165
+ func NewMapSource (name string , m map [any ]any ) * MapSource {
166
+ return & MapSource {
167
+ name : name ,
168
+ m : m ,
169
+ }
170
+ }
171
+
172
+ func (ms * MapSource ) lookup (name string ) (any , bool ) {
173
+ // nestedVal checks if the name has '.' delimiters.
174
+ // If so, it tries to traverse the tree by the '.' delimited sections to find
175
+ // a nested value for the key.
176
+ if sections := strings .Split (name , "." ); len (sections ) > 1 {
177
+ node := ms .m
178
+ for _ , section := range sections [:len (sections )- 1 ] {
179
+ child , ok := node [section ]
180
+ if ! ok {
181
+ return nil , false
182
+ }
183
+
184
+ switch child := child .(type ) {
185
+ case map [string ]any :
186
+ node = make (map [any ]any , len (child ))
187
+ for k , v := range child {
188
+ node [k ] = v
189
+ }
190
+ case map [any ]any :
191
+ node = child
192
+ default :
193
+ return nil , false
194
+ }
195
+ }
196
+ if val , ok := node [sections [len (sections )- 1 ]]; ok {
197
+ return val , true
198
+ }
199
+ }
200
+
201
+ return nil , false
202
+ }
203
+
204
+ type mapValueSource struct {
205
+ key string
206
+ ms * MapSource
207
+ }
208
+
209
+ func NewMapValueSource (key string , ms * MapSource ) ValueSource {
210
+ return & mapValueSource {
211
+ key : key ,
212
+ ms : ms ,
213
+ }
214
+ }
215
+
216
+ func (mvs * mapValueSource ) String () string {
217
+ return fmt .Sprintf ("map source key %[1]q from %[2]q" , mvs .key , mvs .ms .name )
218
+ }
219
+
220
+ func (mvs * mapValueSource ) GoString () string {
221
+ return fmt .Sprintf ("&mapValueSource{key:%[1]q, src:%[2]q}" , mvs .key , mvs .ms .m )
222
+ }
223
+
224
+ func (mvs * mapValueSource ) Lookup () (string , bool ) {
225
+ if v , ok := mvs .ms .lookup (mvs .key ); ! ok {
226
+ return "" , false
227
+ } else {
228
+ return fmt .Sprintf ("%+v" , v ), true
229
+ }
230
+ }
0 commit comments