Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
kardolus
GitHub Repository: kardolus/chatgpt-cli
Path: blob/main/vendor/github.com/spf13/viper/viper.go
2875 views
1
// Copyright © 2014 Steve Francia <[email protected]>.
2
//
3
// Use of this source code is governed by an MIT-style
4
// license that can be found in the LICENSE file.
5
6
// Viper is an application configuration system.
7
// It believes that applications can be configured a variety of ways
8
// via flags, ENVIRONMENT variables, configuration files retrieved
9
// from the file system, or a remote key/value store.
10
11
// Each item takes precedence over the item below it:
12
13
// overrides
14
// flag
15
// env
16
// config
17
// key/value store
18
// default
19
20
package viper
21
22
import (
23
"bytes"
24
"encoding/csv"
25
"errors"
26
"fmt"
27
"io"
28
"log/slog"
29
"os"
30
"path/filepath"
31
"reflect"
32
"slices"
33
"strconv"
34
"strings"
35
"sync"
36
"time"
37
38
"github.com/fsnotify/fsnotify"
39
"github.com/go-viper/mapstructure/v2"
40
"github.com/spf13/afero"
41
"github.com/spf13/cast"
42
"github.com/spf13/pflag"
43
44
"github.com/spf13/viper/internal/features"
45
)
46
47
// ConfigMarshalError happens when failing to marshal the configuration.
48
type ConfigMarshalError struct {
49
err error
50
}
51
52
// Error returns the formatted configuration error.
53
func (e ConfigMarshalError) Error() string {
54
return fmt.Sprintf("While marshaling config: %s", e.err.Error())
55
}
56
57
var v *Viper
58
59
func init() {
60
v = New()
61
}
62
63
// UnsupportedConfigError denotes encountering an unsupported
64
// configuration filetype.
65
type UnsupportedConfigError string
66
67
// Error returns the formatted configuration error.
68
func (str UnsupportedConfigError) Error() string {
69
return fmt.Sprintf("Unsupported Config Type %q", string(str))
70
}
71
72
// ConfigFileNotFoundError denotes failing to find configuration file.
73
type ConfigFileNotFoundError struct {
74
name, locations string
75
}
76
77
// Error returns the formatted configuration error.
78
func (fnfe ConfigFileNotFoundError) Error() string {
79
return fmt.Sprintf("Config File %q Not Found in %q", fnfe.name, fnfe.locations)
80
}
81
82
// ConfigFileAlreadyExistsError denotes failure to write new configuration file.
83
type ConfigFileAlreadyExistsError string
84
85
// Error returns the formatted error when configuration already exists.
86
func (faee ConfigFileAlreadyExistsError) Error() string {
87
return fmt.Sprintf("Config File %q Already Exists", string(faee))
88
}
89
90
// A DecoderConfigOption can be passed to viper.Unmarshal to configure
91
// mapstructure.DecoderConfig options.
92
type DecoderConfigOption func(*mapstructure.DecoderConfig)
93
94
// DecodeHook returns a DecoderConfigOption which overrides the default
95
// DecoderConfig.DecodeHook value, the default is:
96
//
97
// mapstructure.ComposeDecodeHookFunc(
98
// mapstructure.StringToTimeDurationHookFunc(),
99
// mapstructure.StringToSliceHookFunc(","),
100
// )
101
func DecodeHook(hook mapstructure.DecodeHookFunc) DecoderConfigOption {
102
return func(c *mapstructure.DecoderConfig) {
103
c.DecodeHook = hook
104
}
105
}
106
107
// Viper is a prioritized configuration registry. It
108
// maintains a set of configuration sources, fetches
109
// values to populate those, and provides them according
110
// to the source's priority.
111
// The priority of the sources is the following:
112
// 1. overrides
113
// 2. flags
114
// 3. env. variables
115
// 4. config file
116
// 5. key/value store
117
// 6. defaults
118
//
119
// For example, if values from the following sources were loaded:
120
//
121
// Defaults : {
122
// "secret": "",
123
// "user": "default",
124
// "endpoint": "https://localhost"
125
// }
126
// Config : {
127
// "user": "root"
128
// "secret": "defaultsecret"
129
// }
130
// Env : {
131
// "secret": "somesecretkey"
132
// }
133
//
134
// The resulting config will have the following values:
135
//
136
// {
137
// "secret": "somesecretkey",
138
// "user": "root",
139
// "endpoint": "https://localhost"
140
// }
141
//
142
// Note: Vipers are not safe for concurrent Get() and Set() operations.
143
type Viper struct {
144
// Delimiter that separates a list of keys
145
// used to access a nested value in one go
146
keyDelim string
147
148
// A set of paths to look for the config file in
149
configPaths []string
150
151
// The filesystem to read config from.
152
fs afero.Fs
153
154
finder Finder
155
156
// A set of remote providers to search for the configuration
157
remoteProviders []*defaultRemoteProvider
158
159
// Name of file to look for inside the path
160
configName string
161
configFile string
162
configType string
163
configPermissions os.FileMode
164
envPrefix string
165
166
automaticEnvApplied bool
167
envKeyReplacer StringReplacer
168
allowEmptyEnv bool
169
170
parents []string
171
config map[string]any
172
override map[string]any
173
defaults map[string]any
174
kvstore map[string]any
175
pflags map[string]FlagValue
176
env map[string][]string
177
aliases map[string]string
178
typeByDefValue bool
179
180
onConfigChange func(fsnotify.Event)
181
182
logger *slog.Logger
183
184
encoderRegistry EncoderRegistry
185
decoderRegistry DecoderRegistry
186
187
decodeHook mapstructure.DecodeHookFunc
188
189
experimentalFinder bool
190
experimentalBindStruct bool
191
}
192
193
// New returns an initialized Viper instance.
194
func New() *Viper {
195
v := new(Viper)
196
v.keyDelim = "."
197
v.configName = "config"
198
v.configPermissions = os.FileMode(0o644)
199
v.fs = afero.NewOsFs()
200
v.config = make(map[string]any)
201
v.parents = []string{}
202
v.override = make(map[string]any)
203
v.defaults = make(map[string]any)
204
v.kvstore = make(map[string]any)
205
v.pflags = make(map[string]FlagValue)
206
v.env = make(map[string][]string)
207
v.aliases = make(map[string]string)
208
v.typeByDefValue = false
209
v.logger = slog.New(&discardHandler{})
210
211
codecRegistry := NewCodecRegistry()
212
213
v.encoderRegistry = codecRegistry
214
v.decoderRegistry = codecRegistry
215
216
v.experimentalFinder = features.Finder
217
v.experimentalBindStruct = features.BindStruct
218
219
return v
220
}
221
222
// Option configures Viper using the functional options paradigm popularized by Rob Pike and Dave Cheney.
223
// If you're unfamiliar with this style,
224
// see https://commandcenter.blogspot.com/2014/01/self-referential-functions-and-design.html and
225
// https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis.
226
type Option interface {
227
apply(v *Viper)
228
}
229
230
type optionFunc func(v *Viper)
231
232
func (fn optionFunc) apply(v *Viper) {
233
fn(v)
234
}
235
236
// KeyDelimiter sets the delimiter used for determining key parts.
237
// By default it's value is ".".
238
func KeyDelimiter(d string) Option {
239
return optionFunc(func(v *Viper) {
240
v.keyDelim = d
241
})
242
}
243
244
// StringReplacer applies a set of replacements to a string.
245
type StringReplacer interface {
246
// Replace returns a copy of s with all replacements performed.
247
Replace(s string) string
248
}
249
250
// EnvKeyReplacer sets a replacer used for mapping environment variables to internal keys.
251
func EnvKeyReplacer(r StringReplacer) Option {
252
return optionFunc(func(v *Viper) {
253
if r == nil {
254
return
255
}
256
257
v.envKeyReplacer = r
258
})
259
}
260
261
// WithDecodeHook sets a default decode hook for mapstructure.
262
func WithDecodeHook(h mapstructure.DecodeHookFunc) Option {
263
return optionFunc(func(v *Viper) {
264
if h == nil {
265
return
266
}
267
268
v.decodeHook = h
269
})
270
}
271
272
// NewWithOptions creates a new Viper instance.
273
func NewWithOptions(opts ...Option) *Viper {
274
v := New()
275
276
for _, opt := range opts {
277
opt.apply(v)
278
}
279
280
return v
281
}
282
283
// SetOptions sets the options on the global Viper instance.
284
//
285
// Be careful when using this function: subsequent calls may override options you set.
286
// It's always better to use a local Viper instance.
287
func SetOptions(opts ...Option) {
288
for _, opt := range opts {
289
opt.apply(v)
290
}
291
}
292
293
// Reset is intended for testing, will reset all to default settings.
294
// In the public interface for the viper package so applications
295
// can use it in their testing as well.
296
func Reset() {
297
v = New()
298
SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}
299
300
resetRemote()
301
}
302
303
// SupportedExts are universally supported extensions.
304
var SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}
305
306
// OnConfigChange sets the event handler that is called when a config file changes.
307
func OnConfigChange(run func(in fsnotify.Event)) { v.OnConfigChange(run) }
308
309
// OnConfigChange sets the event handler that is called when a config file changes.
310
func (v *Viper) OnConfigChange(run func(in fsnotify.Event)) {
311
v.onConfigChange = run
312
}
313
314
// WatchConfig starts watching a config file for changes.
315
func WatchConfig() { v.WatchConfig() }
316
317
// WatchConfig starts watching a config file for changes.
318
func (v *Viper) WatchConfig() {
319
initWG := sync.WaitGroup{}
320
initWG.Add(1)
321
go func() {
322
watcher, err := fsnotify.NewWatcher()
323
if err != nil {
324
v.logger.Error(fmt.Sprintf("failed to create watcher: %s", err))
325
os.Exit(1)
326
}
327
defer watcher.Close()
328
// we have to watch the entire directory to pick up renames/atomic saves in a cross-platform way
329
filename, err := v.getConfigFile()
330
if err != nil {
331
v.logger.Error(fmt.Sprintf("get config file: %s", err))
332
initWG.Done()
333
return
334
}
335
336
configFile := filepath.Clean(filename)
337
configDir, _ := filepath.Split(configFile)
338
realConfigFile, _ := filepath.EvalSymlinks(filename)
339
340
eventsWG := sync.WaitGroup{}
341
eventsWG.Add(1)
342
go func() {
343
for {
344
select {
345
case event, ok := <-watcher.Events:
346
if !ok { // 'Events' channel is closed
347
eventsWG.Done()
348
return
349
}
350
currentConfigFile, _ := filepath.EvalSymlinks(filename)
351
// we only care about the config file with the following cases:
352
// 1 - if the config file was modified or created
353
// 2 - if the real path to the config file changed (eg: k8s ConfigMap replacement)
354
if (filepath.Clean(event.Name) == configFile &&
355
(event.Has(fsnotify.Write) || event.Has(fsnotify.Create))) ||
356
(currentConfigFile != "" && currentConfigFile != realConfigFile) {
357
realConfigFile = currentConfigFile
358
err := v.ReadInConfig()
359
if err != nil {
360
v.logger.Error(fmt.Sprintf("read config file: %s", err))
361
}
362
if v.onConfigChange != nil {
363
v.onConfigChange(event)
364
}
365
} else if filepath.Clean(event.Name) == configFile && event.Has(fsnotify.Remove) {
366
eventsWG.Done()
367
return
368
}
369
370
case err, ok := <-watcher.Errors:
371
if ok { // 'Errors' channel is not closed
372
v.logger.Error(fmt.Sprintf("watcher error: %s", err))
373
}
374
eventsWG.Done()
375
return
376
}
377
}
378
}()
379
err = watcher.Add(configDir)
380
if err != nil {
381
v.logger.Error(fmt.Sprintf("failed to add watcher: %s", err))
382
initWG.Done()
383
return
384
}
385
initWG.Done() // done initializing the watch in this go routine, so the parent routine can move on...
386
eventsWG.Wait() // now, wait for event loop to end in this go-routine...
387
}()
388
initWG.Wait() // make sure that the go routine above fully ended before returning
389
}
390
391
// SetConfigFile explicitly defines the path, name and extension of the config file.
392
// Viper will use this and not check any of the config paths.
393
func SetConfigFile(in string) { v.SetConfigFile(in) }
394
395
func (v *Viper) SetConfigFile(in string) {
396
if in != "" {
397
v.configFile = in
398
}
399
}
400
401
// SetEnvPrefix defines a prefix that ENVIRONMENT variables will use.
402
// E.g. if your prefix is "spf", the env registry will look for env
403
// variables that start with "SPF_".
404
func SetEnvPrefix(in string) { v.SetEnvPrefix(in) }
405
406
func (v *Viper) SetEnvPrefix(in string) {
407
if in != "" {
408
v.envPrefix = in
409
}
410
}
411
412
func GetEnvPrefix() string { return v.GetEnvPrefix() }
413
414
func (v *Viper) GetEnvPrefix() string {
415
return v.envPrefix
416
}
417
418
func (v *Viper) mergeWithEnvPrefix(in string) string {
419
if v.envPrefix != "" {
420
return strings.ToUpper(v.envPrefix + "_" + in)
421
}
422
423
return strings.ToUpper(in)
424
}
425
426
// AllowEmptyEnv tells Viper to consider set,
427
// but empty environment variables as valid values instead of falling back.
428
// For backward compatibility reasons this is false by default.
429
func AllowEmptyEnv(allowEmptyEnv bool) { v.AllowEmptyEnv(allowEmptyEnv) }
430
431
func (v *Viper) AllowEmptyEnv(allowEmptyEnv bool) {
432
v.allowEmptyEnv = allowEmptyEnv
433
}
434
435
// TODO: should getEnv logic be moved into find(). Can generalize the use of
436
// rewriting keys many things, Ex: Get('someKey') -> some_key
437
// (camel case to snake case for JSON keys perhaps)
438
439
// getEnv is a wrapper around os.Getenv which replaces characters in the original
440
// key. This allows env vars which have different keys than the config object
441
// keys.
442
func (v *Viper) getEnv(key string) (string, bool) {
443
if v.envKeyReplacer != nil {
444
key = v.envKeyReplacer.Replace(key)
445
}
446
447
val, ok := os.LookupEnv(key)
448
449
return val, ok && (v.allowEmptyEnv || val != "")
450
}
451
452
// ConfigFileUsed returns the file used to populate the config registry.
453
func ConfigFileUsed() string { return v.ConfigFileUsed() }
454
func (v *Viper) ConfigFileUsed() string { return v.configFile }
455
456
// AddConfigPath adds a path for Viper to search for the config file in.
457
// Can be called multiple times to define multiple search paths.
458
func AddConfigPath(in string) { v.AddConfigPath(in) }
459
460
func (v *Viper) AddConfigPath(in string) {
461
if v.finder != nil {
462
v.logger.Warn("ineffective call to function: custom finder takes precedence", slog.String("function", "AddConfigPath"))
463
}
464
465
if in != "" {
466
absin := absPathify(v.logger, in)
467
468
v.logger.Info("adding path to search paths", "path", absin)
469
if !slices.Contains(v.configPaths, absin) {
470
v.configPaths = append(v.configPaths, absin)
471
}
472
}
473
}
474
475
// searchMap recursively searches for a value for path in source map.
476
// Returns nil if not found.
477
// Note: This assumes that the path entries and map keys are lower cased.
478
func (v *Viper) searchMap(source map[string]any, path []string) any {
479
if len(path) == 0 {
480
return source
481
}
482
483
next, ok := source[path[0]]
484
if ok {
485
// Fast path
486
if len(path) == 1 {
487
return next
488
}
489
490
// Nested case
491
switch next := next.(type) {
492
case map[any]any:
493
return v.searchMap(cast.ToStringMap(next), path[1:])
494
case map[string]any:
495
// Type assertion is safe here since it is only reached
496
// if the type of `next` is the same as the type being asserted
497
return v.searchMap(next, path[1:])
498
default:
499
// got a value but nested key expected, return "nil" for not found
500
return nil
501
}
502
}
503
return nil
504
}
505
506
// searchIndexableWithPathPrefixes recursively searches for a value for path in source map/slice.
507
//
508
// While searchMap() considers each path element as a single map key or slice index, this
509
// function searches for, and prioritizes, merged path elements.
510
// e.g., if in the source, "foo" is defined with a sub-key "bar", and "foo.bar"
511
// is also defined, this latter value is returned for path ["foo", "bar"].
512
//
513
// This should be useful only at config level (other maps may not contain dots
514
// in their keys).
515
//
516
// Note: This assumes that the path entries and map keys are lower cased.
517
func (v *Viper) searchIndexableWithPathPrefixes(source any, path []string) any {
518
if len(path) == 0 {
519
return source
520
}
521
522
// search for path prefixes, starting from the longest one
523
for i := len(path); i > 0; i-- {
524
prefixKey := strings.ToLower(strings.Join(path[0:i], v.keyDelim))
525
526
var val any
527
switch sourceIndexable := source.(type) {
528
case []any:
529
val = v.searchSliceWithPathPrefixes(sourceIndexable, prefixKey, i, path)
530
case map[string]any:
531
val = v.searchMapWithPathPrefixes(sourceIndexable, prefixKey, i, path)
532
}
533
if val != nil {
534
return val
535
}
536
}
537
538
// not found
539
return nil
540
}
541
542
// searchSliceWithPathPrefixes searches for a value for path in sourceSlice
543
//
544
// This function is part of the searchIndexableWithPathPrefixes recurring search and
545
// should not be called directly from functions other than searchIndexableWithPathPrefixes.
546
func (v *Viper) searchSliceWithPathPrefixes(
547
sourceSlice []any,
548
prefixKey string,
549
pathIndex int,
550
path []string,
551
) any {
552
// if the prefixKey is not a number or it is out of bounds of the slice
553
index, err := strconv.Atoi(prefixKey)
554
if err != nil || len(sourceSlice) <= index {
555
return nil
556
}
557
558
next := sourceSlice[index]
559
560
// Fast path
561
if pathIndex == len(path) {
562
return next
563
}
564
565
switch n := next.(type) {
566
case map[any]any:
567
return v.searchIndexableWithPathPrefixes(cast.ToStringMap(n), path[pathIndex:])
568
case map[string]any, []any:
569
return v.searchIndexableWithPathPrefixes(n, path[pathIndex:])
570
default:
571
// got a value but nested key expected, do nothing and look for next prefix
572
}
573
574
// not found
575
return nil
576
}
577
578
// searchMapWithPathPrefixes searches for a value for path in sourceMap
579
//
580
// This function is part of the searchIndexableWithPathPrefixes recurring search and
581
// should not be called directly from functions other than searchIndexableWithPathPrefixes.
582
func (v *Viper) searchMapWithPathPrefixes(
583
sourceMap map[string]any,
584
prefixKey string,
585
pathIndex int,
586
path []string,
587
) any {
588
next, ok := sourceMap[prefixKey]
589
if !ok {
590
return nil
591
}
592
593
// Fast path
594
if pathIndex == len(path) {
595
return next
596
}
597
598
// Nested case
599
switch n := next.(type) {
600
case map[any]any:
601
return v.searchIndexableWithPathPrefixes(cast.ToStringMap(n), path[pathIndex:])
602
case map[string]any, []any:
603
return v.searchIndexableWithPathPrefixes(n, path[pathIndex:])
604
default:
605
// got a value but nested key expected, do nothing and look for next prefix
606
}
607
608
// not found
609
return nil
610
}
611
612
// isPathShadowedInDeepMap makes sure the given path is not shadowed somewhere
613
// on its path in the map.
614
// e.g., if "foo.bar" has a value in the given map, it “shadows”
615
//
616
// "foo.bar.baz" in a lower-priority map
617
func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]any) string {
618
var parentVal any
619
for i := 1; i < len(path); i++ {
620
parentVal = v.searchMap(m, path[0:i])
621
if parentVal == nil {
622
// not found, no need to add more path elements
623
return ""
624
}
625
switch parentVal.(type) {
626
case map[any]any:
627
continue
628
case map[string]any:
629
continue
630
default:
631
// parentVal is a regular value which shadows "path"
632
return strings.Join(path[0:i], v.keyDelim)
633
}
634
}
635
return ""
636
}
637
638
// isPathShadowedInFlatMap makes sure the given path is not shadowed somewhere
639
// in a sub-path of the map.
640
// e.g., if "foo.bar" has a value in the given map, it “shadows”
641
//
642
// "foo.bar.baz" in a lower-priority map
643
func (v *Viper) isPathShadowedInFlatMap(path []string, mi any) string {
644
// unify input map
645
var m map[string]interface{}
646
switch miv := mi.(type) {
647
case map[string]string:
648
m = castMapStringToMapInterface(miv)
649
case map[string]FlagValue:
650
m = castMapFlagToMapInterface(miv)
651
default:
652
return ""
653
}
654
655
// scan paths
656
var parentKey string
657
for i := 1; i < len(path); i++ {
658
parentKey = strings.Join(path[0:i], v.keyDelim)
659
if _, ok := m[parentKey]; ok {
660
return parentKey
661
}
662
}
663
return ""
664
}
665
666
// isPathShadowedInAutoEnv makes sure the given path is not shadowed somewhere
667
// in the environment, when automatic env is on.
668
// e.g., if "foo.bar" has a value in the environment, it “shadows”
669
//
670
// "foo.bar.baz" in a lower-priority map
671
func (v *Viper) isPathShadowedInAutoEnv(path []string) string {
672
var parentKey string
673
for i := 1; i < len(path); i++ {
674
parentKey = strings.Join(path[0:i], v.keyDelim)
675
if _, ok := v.getEnv(v.mergeWithEnvPrefix(parentKey)); ok {
676
return parentKey
677
}
678
}
679
return ""
680
}
681
682
// SetTypeByDefaultValue enables or disables the inference of a key value's
683
// type when the Get function is used based upon a key's default value as
684
// opposed to the value returned based on the normal fetch logic.
685
//
686
// For example, if a key has a default value of []string{} and the same key
687
// is set via an environment variable to "a b c", a call to the Get function
688
// would return a string slice for the key if the key's type is inferred by
689
// the default value and the Get function would return:
690
//
691
// []string {"a", "b", "c"}
692
//
693
// Otherwise the Get function would return:
694
//
695
// "a b c"
696
func SetTypeByDefaultValue(enable bool) { v.SetTypeByDefaultValue(enable) }
697
698
func (v *Viper) SetTypeByDefaultValue(enable bool) {
699
v.typeByDefValue = enable
700
}
701
702
// GetViper gets the global Viper instance.
703
func GetViper() *Viper {
704
return v
705
}
706
707
// Get can retrieve any value given the key to use.
708
// Get is case-insensitive for a key.
709
// Get has the behavior of returning the value associated with the first
710
// place from where it is set. Viper will check in the following order:
711
// override, flag, env, config file, key/value store, default
712
//
713
// Get returns an interface. For a specific value use one of the Get____ methods.
714
func Get(key string) any { return v.Get(key) }
715
716
func (v *Viper) Get(key string) any {
717
lcaseKey := strings.ToLower(key)
718
val := v.find(lcaseKey, true)
719
if val == nil {
720
return nil
721
}
722
723
if v.typeByDefValue {
724
// TODO(bep) this branch isn't covered by a single test.
725
valType := val
726
path := strings.Split(lcaseKey, v.keyDelim)
727
defVal := v.searchMap(v.defaults, path)
728
if defVal != nil {
729
valType = defVal
730
}
731
732
switch valType.(type) {
733
case bool:
734
return cast.ToBool(val)
735
case string:
736
return cast.ToString(val)
737
case int32, int16, int8, int:
738
return cast.ToInt(val)
739
case uint:
740
return cast.ToUint(val)
741
case uint32:
742
return cast.ToUint32(val)
743
case uint64:
744
return cast.ToUint64(val)
745
case int64:
746
return cast.ToInt64(val)
747
case float64, float32:
748
return cast.ToFloat64(val)
749
case time.Time:
750
return cast.ToTime(val)
751
case time.Duration:
752
return cast.ToDuration(val)
753
case []string:
754
return cast.ToStringSlice(val)
755
case []int:
756
return cast.ToIntSlice(val)
757
case []time.Duration:
758
return cast.ToDurationSlice(val)
759
}
760
}
761
762
return val
763
}
764
765
// Sub returns new Viper instance representing a sub tree of this instance.
766
// Sub is case-insensitive for a key.
767
func Sub(key string) *Viper { return v.Sub(key) }
768
769
func (v *Viper) Sub(key string) *Viper {
770
subv := New()
771
data := v.Get(key)
772
if data == nil {
773
return nil
774
}
775
776
if reflect.TypeOf(data).Kind() == reflect.Map {
777
subv.parents = append([]string(nil), v.parents...)
778
subv.parents = append(subv.parents, strings.ToLower(key))
779
subv.automaticEnvApplied = v.automaticEnvApplied
780
subv.envPrefix = v.envPrefix
781
subv.envKeyReplacer = v.envKeyReplacer
782
subv.keyDelim = v.keyDelim
783
subv.config = cast.ToStringMap(data)
784
return subv
785
}
786
return nil
787
}
788
789
// GetString returns the value associated with the key as a string.
790
func GetString(key string) string { return v.GetString(key) }
791
792
func (v *Viper) GetString(key string) string {
793
return cast.ToString(v.Get(key))
794
}
795
796
// GetBool returns the value associated with the key as a boolean.
797
func GetBool(key string) bool { return v.GetBool(key) }
798
799
func (v *Viper) GetBool(key string) bool {
800
return cast.ToBool(v.Get(key))
801
}
802
803
// GetInt returns the value associated with the key as an integer.
804
func GetInt(key string) int { return v.GetInt(key) }
805
806
func (v *Viper) GetInt(key string) int {
807
return cast.ToInt(v.Get(key))
808
}
809
810
// GetInt32 returns the value associated with the key as an integer.
811
func GetInt32(key string) int32 { return v.GetInt32(key) }
812
813
func (v *Viper) GetInt32(key string) int32 {
814
return cast.ToInt32(v.Get(key))
815
}
816
817
// GetInt64 returns the value associated with the key as an integer.
818
func GetInt64(key string) int64 { return v.GetInt64(key) }
819
820
func (v *Viper) GetInt64(key string) int64 {
821
return cast.ToInt64(v.Get(key))
822
}
823
824
// GetUint8 returns the value associated with the key as an unsigned integer.
825
func GetUint8(key string) uint8 { return v.GetUint8(key) }
826
827
func (v *Viper) GetUint8(key string) uint8 {
828
return cast.ToUint8(v.Get(key))
829
}
830
831
// GetUint returns the value associated with the key as an unsigned integer.
832
func GetUint(key string) uint { return v.GetUint(key) }
833
834
func (v *Viper) GetUint(key string) uint {
835
return cast.ToUint(v.Get(key))
836
}
837
838
// GetUint16 returns the value associated with the key as an unsigned integer.
839
func GetUint16(key string) uint16 { return v.GetUint16(key) }
840
841
func (v *Viper) GetUint16(key string) uint16 {
842
return cast.ToUint16(v.Get(key))
843
}
844
845
// GetUint32 returns the value associated with the key as an unsigned integer.
846
func GetUint32(key string) uint32 { return v.GetUint32(key) }
847
848
func (v *Viper) GetUint32(key string) uint32 {
849
return cast.ToUint32(v.Get(key))
850
}
851
852
// GetUint64 returns the value associated with the key as an unsigned integer.
853
func GetUint64(key string) uint64 { return v.GetUint64(key) }
854
855
func (v *Viper) GetUint64(key string) uint64 {
856
return cast.ToUint64(v.Get(key))
857
}
858
859
// GetFloat64 returns the value associated with the key as a float64.
860
func GetFloat64(key string) float64 { return v.GetFloat64(key) }
861
862
func (v *Viper) GetFloat64(key string) float64 {
863
return cast.ToFloat64(v.Get(key))
864
}
865
866
// GetTime returns the value associated with the key as time.
867
func GetTime(key string) time.Time { return v.GetTime(key) }
868
869
func (v *Viper) GetTime(key string) time.Time {
870
return cast.ToTime(v.Get(key))
871
}
872
873
// GetDuration returns the value associated with the key as a duration.
874
func GetDuration(key string) time.Duration { return v.GetDuration(key) }
875
876
func (v *Viper) GetDuration(key string) time.Duration {
877
return cast.ToDuration(v.Get(key))
878
}
879
880
// GetIntSlice returns the value associated with the key as a slice of int values.
881
func GetIntSlice(key string) []int { return v.GetIntSlice(key) }
882
883
func (v *Viper) GetIntSlice(key string) []int {
884
return cast.ToIntSlice(v.Get(key))
885
}
886
887
// GetStringSlice returns the value associated with the key as a slice of strings.
888
func GetStringSlice(key string) []string { return v.GetStringSlice(key) }
889
890
func (v *Viper) GetStringSlice(key string) []string {
891
return cast.ToStringSlice(v.Get(key))
892
}
893
894
// GetStringMap returns the value associated with the key as a map of interfaces.
895
func GetStringMap(key string) map[string]any { return v.GetStringMap(key) }
896
897
func (v *Viper) GetStringMap(key string) map[string]any {
898
return cast.ToStringMap(v.Get(key))
899
}
900
901
// GetStringMapString returns the value associated with the key as a map of strings.
902
func GetStringMapString(key string) map[string]string { return v.GetStringMapString(key) }
903
904
func (v *Viper) GetStringMapString(key string) map[string]string {
905
return cast.ToStringMapString(v.Get(key))
906
}
907
908
// GetStringMapStringSlice returns the value associated with the key as a map to a slice of strings.
909
func GetStringMapStringSlice(key string) map[string][]string { return v.GetStringMapStringSlice(key) }
910
911
func (v *Viper) GetStringMapStringSlice(key string) map[string][]string {
912
return cast.ToStringMapStringSlice(v.Get(key))
913
}
914
915
// GetSizeInBytes returns the size of the value associated with the given key
916
// in bytes.
917
func GetSizeInBytes(key string) uint { return v.GetSizeInBytes(key) }
918
919
func (v *Viper) GetSizeInBytes(key string) uint {
920
sizeStr := cast.ToString(v.Get(key))
921
return parseSizeInBytes(sizeStr)
922
}
923
924
// UnmarshalKey takes a single key and unmarshals it into a Struct.
925
func UnmarshalKey(key string, rawVal any, opts ...DecoderConfigOption) error {
926
return v.UnmarshalKey(key, rawVal, opts...)
927
}
928
929
func (v *Viper) UnmarshalKey(key string, rawVal any, opts ...DecoderConfigOption) error {
930
return decode(v.Get(key), v.defaultDecoderConfig(rawVal, opts...))
931
}
932
933
// Unmarshal unmarshals the config into a Struct. Make sure that the tags
934
// on the fields of the structure are properly set.
935
func Unmarshal(rawVal any, opts ...DecoderConfigOption) error {
936
return v.Unmarshal(rawVal, opts...)
937
}
938
939
func (v *Viper) Unmarshal(rawVal any, opts ...DecoderConfigOption) error {
940
keys := v.AllKeys()
941
942
if v.experimentalBindStruct {
943
// TODO: make this optional?
944
structKeys, err := v.decodeStructKeys(rawVal, opts...)
945
if err != nil {
946
return err
947
}
948
949
keys = append(keys, structKeys...)
950
}
951
952
// TODO: struct keys should be enough?
953
return decode(v.getSettings(keys), v.defaultDecoderConfig(rawVal, opts...))
954
}
955
956
func (v *Viper) decodeStructKeys(input any, opts ...DecoderConfigOption) ([]string, error) {
957
var structKeyMap map[string]any
958
959
err := decode(input, v.defaultDecoderConfig(&structKeyMap, opts...))
960
if err != nil {
961
return nil, err
962
}
963
964
flattenedStructKeyMap := v.flattenAndMergeMap(map[string]bool{}, structKeyMap, "")
965
966
r := make([]string, 0, len(flattenedStructKeyMap))
967
for v := range flattenedStructKeyMap {
968
r = append(r, v)
969
}
970
971
return r, nil
972
}
973
974
// defaultDecoderConfig returns default mapstructure.DecoderConfig with support
975
// of time.Duration values & string slices.
976
func (v *Viper) defaultDecoderConfig(output any, opts ...DecoderConfigOption) *mapstructure.DecoderConfig {
977
decodeHook := v.decodeHook
978
if decodeHook == nil {
979
decodeHook = mapstructure.ComposeDecodeHookFunc(
980
mapstructure.StringToTimeDurationHookFunc(),
981
// mapstructure.StringToSliceHookFunc(","),
982
stringToWeakSliceHookFunc(","),
983
)
984
}
985
986
c := &mapstructure.DecoderConfig{
987
Metadata: nil,
988
WeaklyTypedInput: true,
989
DecodeHook: decodeHook,
990
}
991
992
for _, opt := range opts {
993
opt(c)
994
}
995
996
// Do not allow overwriting the output
997
c.Result = output
998
999
return c
1000
}
1001
1002
// As of mapstructure v2.0.0 StringToSliceHookFunc checks if the return type is a string slice.
1003
// This function removes that check.
1004
// TODO: implement a function that checks if the value can be converted to the return type and use it instead.
1005
func stringToWeakSliceHookFunc(sep string) mapstructure.DecodeHookFunc {
1006
return func(
1007
f reflect.Type,
1008
t reflect.Type,
1009
data interface{},
1010
) (interface{}, error) {
1011
if f.Kind() != reflect.String || t.Kind() != reflect.Slice {
1012
return data, nil
1013
}
1014
1015
raw := data.(string)
1016
if raw == "" {
1017
return []string{}, nil
1018
}
1019
1020
return strings.Split(raw, sep), nil
1021
}
1022
}
1023
1024
// decode is a wrapper around mapstructure.Decode that mimics the WeakDecode functionality.
1025
func decode(input any, config *mapstructure.DecoderConfig) error {
1026
decoder, err := mapstructure.NewDecoder(config)
1027
if err != nil {
1028
return err
1029
}
1030
return decoder.Decode(input)
1031
}
1032
1033
// UnmarshalExact unmarshals the config into a Struct, erroring if a field is nonexistent
1034
// in the destination struct.
1035
func UnmarshalExact(rawVal any, opts ...DecoderConfigOption) error {
1036
return v.UnmarshalExact(rawVal, opts...)
1037
}
1038
1039
func (v *Viper) UnmarshalExact(rawVal any, opts ...DecoderConfigOption) error {
1040
config := v.defaultDecoderConfig(rawVal, opts...)
1041
config.ErrorUnused = true
1042
1043
keys := v.AllKeys()
1044
1045
if v.experimentalBindStruct {
1046
// TODO: make this optional?
1047
structKeys, err := v.decodeStructKeys(rawVal, opts...)
1048
if err != nil {
1049
return err
1050
}
1051
1052
keys = append(keys, structKeys...)
1053
}
1054
1055
// TODO: struct keys should be enough?
1056
return decode(v.getSettings(keys), config)
1057
}
1058
1059
// BindPFlags binds a full flag set to the configuration, using each flag's long
1060
// name as the config key.
1061
func BindPFlags(flags *pflag.FlagSet) error { return v.BindPFlags(flags) }
1062
1063
func (v *Viper) BindPFlags(flags *pflag.FlagSet) error {
1064
return v.BindFlagValues(pflagValueSet{flags})
1065
}
1066
1067
// BindPFlag binds a specific key to a pflag (as used by cobra).
1068
// Example (where serverCmd is a Cobra instance):
1069
//
1070
// serverCmd.Flags().Int("port", 1138, "Port to run Application server on")
1071
// Viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))
1072
func BindPFlag(key string, flag *pflag.Flag) error { return v.BindPFlag(key, flag) }
1073
1074
func (v *Viper) BindPFlag(key string, flag *pflag.Flag) error {
1075
if flag == nil {
1076
return fmt.Errorf("flag for %q is nil", key)
1077
}
1078
return v.BindFlagValue(key, pflagValue{flag})
1079
}
1080
1081
// BindFlagValues binds a full FlagValue set to the configuration, using each flag's long
1082
// name as the config key.
1083
func BindFlagValues(flags FlagValueSet) error { return v.BindFlagValues(flags) }
1084
1085
func (v *Viper) BindFlagValues(flags FlagValueSet) (err error) {
1086
flags.VisitAll(func(flag FlagValue) {
1087
if err = v.BindFlagValue(flag.Name(), flag); err != nil {
1088
return
1089
}
1090
})
1091
return nil
1092
}
1093
1094
// BindFlagValue binds a specific key to a FlagValue.
1095
func BindFlagValue(key string, flag FlagValue) error { return v.BindFlagValue(key, flag) }
1096
1097
func (v *Viper) BindFlagValue(key string, flag FlagValue) error {
1098
if flag == nil {
1099
return fmt.Errorf("flag for %q is nil", key)
1100
}
1101
v.pflags[strings.ToLower(key)] = flag
1102
return nil
1103
}
1104
1105
// BindEnv binds a Viper key to a ENV variable.
1106
// ENV variables are case sensitive.
1107
// If only a key is provided, it will use the env key matching the key, uppercased.
1108
// If more arguments are provided, they will represent the env variable names that
1109
// should bind to this key and will be taken in the specified order.
1110
// EnvPrefix will be used when set when env name is not provided.
1111
func BindEnv(input ...string) error { return v.BindEnv(input...) }
1112
1113
func (v *Viper) BindEnv(input ...string) error {
1114
if len(input) == 0 {
1115
return fmt.Errorf("missing key to bind to")
1116
}
1117
1118
key := strings.ToLower(input[0])
1119
1120
if len(input) == 1 {
1121
v.env[key] = append(v.env[key], v.mergeWithEnvPrefix(key))
1122
} else {
1123
v.env[key] = append(v.env[key], input[1:]...)
1124
}
1125
1126
return nil
1127
}
1128
1129
// MustBindEnv wraps BindEnv in a panic.
1130
// If there is an error binding an environment variable, MustBindEnv will
1131
// panic.
1132
func MustBindEnv(input ...string) { v.MustBindEnv(input...) }
1133
1134
func (v *Viper) MustBindEnv(input ...string) {
1135
if err := v.BindEnv(input...); err != nil {
1136
panic(fmt.Sprintf("error while binding environment variable: %v", err))
1137
}
1138
}
1139
1140
// Given a key, find the value.
1141
//
1142
// Viper will check to see if an alias exists first.
1143
// Viper will then check in the following order:
1144
// flag, env, config file, key/value store.
1145
// Lastly, if no value was found and flagDefault is true, and if the key
1146
// corresponds to a flag, the flag's default value is returned.
1147
//
1148
// Note: this assumes a lower-cased key given.
1149
func (v *Viper) find(lcaseKey string, flagDefault bool) any {
1150
var (
1151
val any
1152
exists bool
1153
path = strings.Split(lcaseKey, v.keyDelim)
1154
nested = len(path) > 1
1155
)
1156
1157
// compute the path through the nested maps to the nested value
1158
if nested && v.isPathShadowedInDeepMap(path, castMapStringToMapInterface(v.aliases)) != "" {
1159
return nil
1160
}
1161
1162
// if the requested key is an alias, then return the proper key
1163
lcaseKey = v.realKey(lcaseKey)
1164
path = strings.Split(lcaseKey, v.keyDelim)
1165
nested = len(path) > 1
1166
1167
// Set() override first
1168
val = v.searchMap(v.override, path)
1169
if val != nil {
1170
return val
1171
}
1172
if nested && v.isPathShadowedInDeepMap(path, v.override) != "" {
1173
return nil
1174
}
1175
1176
// PFlag override next
1177
flag, exists := v.pflags[lcaseKey]
1178
if exists && flag.HasChanged() {
1179
switch flag.ValueType() {
1180
case "int", "int8", "int16", "int32", "int64":
1181
return cast.ToInt(flag.ValueString())
1182
case "bool":
1183
return cast.ToBool(flag.ValueString())
1184
case "stringSlice", "stringArray":
1185
s := strings.TrimPrefix(flag.ValueString(), "[")
1186
s = strings.TrimSuffix(s, "]")
1187
res, _ := readAsCSV(s)
1188
return res
1189
case "boolSlice":
1190
s := strings.TrimPrefix(flag.ValueString(), "[")
1191
s = strings.TrimSuffix(s, "]")
1192
res, _ := readAsCSV(s)
1193
return cast.ToBoolSlice(res)
1194
case "intSlice":
1195
s := strings.TrimPrefix(flag.ValueString(), "[")
1196
s = strings.TrimSuffix(s, "]")
1197
res, _ := readAsCSV(s)
1198
return cast.ToIntSlice(res)
1199
case "uintSlice":
1200
s := strings.TrimPrefix(flag.ValueString(), "[")
1201
s = strings.TrimSuffix(s, "]")
1202
res, _ := readAsCSV(s)
1203
return cast.ToUintSlice(res)
1204
case "float64Slice":
1205
s := strings.TrimPrefix(flag.ValueString(), "[")
1206
s = strings.TrimSuffix(s, "]")
1207
res, _ := readAsCSV(s)
1208
return cast.ToFloat64Slice(res)
1209
case "durationSlice":
1210
s := strings.TrimPrefix(flag.ValueString(), "[")
1211
s = strings.TrimSuffix(s, "]")
1212
slice := strings.Split(s, ",")
1213
return cast.ToDurationSlice(slice)
1214
case "stringToString":
1215
return stringToStringConv(flag.ValueString())
1216
case "stringToInt":
1217
return stringToIntConv(flag.ValueString())
1218
default:
1219
return flag.ValueString()
1220
}
1221
}
1222
if nested && v.isPathShadowedInFlatMap(path, v.pflags) != "" {
1223
return nil
1224
}
1225
1226
// Env override next
1227
if v.automaticEnvApplied {
1228
envKey := strings.Join(append(v.parents, lcaseKey), ".")
1229
// even if it hasn't been registered, if automaticEnv is used,
1230
// check any Get request
1231
if val, ok := v.getEnv(v.mergeWithEnvPrefix(envKey)); ok {
1232
return val
1233
}
1234
if nested && v.isPathShadowedInAutoEnv(path) != "" {
1235
return nil
1236
}
1237
}
1238
envkeys, exists := v.env[lcaseKey]
1239
if exists {
1240
for _, envkey := range envkeys {
1241
if val, ok := v.getEnv(envkey); ok {
1242
return val
1243
}
1244
}
1245
}
1246
if nested && v.isPathShadowedInFlatMap(path, v.env) != "" {
1247
return nil
1248
}
1249
1250
// Config file next
1251
val = v.searchIndexableWithPathPrefixes(v.config, path)
1252
if val != nil {
1253
return val
1254
}
1255
if nested && v.isPathShadowedInDeepMap(path, v.config) != "" {
1256
return nil
1257
}
1258
1259
// K/V store next
1260
val = v.searchMap(v.kvstore, path)
1261
if val != nil {
1262
return val
1263
}
1264
if nested && v.isPathShadowedInDeepMap(path, v.kvstore) != "" {
1265
return nil
1266
}
1267
1268
// Default next
1269
val = v.searchMap(v.defaults, path)
1270
if val != nil {
1271
return val
1272
}
1273
if nested && v.isPathShadowedInDeepMap(path, v.defaults) != "" {
1274
return nil
1275
}
1276
1277
if flagDefault {
1278
// last chance: if no value is found and a flag does exist for the key,
1279
// get the flag's default value even if the flag's value has not been set.
1280
if flag, exists := v.pflags[lcaseKey]; exists {
1281
switch flag.ValueType() {
1282
case "int", "int8", "int16", "int32", "int64":
1283
return cast.ToInt(flag.ValueString())
1284
case "bool":
1285
return cast.ToBool(flag.ValueString())
1286
case "stringSlice", "stringArray":
1287
s := strings.TrimPrefix(flag.ValueString(), "[")
1288
s = strings.TrimSuffix(s, "]")
1289
res, _ := readAsCSV(s)
1290
return res
1291
case "boolSlice":
1292
s := strings.TrimPrefix(flag.ValueString(), "[")
1293
s = strings.TrimSuffix(s, "]")
1294
res, _ := readAsCSV(s)
1295
return cast.ToBoolSlice(res)
1296
case "intSlice":
1297
s := strings.TrimPrefix(flag.ValueString(), "[")
1298
s = strings.TrimSuffix(s, "]")
1299
res, _ := readAsCSV(s)
1300
return cast.ToIntSlice(res)
1301
case "uintSlice":
1302
s := strings.TrimPrefix(flag.ValueString(), "[")
1303
s = strings.TrimSuffix(s, "]")
1304
res, _ := readAsCSV(s)
1305
return cast.ToUintSlice(res)
1306
case "float64Slice":
1307
s := strings.TrimPrefix(flag.ValueString(), "[")
1308
s = strings.TrimSuffix(s, "]")
1309
res, _ := readAsCSV(s)
1310
return cast.ToFloat64Slice(res)
1311
case "stringToString":
1312
return stringToStringConv(flag.ValueString())
1313
case "stringToInt":
1314
return stringToIntConv(flag.ValueString())
1315
case "durationSlice":
1316
s := strings.TrimPrefix(flag.ValueString(), "[")
1317
s = strings.TrimSuffix(s, "]")
1318
slice := strings.Split(s, ",")
1319
return cast.ToDurationSlice(slice)
1320
default:
1321
return flag.ValueString()
1322
}
1323
}
1324
// last item, no need to check shadowing
1325
}
1326
1327
return nil
1328
}
1329
1330
func readAsCSV(val string) ([]string, error) {
1331
if val == "" {
1332
return []string{}, nil
1333
}
1334
stringReader := strings.NewReader(val)
1335
csvReader := csv.NewReader(stringReader)
1336
return csvReader.Read()
1337
}
1338
1339
// mostly copied from pflag's implementation of this operation here https://github.com/spf13/pflag/blob/master/string_to_string.go#L79
1340
// alterations are: errors are swallowed, map[string]any is returned in order to enable cast.ToStringMap.
1341
func stringToStringConv(val string) any {
1342
val = strings.Trim(val, "[]")
1343
// An empty string would cause an empty map
1344
if val == "" {
1345
return map[string]any{}
1346
}
1347
r := csv.NewReader(strings.NewReader(val))
1348
ss, err := r.Read()
1349
if err != nil {
1350
return nil
1351
}
1352
out := make(map[string]any, len(ss))
1353
for _, pair := range ss {
1354
k, vv, found := strings.Cut(pair, "=")
1355
if !found {
1356
return nil
1357
}
1358
out[k] = vv
1359
}
1360
return out
1361
}
1362
1363
// mostly copied from pflag's implementation of this operation here https://github.com/spf13/pflag/blob/d5e0c0615acee7028e1e2740a11102313be88de1/string_to_int.go#L68
1364
// alterations are: errors are swallowed, map[string]any is returned in order to enable cast.ToStringMap.
1365
func stringToIntConv(val string) any {
1366
val = strings.Trim(val, "[]")
1367
// An empty string would cause an empty map
1368
if val == "" {
1369
return map[string]any{}
1370
}
1371
ss := strings.Split(val, ",")
1372
out := make(map[string]any, len(ss))
1373
for _, pair := range ss {
1374
k, vv, found := strings.Cut(pair, "=")
1375
if !found {
1376
return nil
1377
}
1378
var err error
1379
out[k], err = strconv.Atoi(vv)
1380
if err != nil {
1381
return nil
1382
}
1383
}
1384
return out
1385
}
1386
1387
// IsSet checks to see if the key has been set in any of the data locations.
1388
// IsSet is case-insensitive for a key.
1389
func IsSet(key string) bool { return v.IsSet(key) }
1390
1391
func (v *Viper) IsSet(key string) bool {
1392
lcaseKey := strings.ToLower(key)
1393
val := v.find(lcaseKey, false)
1394
return val != nil
1395
}
1396
1397
// AutomaticEnv makes Viper check if environment variables match any of the existing keys
1398
// (config, default or flags). If matching env vars are found, they are loaded into Viper.
1399
func AutomaticEnv() { v.AutomaticEnv() }
1400
1401
func (v *Viper) AutomaticEnv() {
1402
v.automaticEnvApplied = true
1403
}
1404
1405
// SetEnvKeyReplacer sets the strings.Replacer on the viper object
1406
// Useful for mapping an environmental variable to a key that does
1407
// not match it.
1408
func SetEnvKeyReplacer(r *strings.Replacer) { v.SetEnvKeyReplacer(r) }
1409
1410
func (v *Viper) SetEnvKeyReplacer(r *strings.Replacer) {
1411
v.envKeyReplacer = r
1412
}
1413
1414
// RegisterAlias creates an alias that provides another accessor for the same key.
1415
// This enables one to change a name without breaking the application.
1416
func RegisterAlias(alias, key string) { v.RegisterAlias(alias, key) }
1417
1418
func (v *Viper) RegisterAlias(alias, key string) {
1419
v.registerAlias(alias, strings.ToLower(key))
1420
}
1421
1422
func (v *Viper) registerAlias(alias, key string) {
1423
alias = strings.ToLower(alias)
1424
if alias != key && alias != v.realKey(key) {
1425
_, exists := v.aliases[alias]
1426
1427
if !exists {
1428
// if we alias something that exists in one of the maps to another
1429
// name, we'll never be able to get that value using the original
1430
// name, so move the config value to the new realkey.
1431
if val, ok := v.config[alias]; ok {
1432
delete(v.config, alias)
1433
v.config[key] = val
1434
}
1435
if val, ok := v.kvstore[alias]; ok {
1436
delete(v.kvstore, alias)
1437
v.kvstore[key] = val
1438
}
1439
if val, ok := v.defaults[alias]; ok {
1440
delete(v.defaults, alias)
1441
v.defaults[key] = val
1442
}
1443
if val, ok := v.override[alias]; ok {
1444
delete(v.override, alias)
1445
v.override[key] = val
1446
}
1447
v.aliases[alias] = key
1448
}
1449
} else {
1450
v.logger.Warn("creating circular reference alias", "alias", alias, "key", key, "real_key", v.realKey(key))
1451
}
1452
}
1453
1454
func (v *Viper) realKey(key string) string {
1455
newkey, exists := v.aliases[key]
1456
if exists {
1457
v.logger.Debug("key is an alias", "alias", key, "to", newkey)
1458
1459
return v.realKey(newkey)
1460
}
1461
return key
1462
}
1463
1464
// InConfig checks to see if the given key (or an alias) is in the config file.
1465
func InConfig(key string) bool { return v.InConfig(key) }
1466
1467
func (v *Viper) InConfig(key string) bool {
1468
lcaseKey := strings.ToLower(key)
1469
1470
// if the requested key is an alias, then return the proper key
1471
lcaseKey = v.realKey(lcaseKey)
1472
path := strings.Split(lcaseKey, v.keyDelim)
1473
1474
return v.searchIndexableWithPathPrefixes(v.config, path) != nil
1475
}
1476
1477
// SetDefault sets the default value for this key.
1478
// SetDefault is case-insensitive for a key.
1479
// Default only used when no value is provided by the user via flag, config or ENV.
1480
func SetDefault(key string, value any) { v.SetDefault(key, value) }
1481
1482
func (v *Viper) SetDefault(key string, value any) {
1483
// If alias passed in, then set the proper default
1484
key = v.realKey(strings.ToLower(key))
1485
value = toCaseInsensitiveValue(value)
1486
1487
path := strings.Split(key, v.keyDelim)
1488
lastKey := strings.ToLower(path[len(path)-1])
1489
deepestMap := deepSearch(v.defaults, path[0:len(path)-1])
1490
1491
// set innermost value
1492
deepestMap[lastKey] = value
1493
}
1494
1495
// Set sets the value for the key in the override register.
1496
// Set is case-insensitive for a key.
1497
// Will be used instead of values obtained via
1498
// flags, config file, ENV, default, or key/value store.
1499
func Set(key string, value any) { v.Set(key, value) }
1500
1501
func (v *Viper) Set(key string, value any) {
1502
// If alias passed in, then set the proper override
1503
key = v.realKey(strings.ToLower(key))
1504
value = toCaseInsensitiveValue(value)
1505
1506
path := strings.Split(key, v.keyDelim)
1507
lastKey := strings.ToLower(path[len(path)-1])
1508
deepestMap := deepSearch(v.override, path[0:len(path)-1])
1509
1510
// set innermost value
1511
deepestMap[lastKey] = value
1512
}
1513
1514
// ReadInConfig will discover and load the configuration file from disk
1515
// and key/value stores, searching in one of the defined paths.
1516
func ReadInConfig() error { return v.ReadInConfig() }
1517
1518
func (v *Viper) ReadInConfig() error {
1519
v.logger.Info("attempting to read in config file")
1520
filename, err := v.getConfigFile()
1521
if err != nil {
1522
return err
1523
}
1524
1525
if !slices.Contains(SupportedExts, v.getConfigType()) {
1526
return UnsupportedConfigError(v.getConfigType())
1527
}
1528
1529
v.logger.Debug("reading file", "file", filename)
1530
file, err := afero.ReadFile(v.fs, filename)
1531
if err != nil {
1532
return err
1533
}
1534
1535
config := make(map[string]any)
1536
1537
err = v.unmarshalReader(bytes.NewReader(file), config)
1538
if err != nil {
1539
return err
1540
}
1541
1542
v.config = config
1543
return nil
1544
}
1545
1546
// MergeInConfig merges a new configuration with an existing config.
1547
func MergeInConfig() error { return v.MergeInConfig() }
1548
1549
func (v *Viper) MergeInConfig() error {
1550
v.logger.Info("attempting to merge in config file")
1551
filename, err := v.getConfigFile()
1552
if err != nil {
1553
return err
1554
}
1555
1556
if !slices.Contains(SupportedExts, v.getConfigType()) {
1557
return UnsupportedConfigError(v.getConfigType())
1558
}
1559
1560
file, err := afero.ReadFile(v.fs, filename)
1561
if err != nil {
1562
return err
1563
}
1564
1565
return v.MergeConfig(bytes.NewReader(file))
1566
}
1567
1568
// ReadConfig will read a configuration file, setting existing keys to nil if the
1569
// key does not exist in the file.
1570
func ReadConfig(in io.Reader) error { return v.ReadConfig(in) }
1571
1572
func (v *Viper) ReadConfig(in io.Reader) error {
1573
config := make(map[string]any)
1574
1575
err := v.unmarshalReader(in, config)
1576
if err != nil {
1577
return err
1578
}
1579
1580
v.config = config
1581
1582
return nil
1583
}
1584
1585
// MergeConfig merges a new configuration with an existing config.
1586
func MergeConfig(in io.Reader) error { return v.MergeConfig(in) }
1587
1588
func (v *Viper) MergeConfig(in io.Reader) error {
1589
config := make(map[string]any)
1590
1591
if err := v.unmarshalReader(in, config); err != nil {
1592
return err
1593
}
1594
1595
return v.MergeConfigMap(config)
1596
}
1597
1598
// MergeConfigMap merges the configuration from the map given with an existing config.
1599
// Note that the map given may be modified.
1600
func MergeConfigMap(cfg map[string]any) error { return v.MergeConfigMap(cfg) }
1601
1602
func (v *Viper) MergeConfigMap(cfg map[string]any) error {
1603
if v.config == nil {
1604
v.config = make(map[string]any)
1605
}
1606
insensitiviseMap(cfg)
1607
mergeMaps(cfg, v.config, nil)
1608
return nil
1609
}
1610
1611
// WriteConfig writes the current configuration to a file.
1612
func WriteConfig() error { return v.WriteConfig() }
1613
1614
func (v *Viper) WriteConfig() error {
1615
filename, err := v.getConfigFile()
1616
if err != nil {
1617
return err
1618
}
1619
return v.writeConfig(filename, true)
1620
}
1621
1622
// SafeWriteConfig writes current configuration to file only if the file does not exist.
1623
func SafeWriteConfig() error { return v.SafeWriteConfig() }
1624
1625
func (v *Viper) SafeWriteConfig() error {
1626
if len(v.configPaths) < 1 {
1627
return errors.New("missing configuration for 'configPath'")
1628
}
1629
return v.SafeWriteConfigAs(filepath.Join(v.configPaths[0], v.configName+"."+v.configType))
1630
}
1631
1632
// WriteConfigAs writes current configuration to a given filename.
1633
func WriteConfigAs(filename string) error { return v.WriteConfigAs(filename) }
1634
1635
func (v *Viper) WriteConfigAs(filename string) error {
1636
return v.writeConfig(filename, true)
1637
}
1638
1639
// WriteConfigTo writes current configuration to an [io.Writer].
1640
func WriteConfigTo(w io.Writer) error { return v.WriteConfigTo(w) }
1641
1642
func (v *Viper) WriteConfigTo(w io.Writer) error {
1643
format := strings.ToLower(v.getConfigType())
1644
1645
if !slices.Contains(SupportedExts, format) {
1646
return UnsupportedConfigError(format)
1647
}
1648
1649
return v.marshalWriter(w, format)
1650
}
1651
1652
// SafeWriteConfigAs writes current configuration to a given filename if it does not exist.
1653
func SafeWriteConfigAs(filename string) error { return v.SafeWriteConfigAs(filename) }
1654
1655
func (v *Viper) SafeWriteConfigAs(filename string) error {
1656
alreadyExists, err := afero.Exists(v.fs, filename)
1657
if alreadyExists && err == nil {
1658
return ConfigFileAlreadyExistsError(filename)
1659
}
1660
return v.writeConfig(filename, false)
1661
}
1662
1663
func (v *Viper) writeConfig(filename string, force bool) error {
1664
v.logger.Info("attempting to write configuration to file")
1665
1666
var configType string
1667
1668
ext := filepath.Ext(filename)
1669
if ext != "" && ext != filepath.Base(filename) {
1670
configType = ext[1:]
1671
} else {
1672
configType = v.configType
1673
}
1674
if configType == "" {
1675
return fmt.Errorf("config type could not be determined for %s", filename)
1676
}
1677
1678
if !slices.Contains(SupportedExts, configType) {
1679
return UnsupportedConfigError(configType)
1680
}
1681
if v.config == nil {
1682
v.config = make(map[string]any)
1683
}
1684
flags := os.O_CREATE | os.O_TRUNC | os.O_WRONLY
1685
if !force {
1686
flags |= os.O_EXCL
1687
}
1688
f, err := v.fs.OpenFile(filename, flags, v.configPermissions)
1689
if err != nil {
1690
return err
1691
}
1692
defer f.Close()
1693
1694
if err := v.marshalWriter(f, configType); err != nil {
1695
return err
1696
}
1697
1698
return f.Sync()
1699
}
1700
1701
func (v *Viper) unmarshalReader(in io.Reader, c map[string]any) error {
1702
format := strings.ToLower(v.getConfigType())
1703
if format == "" {
1704
return errors.New("cannot decode configuration: unable to determine config type")
1705
}
1706
1707
buf := new(bytes.Buffer)
1708
_, err := buf.ReadFrom(in)
1709
if err != nil {
1710
return fmt.Errorf("failed to read configuration from input: %w", err)
1711
}
1712
1713
// TODO: remove this once SupportedExts is deprecated/removed
1714
if !slices.Contains(SupportedExts, format) {
1715
return UnsupportedConfigError(format)
1716
}
1717
1718
// TODO: return [UnsupportedConfigError] if the registry does not contain the format
1719
// TODO: consider deprecating this error type
1720
decoder, err := v.decoderRegistry.Decoder(format)
1721
if err != nil {
1722
return ConfigParseError{err}
1723
}
1724
1725
err = decoder.Decode(buf.Bytes(), c)
1726
if err != nil {
1727
return ConfigParseError{err}
1728
}
1729
1730
insensitiviseMap(c)
1731
return nil
1732
}
1733
1734
// Marshal a map into Writer.
1735
func (v *Viper) marshalWriter(w io.Writer, configType string) error {
1736
c := v.AllSettings()
1737
1738
encoder, err := v.encoderRegistry.Encoder(configType)
1739
if err != nil {
1740
return ConfigMarshalError{err}
1741
}
1742
1743
b, err := encoder.Encode(c)
1744
if err != nil {
1745
return ConfigMarshalError{err}
1746
}
1747
1748
_, err = w.Write(b)
1749
if err != nil {
1750
return ConfigMarshalError{err}
1751
}
1752
1753
return nil
1754
}
1755
1756
func keyExists(k string, m map[string]any) string {
1757
lk := strings.ToLower(k)
1758
for mk := range m {
1759
lmk := strings.ToLower(mk)
1760
if lmk == lk {
1761
return mk
1762
}
1763
}
1764
return ""
1765
}
1766
1767
func castToMapStringInterface(
1768
src map[any]any,
1769
) map[string]any {
1770
tgt := map[string]any{}
1771
for k, v := range src {
1772
tgt[fmt.Sprintf("%v", k)] = v
1773
}
1774
return tgt
1775
}
1776
1777
func castMapStringSliceToMapInterface(src map[string][]string) map[string]any {
1778
tgt := map[string]any{}
1779
for k, v := range src {
1780
tgt[k] = v
1781
}
1782
return tgt
1783
}
1784
1785
func castMapStringToMapInterface(src map[string]string) map[string]any {
1786
tgt := map[string]any{}
1787
for k, v := range src {
1788
tgt[k] = v
1789
}
1790
return tgt
1791
}
1792
1793
func castMapFlagToMapInterface(src map[string]FlagValue) map[string]any {
1794
tgt := map[string]any{}
1795
for k, v := range src {
1796
tgt[k] = v
1797
}
1798
return tgt
1799
}
1800
1801
// mergeMaps merges two maps. The `itgt` parameter is for handling go-yaml's
1802
// insistence on parsing nested structures as `map[any]any`
1803
// instead of using a `string` as the key for nest structures beyond one level
1804
// deep. Both map types are supported as there is a go-yaml fork that uses
1805
// `map[string]any` instead.
1806
func mergeMaps(src, tgt map[string]any, itgt map[any]any) {
1807
for sk, sv := range src {
1808
tk := keyExists(sk, tgt)
1809
if tk == "" {
1810
v.logger.Debug("", "tk", "\"\"", fmt.Sprintf("tgt[%s]", sk), sv)
1811
tgt[sk] = sv
1812
if itgt != nil {
1813
itgt[sk] = sv
1814
}
1815
continue
1816
}
1817
1818
tv, ok := tgt[tk]
1819
if !ok {
1820
v.logger.Debug("", fmt.Sprintf("ok[%s]", tk), false, fmt.Sprintf("tgt[%s]", sk), sv)
1821
tgt[sk] = sv
1822
if itgt != nil {
1823
itgt[sk] = sv
1824
}
1825
continue
1826
}
1827
1828
svType := reflect.TypeOf(sv)
1829
tvType := reflect.TypeOf(tv)
1830
1831
v.logger.Debug(
1832
"processing",
1833
"key", sk,
1834
"st", svType,
1835
"tt", tvType,
1836
"sv", sv,
1837
"tv", tv,
1838
)
1839
1840
switch ttv := tv.(type) {
1841
case map[any]any:
1842
v.logger.Debug("merging maps (must convert)")
1843
tsv, ok := sv.(map[any]any)
1844
if !ok {
1845
v.logger.Error(
1846
"Could not cast sv to map[any]any",
1847
"key", sk,
1848
"st", svType,
1849
"tt", tvType,
1850
"sv", sv,
1851
"tv", tv,
1852
)
1853
continue
1854
}
1855
1856
ssv := castToMapStringInterface(tsv)
1857
stv := castToMapStringInterface(ttv)
1858
mergeMaps(ssv, stv, ttv)
1859
case map[string]any:
1860
v.logger.Debug("merging maps")
1861
tsv, ok := sv.(map[string]any)
1862
if !ok {
1863
v.logger.Error(
1864
"Could not cast sv to map[string]any",
1865
"key", sk,
1866
"st", svType,
1867
"tt", tvType,
1868
"sv", sv,
1869
"tv", tv,
1870
)
1871
continue
1872
}
1873
mergeMaps(tsv, ttv, nil)
1874
default:
1875
v.logger.Debug("setting value")
1876
tgt[tk] = sv
1877
if itgt != nil {
1878
itgt[tk] = sv
1879
}
1880
}
1881
}
1882
}
1883
1884
// AllKeys returns all keys holding a value, regardless of where they are set.
1885
// Nested keys are returned with a v.keyDelim separator.
1886
func AllKeys() []string { return v.AllKeys() }
1887
1888
func (v *Viper) AllKeys() []string {
1889
m := map[string]bool{}
1890
// add all paths, by order of descending priority to ensure correct shadowing
1891
m = v.flattenAndMergeMap(m, castMapStringToMapInterface(v.aliases), "")
1892
m = v.flattenAndMergeMap(m, v.override, "")
1893
m = v.mergeFlatMap(m, castMapFlagToMapInterface(v.pflags))
1894
m = v.mergeFlatMap(m, castMapStringSliceToMapInterface(v.env))
1895
m = v.flattenAndMergeMap(m, v.config, "")
1896
m = v.flattenAndMergeMap(m, v.kvstore, "")
1897
m = v.flattenAndMergeMap(m, v.defaults, "")
1898
1899
// convert set of paths to list
1900
a := make([]string, 0, len(m))
1901
for x := range m {
1902
a = append(a, x)
1903
}
1904
return a
1905
}
1906
1907
// flattenAndMergeMap recursively flattens the given map into a map[string]bool
1908
// of key paths (used as a set, easier to manipulate than a []string):
1909
// - each path is merged into a single key string, delimited with v.keyDelim
1910
// - if a path is shadowed by an earlier value in the initial shadow map,
1911
// it is skipped.
1912
//
1913
// The resulting set of paths is merged to the given shadow set at the same time.
1914
func (v *Viper) flattenAndMergeMap(shadow map[string]bool, m map[string]any, prefix string) map[string]bool {
1915
if shadow != nil && prefix != "" && shadow[prefix] {
1916
// prefix is shadowed => nothing more to flatten
1917
return shadow
1918
}
1919
if shadow == nil {
1920
shadow = make(map[string]bool)
1921
}
1922
1923
var m2 map[string]any
1924
if prefix != "" {
1925
prefix += v.keyDelim
1926
}
1927
for k, val := range m {
1928
fullKey := prefix + k
1929
switch val := val.(type) {
1930
case map[string]any:
1931
m2 = val
1932
case map[any]any:
1933
m2 = cast.ToStringMap(val)
1934
default:
1935
// immediate value
1936
shadow[strings.ToLower(fullKey)] = true
1937
continue
1938
}
1939
// recursively merge to shadow map
1940
shadow = v.flattenAndMergeMap(shadow, m2, fullKey)
1941
}
1942
return shadow
1943
}
1944
1945
// mergeFlatMap merges the given maps, excluding values of the second map
1946
// shadowed by values from the first map.
1947
func (v *Viper) mergeFlatMap(shadow map[string]bool, m map[string]any) map[string]bool {
1948
// scan keys
1949
outer:
1950
for k := range m {
1951
path := strings.Split(k, v.keyDelim)
1952
// scan intermediate paths
1953
var parentKey string
1954
for i := 1; i < len(path); i++ {
1955
parentKey = strings.Join(path[0:i], v.keyDelim)
1956
if shadow[parentKey] {
1957
// path is shadowed, continue
1958
continue outer
1959
}
1960
}
1961
// add key
1962
shadow[strings.ToLower(k)] = true
1963
}
1964
return shadow
1965
}
1966
1967
// AllSettings merges all settings and returns them as a map[string]any.
1968
func AllSettings() map[string]any { return v.AllSettings() }
1969
1970
func (v *Viper) AllSettings() map[string]any {
1971
return v.getSettings(v.AllKeys())
1972
}
1973
1974
func (v *Viper) getSettings(keys []string) map[string]any {
1975
m := map[string]any{}
1976
// start from the list of keys, and construct the map one value at a time
1977
for _, k := range keys {
1978
value := v.Get(k)
1979
if value == nil {
1980
// should not happen, since AllKeys() returns only keys holding a value,
1981
// check just in case anything changes
1982
continue
1983
}
1984
path := strings.Split(k, v.keyDelim)
1985
lastKey := strings.ToLower(path[len(path)-1])
1986
deepestMap := deepSearch(m, path[0:len(path)-1])
1987
// set innermost value
1988
deepestMap[lastKey] = value
1989
}
1990
return m
1991
}
1992
1993
// SetFs sets the filesystem to use to read configuration.
1994
func SetFs(fs afero.Fs) { v.SetFs(fs) }
1995
1996
func (v *Viper) SetFs(fs afero.Fs) {
1997
v.fs = fs
1998
}
1999
2000
// SetConfigName sets name for the config file.
2001
// Does not include extension.
2002
func SetConfigName(in string) { v.SetConfigName(in) }
2003
2004
func (v *Viper) SetConfigName(in string) {
2005
if v.finder != nil {
2006
v.logger.Warn("ineffective call to function: custom finder takes precedence", slog.String("function", "SetConfigName"))
2007
}
2008
2009
if in != "" {
2010
v.configName = in
2011
v.configFile = ""
2012
}
2013
}
2014
2015
// SetConfigType sets the type of the configuration returned by the
2016
// remote source, e.g. "json".
2017
func SetConfigType(in string) { v.SetConfigType(in) }
2018
2019
func (v *Viper) SetConfigType(in string) {
2020
if in != "" {
2021
v.configType = in
2022
}
2023
}
2024
2025
// SetConfigPermissions sets the permissions for the config file.
2026
func SetConfigPermissions(perm os.FileMode) { v.SetConfigPermissions(perm) }
2027
2028
func (v *Viper) SetConfigPermissions(perm os.FileMode) {
2029
v.configPermissions = perm.Perm()
2030
}
2031
2032
func (v *Viper) getConfigType() string {
2033
if v.configType != "" {
2034
return v.configType
2035
}
2036
2037
cf, err := v.getConfigFile()
2038
if err != nil {
2039
return ""
2040
}
2041
2042
ext := filepath.Ext(cf)
2043
2044
if len(ext) > 1 {
2045
return ext[1:]
2046
}
2047
2048
return ""
2049
}
2050
2051
func (v *Viper) getConfigFile() (string, error) {
2052
if v.configFile == "" {
2053
cf, err := v.findConfigFile()
2054
if err != nil {
2055
return "", err
2056
}
2057
v.configFile = cf
2058
}
2059
return v.configFile, nil
2060
}
2061
2062
// Debug prints all configuration registries for debugging
2063
// purposes.
2064
func Debug() { v.Debug() }
2065
func DebugTo(w io.Writer) { v.DebugTo(w) }
2066
2067
func (v *Viper) Debug() { v.DebugTo(os.Stdout) }
2068
2069
func (v *Viper) DebugTo(w io.Writer) {
2070
fmt.Fprintf(w, "Aliases:\n%#v\n", v.aliases)
2071
fmt.Fprintf(w, "Override:\n%#v\n", v.override)
2072
fmt.Fprintf(w, "PFlags:\n%#v\n", v.pflags)
2073
fmt.Fprintf(w, "Env:\n%#v\n", v.env)
2074
fmt.Fprintf(w, "Key/Value Store:\n%#v\n", v.kvstore)
2075
fmt.Fprintf(w, "Config:\n%#v\n", v.config)
2076
fmt.Fprintf(w, "Defaults:\n%#v\n", v.defaults)
2077
}
2078
2079