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