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