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