@@ -17,6 +17,11 @@ type ValueSource interface {
1717 Lookup () (string , bool )
1818}
1919
20+ type EnvValueSource interface {
21+ IsFromEnv () bool
22+ Key () string
23+ }
24+
2025// ValueSourceChain contains an ordered series of ValueSource that
2126// allows for lookup where the first ValueSource to resolve is
2227// returned
@@ -38,8 +43,8 @@ func (vsc *ValueSourceChain) EnvKeys() []string {
3843 vals := []string {}
3944
4045 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 () )
4348 }
4449 }
4550
@@ -83,21 +88,29 @@ func (vsc *ValueSourceChain) LookupWithSource() (string, ValueSource, bool) {
8388
8489// envVarValueSource encapsulates a ValueSource from an environment variable
8590type envVarValueSource struct {
86- Key string
91+ key string
8792}
8893
8994func (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
91100}
92101
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 ) }
94107func (e * envVarValueSource ) GoString () string {
95- return fmt .Sprintf ("&envVarValueSource{Key:%[1]q}" , e .Key )
108+ return fmt .Sprintf ("&envVarValueSource{Key:%[1]q}" , e .key )
96109}
97110
98111func EnvVar (key string ) ValueSource {
99112 return & envVarValueSource {
100- Key : key ,
113+ key : key ,
101114 }
102115}
103116
@@ -107,7 +120,7 @@ func EnvVars(keys ...string) ValueSourceChain {
107120 vsc := ValueSourceChain {Chain : []ValueSource {}}
108121
109122 for _ , key := range keys {
110- vsc .Chain = append (vsc .Chain , & envVarValueSource { Key : key } )
123+ vsc .Chain = append (vsc .Chain , EnvVar ( key ) )
111124 }
112125
113126 return vsc
@@ -138,8 +151,80 @@ func Files(paths ...string) ValueSourceChain {
138151 vsc := ValueSourceChain {Chain : []ValueSource {}}
139152
140153 for _ , path := range paths {
141- vsc .Chain = append (vsc .Chain , & fileValueSource { Path : path } )
154+ vsc .Chain = append (vsc .Chain , File ( path ) )
142155 }
143156
144157 return vsc
145158}
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