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