github.com/biasys/viper@v1.0.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 a 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 "fmt" 26 "io" 27 "log" 28 "os" 29 "path/filepath" 30 "reflect" 31 "strings" 32 "time" 33 34 "github.com/fsnotify/fsnotify" 35 "github.com/mitchellh/mapstructure" 36 "github.com/spf13/afero" 37 "github.com/spf13/cast" 38 jww "github.com/spf13/jwalterweatherman" 39 "github.com/spf13/pflag" 40 ) 41 42 var v *Viper 43 44 type RemoteResponse struct { 45 Value []byte 46 Error error 47 } 48 49 func init() { 50 v = New() 51 } 52 53 type remoteConfigFactory interface { 54 Get(rp RemoteProvider) (io.Reader, error) 55 Watch(rp RemoteProvider) (io.Reader, error) 56 WatchChannel(rp RemoteProvider) (<-chan *RemoteResponse, chan bool) 57 } 58 59 // RemoteConfig is optional, see the remote package 60 var RemoteConfig remoteConfigFactory 61 62 // UnsupportedConfigError denotes encountering an unsupported 63 // configuration filetype. 64 type UnsupportedConfigError string 65 66 // Error returns the formatted configuration error. 67 func (str UnsupportedConfigError) Error() string { 68 return fmt.Sprintf("Unsupported Config Type %q", string(str)) 69 } 70 71 // UnsupportedRemoteProviderError denotes encountering an unsupported remote 72 // provider. Currently only etcd and Consul are supported. 73 type UnsupportedRemoteProviderError string 74 75 // Error returns the formatted remote provider error. 76 func (str UnsupportedRemoteProviderError) Error() string { 77 return fmt.Sprintf("Unsupported Remote Provider Type %q", string(str)) 78 } 79 80 // RemoteConfigError denotes encountering an error while trying to 81 // pull the configuration from the remote provider. 82 type RemoteConfigError string 83 84 // Error returns the formatted remote provider error 85 func (rce RemoteConfigError) Error() string { 86 return fmt.Sprintf("Remote Configurations Error: %s", string(rce)) 87 } 88 89 // ConfigFileNotFoundError denotes failing to find configuration file. 90 type ConfigFileNotFoundError struct { 91 name, locations string 92 } 93 94 // Error returns the formatted configuration error. 95 func (fnfe ConfigFileNotFoundError) Error() string { 96 return fmt.Sprintf("Config File %q Not Found in %q", fnfe.name, fnfe.locations) 97 } 98 99 // Viper is a prioritized configuration registry. It 100 // maintains a set of configuration sources, fetches 101 // values to populate those, and provides them according 102 // to the source's priority. 103 // The priority of the sources is the following: 104 // 1. overrides 105 // 2. flags 106 // 3. env. variables 107 // 4. config file 108 // 5. key/value store 109 // 6. defaults 110 // 111 // For example, if values from the following sources were loaded: 112 // 113 // Defaults : { 114 // "secret": "", 115 // "user": "default", 116 // "endpoint": "https://localhost" 117 // } 118 // Config : { 119 // "user": "root" 120 // "secret": "defaultsecret" 121 // } 122 // Env : { 123 // "secret": "somesecretkey" 124 // } 125 // 126 // The resulting config will have the following values: 127 // 128 // { 129 // "secret": "somesecretkey", 130 // "user": "root", 131 // "endpoint": "https://localhost" 132 // } 133 type Viper struct { 134 // Delimiter that separates a list of keys 135 // used to access a nested value in one go 136 keyDelim string 137 138 // A set of paths to look for the config file in 139 configPaths []string 140 141 // The filesystem to read config from. 142 fs afero.Fs 143 144 // A set of remote providers to search for the configuration 145 remoteProviders []*defaultRemoteProvider 146 147 // Name of file to look for inside the path 148 configName string 149 configFile string 150 configType string 151 envPrefix string 152 153 automaticEnvApplied bool 154 envKeyReplacer *strings.Replacer 155 156 config map[string]interface{} 157 override map[string]interface{} 158 defaults map[string]interface{} 159 kvstore map[string]interface{} 160 pflags map[string]FlagValue 161 env map[string]string 162 aliases map[string]string 163 typeByDefValue bool 164 165 onConfigChange func(fsnotify.Event) 166 } 167 168 // New returns an initialized Viper instance. 169 func New() *Viper { 170 v := new(Viper) 171 v.keyDelim = "." 172 v.configName = "config" 173 v.fs = afero.NewOsFs() 174 v.config = make(map[string]interface{}) 175 v.override = make(map[string]interface{}) 176 v.defaults = make(map[string]interface{}) 177 v.kvstore = make(map[string]interface{}) 178 v.pflags = make(map[string]FlagValue) 179 v.env = make(map[string]string) 180 v.aliases = make(map[string]string) 181 v.typeByDefValue = false 182 183 return v 184 } 185 186 // Intended for testing, will reset all to default settings. 187 // In the public interface for the viper package so applications 188 // can use it in their testing as well. 189 func Reset() { 190 v = New() 191 SupportedExts = []string{"json", "toml", "yaml", "yml", "hcl"} 192 SupportedRemoteProviders = []string{"etcd", "consul"} 193 } 194 195 type defaultRemoteProvider struct { 196 provider string 197 endpoint string 198 path string 199 secretKeyring string 200 } 201 202 func (rp defaultRemoteProvider) Provider() string { 203 return rp.provider 204 } 205 206 func (rp defaultRemoteProvider) Endpoint() string { 207 return rp.endpoint 208 } 209 210 func (rp defaultRemoteProvider) Path() string { 211 return rp.path 212 } 213 214 func (rp defaultRemoteProvider) SecretKeyring() string { 215 return rp.secretKeyring 216 } 217 218 // RemoteProvider stores the configuration necessary 219 // to connect to a remote key/value store. 220 // Optional secretKeyring to unencrypt encrypted values 221 // can be provided. 222 type RemoteProvider interface { 223 Provider() string 224 Endpoint() string 225 Path() string 226 SecretKeyring() string 227 } 228 229 // SupportedExts are universally supported extensions. 230 var SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl"} 231 232 // SupportedRemoteProviders are universally supported remote providers. 233 var SupportedRemoteProviders = []string{"etcd", "consul"} 234 235 func OnConfigChange(run func(in fsnotify.Event)) { v.OnConfigChange(run) } 236 func (v *Viper) OnConfigChange(run func(in fsnotify.Event)) { 237 v.onConfigChange = run 238 } 239 240 func WatchConfig() { v.WatchConfig() } 241 func (v *Viper) WatchConfig() { 242 go func() { 243 watcher, err := fsnotify.NewWatcher() 244 if err != nil { 245 log.Fatal(err) 246 } 247 defer watcher.Close() 248 249 // we have to watch the entire directory to pick up renames/atomic saves in a cross-platform way 250 filename, err := v.getConfigFile() 251 if err != nil { 252 log.Println("error:", err) 253 return 254 } 255 256 configFile := filepath.Clean(filename) 257 configDir, _ := filepath.Split(configFile) 258 259 done := make(chan bool) 260 go func() { 261 for { 262 select { 263 case event := <-watcher.Events: 264 // we only care about the config file 265 if filepath.Clean(event.Name) == configFile { 266 if event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Create == fsnotify.Create { 267 err := v.ReadInConfig() 268 if err != nil { 269 log.Println("error:", err) 270 } 271 v.onConfigChange(event) 272 } 273 } 274 case err := <-watcher.Errors: 275 log.Println("error:", err) 276 } 277 } 278 }() 279 280 watcher.Add(configDir) 281 <-done 282 }() 283 } 284 285 // SetConfigFile explicitly defines the path, name and extension of the config file. 286 // Viper will use this and not check any of the config paths. 287 func SetConfigFile(in string) { v.SetConfigFile(in) } 288 func (v *Viper) SetConfigFile(in string) { 289 if in != "" { 290 v.configFile = in 291 } 292 } 293 294 // SetEnvPrefix defines a prefix that ENVIRONMENT variables will use. 295 // E.g. if your prefix is "spf", the env registry will look for env 296 // variables that start with "SPF_". 297 func SetEnvPrefix(in string) { v.SetEnvPrefix(in) } 298 func (v *Viper) SetEnvPrefix(in string) { 299 if in != "" { 300 v.envPrefix = in 301 } 302 } 303 304 func (v *Viper) mergeWithEnvPrefix(in string) string { 305 if v.envPrefix != "" { 306 return strings.ToUpper(v.envPrefix + "_" + in) 307 } 308 309 return strings.ToUpper(in) 310 } 311 312 // TODO: should getEnv logic be moved into find(). Can generalize the use of 313 // rewriting keys many things, Ex: Get('someKey') -> some_key 314 // (camel case to snake case for JSON keys perhaps) 315 316 // getEnv is a wrapper around os.Getenv which replaces characters in the original 317 // key. This allows env vars which have different keys than the config object 318 // keys. 319 func (v *Viper) getEnv(key string) string { 320 if v.envKeyReplacer != nil { 321 key = v.envKeyReplacer.Replace(key) 322 } 323 return os.Getenv(key) 324 } 325 326 // ConfigFileUsed returns the file used to populate the config registry. 327 func ConfigFileUsed() string { return v.ConfigFileUsed() } 328 func (v *Viper) ConfigFileUsed() string { return v.configFile } 329 330 // AddConfigPath adds a path for Viper to search for the config file in. 331 // Can be called multiple times to define multiple search paths. 332 func AddConfigPath(in string) { v.AddConfigPath(in) } 333 func (v *Viper) AddConfigPath(in string) { 334 if in != "" { 335 absin := absPathify(in) 336 jww.INFO.Println("adding", absin, "to paths to search") 337 if !stringInSlice(absin, v.configPaths) { 338 v.configPaths = append(v.configPaths, absin) 339 } 340 } 341 } 342 343 // AddRemoteProvider adds a remote configuration source. 344 // Remote Providers are searched in the order they are added. 345 // provider is a string value, "etcd" or "consul" are currently supported. 346 // endpoint is the url. etcd requires http://ip:port consul requires ip:port 347 // path is the path in the k/v store to retrieve configuration 348 // To retrieve a config file called myapp.json from /configs/myapp.json 349 // you should set path to /configs and set config name (SetConfigName()) to 350 // "myapp" 351 func AddRemoteProvider(provider, endpoint, path string) error { 352 return v.AddRemoteProvider(provider, endpoint, path) 353 } 354 func (v *Viper) AddRemoteProvider(provider, endpoint, path string) error { 355 if !stringInSlice(provider, SupportedRemoteProviders) { 356 return UnsupportedRemoteProviderError(provider) 357 } 358 if provider != "" && endpoint != "" { 359 jww.INFO.Printf("adding %s:%s to remote provider list", provider, endpoint) 360 rp := &defaultRemoteProvider{ 361 endpoint: endpoint, 362 provider: provider, 363 path: path, 364 } 365 if !v.providerPathExists(rp) { 366 v.remoteProviders = append(v.remoteProviders, rp) 367 } 368 } 369 return nil 370 } 371 372 // AddSecureRemoteProvider adds a remote configuration source. 373 // Secure Remote Providers are searched in the order they are added. 374 // provider is a string value, "etcd" or "consul" are currently supported. 375 // endpoint is the url. etcd requires http://ip:port consul requires ip:port 376 // secretkeyring is the filepath to your openpgp secret keyring. e.g. /etc/secrets/myring.gpg 377 // path is the path in the k/v store to retrieve configuration 378 // To retrieve a config file called myapp.json from /configs/myapp.json 379 // you should set path to /configs and set config name (SetConfigName()) to 380 // "myapp" 381 // Secure Remote Providers are implemented with github.com/xordataexchange/crypt 382 func AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error { 383 return v.AddSecureRemoteProvider(provider, endpoint, path, secretkeyring) 384 } 385 386 func (v *Viper) AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error { 387 if !stringInSlice(provider, SupportedRemoteProviders) { 388 return UnsupportedRemoteProviderError(provider) 389 } 390 if provider != "" && endpoint != "" { 391 jww.INFO.Printf("adding %s:%s to remote provider list", provider, endpoint) 392 rp := &defaultRemoteProvider{ 393 endpoint: endpoint, 394 provider: provider, 395 path: path, 396 secretKeyring: secretkeyring, 397 } 398 if !v.providerPathExists(rp) { 399 v.remoteProviders = append(v.remoteProviders, rp) 400 } 401 } 402 return nil 403 } 404 405 func (v *Viper) providerPathExists(p *defaultRemoteProvider) bool { 406 for _, y := range v.remoteProviders { 407 if reflect.DeepEqual(y, p) { 408 return true 409 } 410 } 411 return false 412 } 413 414 // searchMap recursively searches for a value for path in source map. 415 // Returns nil if not found. 416 // Note: This assumes that the path entries and map keys are lower cased. 417 func (v *Viper) searchMap(source map[string]interface{}, path []string) interface{} { 418 if len(path) == 0 { 419 return source 420 } 421 422 next, ok := source[path[0]] 423 if ok { 424 // Fast path 425 if len(path) == 1 { 426 return next 427 } 428 429 // Nested case 430 switch next.(type) { 431 case map[interface{}]interface{}: 432 return v.searchMap(cast.ToStringMap(next), path[1:]) 433 case map[string]interface{}: 434 // Type assertion is safe here since it is only reached 435 // if the type of `next` is the same as the type being asserted 436 return v.searchMap(next.(map[string]interface{}), path[1:]) 437 default: 438 // got a value but nested key expected, return "nil" for not found 439 return nil 440 } 441 } 442 return nil 443 } 444 445 // searchMapWithPathPrefixes recursively searches for a value for path in source map. 446 // 447 // While searchMap() considers each path element as a single map key, this 448 // function searches for, and prioritizes, merged path elements. 449 // e.g., if in the source, "foo" is defined with a sub-key "bar", and "foo.bar" 450 // is also defined, this latter value is returned for path ["foo", "bar"]. 451 // 452 // This should be useful only at config level (other maps may not contain dots 453 // in their keys). 454 // 455 // Note: This assumes that the path entries and map keys are lower cased. 456 func (v *Viper) searchMapWithPathPrefixes(source map[string]interface{}, path []string) interface{} { 457 if len(path) == 0 { 458 return source 459 } 460 461 // search for path prefixes, starting from the longest one 462 for i := len(path); i > 0; i-- { 463 prefixKey := strings.ToLower(strings.Join(path[0:i], v.keyDelim)) 464 465 next, ok := source[prefixKey] 466 if ok { 467 // Fast path 468 if i == len(path) { 469 return next 470 } 471 472 // Nested case 473 var val interface{} 474 switch next.(type) { 475 case map[interface{}]interface{}: 476 val = v.searchMapWithPathPrefixes(cast.ToStringMap(next), path[i:]) 477 case map[string]interface{}: 478 // Type assertion is safe here since it is only reached 479 // if the type of `next` is the same as the type being asserted 480 val = v.searchMapWithPathPrefixes(next.(map[string]interface{}), path[i:]) 481 default: 482 // got a value but nested key expected, do nothing and look for next prefix 483 } 484 if val != nil { 485 return val 486 } 487 } 488 } 489 490 // not found 491 return nil 492 } 493 494 // isPathShadowedInDeepMap makes sure the given path is not shadowed somewhere 495 // on its path in the map. 496 // e.g., if "foo.bar" has a value in the given map, it “shadows” 497 // "foo.bar.baz" in a lower-priority map 498 func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]interface{}) string { 499 var parentVal interface{} 500 for i := 1; i < len(path); i++ { 501 parentVal = v.searchMap(m, path[0:i]) 502 if parentVal == nil { 503 // not found, no need to add more path elements 504 return "" 505 } 506 switch parentVal.(type) { 507 case map[interface{}]interface{}: 508 continue 509 case map[string]interface{}: 510 continue 511 default: 512 // parentVal is a regular value which shadows "path" 513 return strings.Join(path[0:i], v.keyDelim) 514 } 515 } 516 return "" 517 } 518 519 // isPathShadowedInFlatMap makes sure the given path is not shadowed somewhere 520 // in a sub-path of the map. 521 // e.g., if "foo.bar" has a value in the given map, it “shadows” 522 // "foo.bar.baz" in a lower-priority map 523 func (v *Viper) isPathShadowedInFlatMap(path []string, mi interface{}) string { 524 // unify input map 525 var m map[string]interface{} 526 switch mi.(type) { 527 case map[string]string, map[string]FlagValue: 528 m = cast.ToStringMap(mi) 529 default: 530 return "" 531 } 532 533 // scan paths 534 var parentKey string 535 for i := 1; i < len(path); i++ { 536 parentKey = strings.Join(path[0:i], v.keyDelim) 537 if _, ok := m[parentKey]; ok { 538 return parentKey 539 } 540 } 541 return "" 542 } 543 544 // isPathShadowedInAutoEnv makes sure the given path is not shadowed somewhere 545 // in the environment, when automatic env is on. 546 // e.g., if "foo.bar" has a value in the environment, it “shadows” 547 // "foo.bar.baz" in a lower-priority map 548 func (v *Viper) isPathShadowedInAutoEnv(path []string) string { 549 var parentKey string 550 var val string 551 for i := 1; i < len(path); i++ { 552 parentKey = strings.Join(path[0:i], v.keyDelim) 553 if val = v.getEnv(v.mergeWithEnvPrefix(parentKey)); val != "" { 554 return parentKey 555 } 556 } 557 return "" 558 } 559 560 // SetTypeByDefaultValue enables or disables the inference of a key value's 561 // type when the Get function is used based upon a key's default value as 562 // opposed to the value returned based on the normal fetch logic. 563 // 564 // For example, if a key has a default value of []string{} and the same key 565 // is set via an environment variable to "a b c", a call to the Get function 566 // would return a string slice for the key if the key's type is inferred by 567 // the default value and the Get function would return: 568 // 569 // []string {"a", "b", "c"} 570 // 571 // Otherwise the Get function would return: 572 // 573 // "a b c" 574 func SetTypeByDefaultValue(enable bool) { v.SetTypeByDefaultValue(enable) } 575 func (v *Viper) SetTypeByDefaultValue(enable bool) { 576 v.typeByDefValue = enable 577 } 578 579 // GetViper gets the global Viper instance. 580 func GetViper() *Viper { 581 return v 582 } 583 584 // Get can retrieve any value given the key to use. 585 // Get is case-insensitive for a key. 586 // Get has the behavior of returning the value associated with the first 587 // place from where it is set. Viper will check in the following order: 588 // override, flag, env, config file, key/value store, default 589 // 590 // Get returns an interface. For a specific value use one of the Get____ methods. 591 func Get(key string) interface{} { return v.Get(key) } 592 func (v *Viper) Get(key string) interface{} { 593 lcaseKey := strings.ToLower(key) 594 val := v.find(lcaseKey) 595 if val == nil { 596 return nil 597 } 598 599 if v.typeByDefValue { 600 // TODO(bep) this branch isn't covered by a single test. 601 valType := val 602 path := strings.Split(lcaseKey, v.keyDelim) 603 defVal := v.searchMap(v.defaults, path) 604 if defVal != nil { 605 valType = defVal 606 } 607 608 switch valType.(type) { 609 case bool: 610 return cast.ToBool(val) 611 case string: 612 return cast.ToString(val) 613 case int64, int32, int16, int8, int: 614 return cast.ToInt(val) 615 case float64, float32: 616 return cast.ToFloat64(val) 617 case time.Time: 618 return cast.ToTime(val) 619 case time.Duration: 620 return cast.ToDuration(val) 621 case []string: 622 return cast.ToStringSlice(val) 623 } 624 } 625 626 return val 627 } 628 629 // Sub returns new Viper instance representing a sub tree of this instance. 630 // Sub is case-insensitive for a key. 631 func Sub(key string) *Viper { return v.Sub(key) } 632 func (v *Viper) Sub(key string) *Viper { 633 subv := New() 634 data := v.Get(key) 635 if data == nil { 636 return nil 637 } 638 639 if reflect.TypeOf(data).Kind() == reflect.Map { 640 subv.config = cast.ToStringMap(data) 641 return subv 642 } 643 return nil 644 } 645 646 // GetString returns the value associated with the key as a string. 647 func GetString(key string) string { return v.GetString(key) } 648 func (v *Viper) GetString(key string) string { 649 return cast.ToString(v.Get(key)) 650 } 651 652 // GetBool returns the value associated with the key as a boolean. 653 func GetBool(key string) bool { return v.GetBool(key) } 654 func (v *Viper) GetBool(key string) bool { 655 return cast.ToBool(v.Get(key)) 656 } 657 658 // GetInt returns the value associated with the key as an integer. 659 func GetInt(key string) int { return v.GetInt(key) } 660 func (v *Viper) GetInt(key string) int { 661 return cast.ToInt(v.Get(key)) 662 } 663 664 // GetInt64 returns the value associated with the key as an integer. 665 func GetInt64(key string) int64 { return v.GetInt64(key) } 666 func (v *Viper) GetInt64(key string) int64 { 667 return cast.ToInt64(v.Get(key)) 668 } 669 670 // GetFloat64 returns the value associated with the key as a float64. 671 func GetFloat64(key string) float64 { return v.GetFloat64(key) } 672 func (v *Viper) GetFloat64(key string) float64 { 673 return cast.ToFloat64(v.Get(key)) 674 } 675 676 // GetTime returns the value associated with the key as time. 677 func GetTime(key string) time.Time { return v.GetTime(key) } 678 func (v *Viper) GetTime(key string) time.Time { 679 return cast.ToTime(v.Get(key)) 680 } 681 682 // GetDuration returns the value associated with the key as a duration. 683 func GetDuration(key string) time.Duration { return v.GetDuration(key) } 684 func (v *Viper) GetDuration(key string) time.Duration { 685 return cast.ToDuration(v.Get(key)) 686 } 687 688 // GetStringSlice returns the value associated with the key as a slice of strings. 689 func GetStringSlice(key string) []string { return v.GetStringSlice(key) } 690 func (v *Viper) GetStringSlice(key string) []string { 691 return cast.ToStringSlice(v.Get(key)) 692 } 693 694 // GetStringMap returns the value associated with the key as a map of interfaces. 695 func GetStringMap(key string) map[string]interface{} { return v.GetStringMap(key) } 696 func (v *Viper) GetStringMap(key string) map[string]interface{} { 697 return cast.ToStringMap(v.Get(key)) 698 } 699 700 // GetStringMapString returns the value associated with the key as a map of strings. 701 func GetStringMapString(key string) map[string]string { return v.GetStringMapString(key) } 702 func (v *Viper) GetStringMapString(key string) map[string]string { 703 return cast.ToStringMapString(v.Get(key)) 704 } 705 706 // GetStringMapStringSlice returns the value associated with the key as a map to a slice of strings. 707 func GetStringMapStringSlice(key string) map[string][]string { return v.GetStringMapStringSlice(key) } 708 func (v *Viper) GetStringMapStringSlice(key string) map[string][]string { 709 return cast.ToStringMapStringSlice(v.Get(key)) 710 } 711 712 // GetSizeInBytes returns the size of the value associated with the given key 713 // in bytes. 714 func GetSizeInBytes(key string) uint { return v.GetSizeInBytes(key) } 715 func (v *Viper) GetSizeInBytes(key string) uint { 716 sizeStr := cast.ToString(v.Get(key)) 717 return parseSizeInBytes(sizeStr) 718 } 719 720 // UnmarshalKey takes a single key and unmarshals it into a Struct. 721 func UnmarshalKey(key string, rawVal interface{}) error { return v.UnmarshalKey(key, rawVal) } 722 func (v *Viper) UnmarshalKey(key string, rawVal interface{}) error { 723 err := decode(v.Get(key), defaultDecoderConfig(rawVal)) 724 725 if err != nil { 726 return err 727 } 728 729 v.insensitiviseMaps() 730 731 return nil 732 } 733 734 // Unmarshal unmarshals the config into a Struct. Make sure that the tags 735 // on the fields of the structure are properly set. 736 func Unmarshal(rawVal interface{}) error { return v.Unmarshal(rawVal) } 737 func (v *Viper) Unmarshal(rawVal interface{}) error { 738 err := decode(v.AllSettings(), defaultDecoderConfig(rawVal)) 739 740 if err != nil { 741 return err 742 } 743 744 v.insensitiviseMaps() 745 746 return nil 747 } 748 749 // defaultDecoderConfig returns default mapsstructure.DecoderConfig with suppot 750 // of time.Duration values 751 func defaultDecoderConfig(output interface{}) *mapstructure.DecoderConfig { 752 return &mapstructure.DecoderConfig{ 753 Metadata: nil, 754 Result: output, 755 WeaklyTypedInput: true, 756 DecodeHook: mapstructure.StringToTimeDurationHookFunc(), 757 } 758 } 759 760 // A wrapper around mapstructure.Decode that mimics the WeakDecode functionality 761 func decode(input interface{}, config *mapstructure.DecoderConfig) error { 762 decoder, err := mapstructure.NewDecoder(config) 763 if err != nil { 764 return err 765 } 766 return decoder.Decode(input) 767 } 768 769 // UnmarshalExact unmarshals the config into a Struct, erroring if a field is nonexistent 770 // in the destination struct. 771 func (v *Viper) UnmarshalExact(rawVal interface{}) error { 772 config := defaultDecoderConfig(rawVal) 773 config.ErrorUnused = true 774 775 err := decode(v.AllSettings(), config) 776 777 if err != nil { 778 return err 779 } 780 781 v.insensitiviseMaps() 782 783 return nil 784 } 785 786 // BindPFlags binds a full flag set to the configuration, using each flag's long 787 // name as the config key. 788 func BindPFlags(flags *pflag.FlagSet) error { return v.BindPFlags(flags) } 789 func (v *Viper) BindPFlags(flags *pflag.FlagSet) error { 790 return v.BindFlagValues(pflagValueSet{flags}) 791 } 792 793 // BindPFlag binds a specific key to a pflag (as used by cobra). 794 // Example (where serverCmd is a Cobra instance): 795 // 796 // serverCmd.Flags().Int("port", 1138, "Port to run Application server on") 797 // Viper.BindPFlag("port", serverCmd.Flags().Lookup("port")) 798 // 799 func BindPFlag(key string, flag *pflag.Flag) error { return v.BindPFlag(key, flag) } 800 func (v *Viper) BindPFlag(key string, flag *pflag.Flag) error { 801 return v.BindFlagValue(key, pflagValue{flag}) 802 } 803 804 // BindFlagValues binds a full FlagValue set to the configuration, using each flag's long 805 // name as the config key. 806 func BindFlagValues(flags FlagValueSet) error { return v.BindFlagValues(flags) } 807 func (v *Viper) BindFlagValues(flags FlagValueSet) (err error) { 808 flags.VisitAll(func(flag FlagValue) { 809 if err = v.BindFlagValue(flag.Name(), flag); err != nil { 810 return 811 } 812 }) 813 return nil 814 } 815 816 // BindFlagValue binds a specific key to a FlagValue. 817 // Example (where serverCmd is a Cobra instance): 818 // 819 // serverCmd.Flags().Int("port", 1138, "Port to run Application server on") 820 // Viper.BindFlagValue("port", serverCmd.Flags().Lookup("port")) 821 // 822 func BindFlagValue(key string, flag FlagValue) error { return v.BindFlagValue(key, flag) } 823 func (v *Viper) BindFlagValue(key string, flag FlagValue) error { 824 if flag == nil { 825 return fmt.Errorf("flag for %q is nil", key) 826 } 827 v.pflags[strings.ToLower(key)] = flag 828 return nil 829 } 830 831 // BindEnv binds a Viper key to a ENV variable. 832 // ENV variables are case sensitive. 833 // If only a key is provided, it will use the env key matching the key, uppercased. 834 // EnvPrefix will be used when set when env name is not provided. 835 func BindEnv(input ...string) error { return v.BindEnv(input...) } 836 func (v *Viper) BindEnv(input ...string) error { 837 var key, envkey string 838 if len(input) == 0 { 839 return fmt.Errorf("BindEnv missing key to bind to") 840 } 841 842 key = strings.ToLower(input[0]) 843 844 if len(input) == 1 { 845 envkey = v.mergeWithEnvPrefix(key) 846 } else { 847 envkey = input[1] 848 } 849 850 v.env[key] = envkey 851 852 return nil 853 } 854 855 // Given a key, find the value. 856 // Viper will check in the following order: 857 // flag, env, config file, key/value store, default. 858 // Viper will check to see if an alias exists first. 859 // Note: this assumes a lower-cased key given. 860 func (v *Viper) find(lcaseKey string) interface{} { 861 862 var ( 863 val interface{} 864 exists bool 865 path = strings.Split(lcaseKey, v.keyDelim) 866 nested = len(path) > 1 867 ) 868 869 // compute the path through the nested maps to the nested value 870 if nested && v.isPathShadowedInDeepMap(path, castMapStringToMapInterface(v.aliases)) != "" { 871 return nil 872 } 873 874 // if the requested key is an alias, then return the proper key 875 lcaseKey = v.realKey(lcaseKey) 876 path = strings.Split(lcaseKey, v.keyDelim) 877 nested = len(path) > 1 878 879 // Set() override first 880 val = v.searchMap(v.override, path) 881 if val != nil { 882 return val 883 } 884 if nested && v.isPathShadowedInDeepMap(path, v.override) != "" { 885 return nil 886 } 887 888 // PFlag override next 889 flag, exists := v.pflags[lcaseKey] 890 if exists && flag.HasChanged() { 891 switch flag.ValueType() { 892 case "int", "int8", "int16", "int32", "int64": 893 return cast.ToInt(flag.ValueString()) 894 case "bool": 895 return cast.ToBool(flag.ValueString()) 896 case "stringSlice": 897 s := strings.TrimPrefix(flag.ValueString(), "[") 898 s = strings.TrimSuffix(s, "]") 899 res, _ := readAsCSV(s) 900 return res 901 default: 902 return flag.ValueString() 903 } 904 } 905 if nested && v.isPathShadowedInFlatMap(path, v.pflags) != "" { 906 return nil 907 } 908 909 // Env override next 910 if v.automaticEnvApplied { 911 // even if it hasn't been registered, if automaticEnv is used, 912 // check any Get request 913 if val = v.getEnv(v.mergeWithEnvPrefix(lcaseKey)); val != "" { 914 return val 915 } 916 if nested && v.isPathShadowedInAutoEnv(path) != "" { 917 return nil 918 } 919 } 920 envkey, exists := v.env[lcaseKey] 921 if exists { 922 if val = v.getEnv(envkey); val != "" { 923 return val 924 } 925 } 926 if nested && v.isPathShadowedInFlatMap(path, v.env) != "" { 927 return nil 928 } 929 930 // Config file next 931 val = v.searchMapWithPathPrefixes(v.config, path) 932 if val != nil { 933 return val 934 } 935 if nested && v.isPathShadowedInDeepMap(path, v.config) != "" { 936 return nil 937 } 938 939 // K/V store next 940 val = v.searchMap(v.kvstore, path) 941 if val != nil { 942 return val 943 } 944 if nested && v.isPathShadowedInDeepMap(path, v.kvstore) != "" { 945 return nil 946 } 947 948 // Default next 949 val = v.searchMap(v.defaults, path) 950 if val != nil { 951 return val 952 } 953 if nested && v.isPathShadowedInDeepMap(path, v.defaults) != "" { 954 return nil 955 } 956 957 // last chance: if no other value is returned and a flag does exist for the value, 958 // get the flag's value even if the flag's value has not changed 959 if flag, exists := v.pflags[lcaseKey]; exists { 960 switch flag.ValueType() { 961 case "int", "int8", "int16", "int32", "int64": 962 return cast.ToInt(flag.ValueString()) 963 case "bool": 964 return cast.ToBool(flag.ValueString()) 965 case "stringSlice": 966 s := strings.TrimPrefix(flag.ValueString(), "[") 967 s = strings.TrimSuffix(s, "]") 968 res, _ := readAsCSV(s) 969 return res 970 default: 971 return flag.ValueString() 972 } 973 } 974 // last item, no need to check shadowing 975 976 return nil 977 } 978 979 func readAsCSV(val string) ([]string, error) { 980 if val == "" { 981 return []string{}, nil 982 } 983 stringReader := strings.NewReader(val) 984 csvReader := csv.NewReader(stringReader) 985 return csvReader.Read() 986 } 987 988 // IsSet checks to see if the key has been set in any of the data locations. 989 // IsSet is case-insensitive for a key. 990 func IsSet(key string) bool { return v.IsSet(key) } 991 func (v *Viper) IsSet(key string) bool { 992 lcaseKey := strings.ToLower(key) 993 val := v.find(lcaseKey) 994 return val != nil 995 } 996 997 // AutomaticEnv has Viper check ENV variables for all. 998 // keys set in config, default & flags 999 func AutomaticEnv() { v.AutomaticEnv() } 1000 func (v *Viper) AutomaticEnv() { 1001 v.automaticEnvApplied = true 1002 } 1003 1004 // SetEnvKeyReplacer sets the strings.Replacer on the viper object 1005 // Useful for mapping an environmental variable to a key that does 1006 // not match it. 1007 func SetEnvKeyReplacer(r *strings.Replacer) { v.SetEnvKeyReplacer(r) } 1008 func (v *Viper) SetEnvKeyReplacer(r *strings.Replacer) { 1009 v.envKeyReplacer = r 1010 } 1011 1012 // Aliases provide another accessor for the same key. 1013 // This enables one to change a name without breaking the application 1014 func RegisterAlias(alias string, key string) { v.RegisterAlias(alias, key) } 1015 func (v *Viper) RegisterAlias(alias string, key string) { 1016 v.registerAlias(alias, strings.ToLower(key)) 1017 } 1018 1019 func (v *Viper) registerAlias(alias string, key string) { 1020 alias = strings.ToLower(alias) 1021 if alias != key && alias != v.realKey(key) { 1022 _, exists := v.aliases[alias] 1023 1024 if !exists { 1025 // if we alias something that exists in one of the maps to another 1026 // name, we'll never be able to get that value using the original 1027 // name, so move the config value to the new realkey. 1028 if val, ok := v.config[alias]; ok { 1029 delete(v.config, alias) 1030 v.config[key] = val 1031 } 1032 if val, ok := v.kvstore[alias]; ok { 1033 delete(v.kvstore, alias) 1034 v.kvstore[key] = val 1035 } 1036 if val, ok := v.defaults[alias]; ok { 1037 delete(v.defaults, alias) 1038 v.defaults[key] = val 1039 } 1040 if val, ok := v.override[alias]; ok { 1041 delete(v.override, alias) 1042 v.override[key] = val 1043 } 1044 v.aliases[alias] = key 1045 } 1046 } else { 1047 jww.WARN.Println("Creating circular reference alias", alias, key, v.realKey(key)) 1048 } 1049 } 1050 1051 func (v *Viper) realKey(key string) string { 1052 newkey, exists := v.aliases[key] 1053 if exists { 1054 jww.DEBUG.Println("Alias", key, "to", newkey) 1055 return v.realKey(newkey) 1056 } 1057 return key 1058 } 1059 1060 // InConfig checks to see if the given key (or an alias) is in the config file. 1061 func InConfig(key string) bool { return v.InConfig(key) } 1062 func (v *Viper) InConfig(key string) bool { 1063 // if the requested key is an alias, then return the proper key 1064 key = v.realKey(key) 1065 1066 _, exists := v.config[key] 1067 return exists 1068 } 1069 1070 // SetDefault sets the default value for this key. 1071 // SetDefault is case-insensitive for a key. 1072 // Default only used when no value is provided by the user via flag, config or ENV. 1073 func SetDefault(key string, value interface{}) { v.SetDefault(key, value) } 1074 func (v *Viper) SetDefault(key string, value interface{}) { 1075 // If alias passed in, then set the proper default 1076 key = v.realKey(strings.ToLower(key)) 1077 value = toCaseInsensitiveValue(value) 1078 1079 path := strings.Split(key, v.keyDelim) 1080 lastKey := strings.ToLower(path[len(path)-1]) 1081 deepestMap := deepSearch(v.defaults, path[0:len(path)-1]) 1082 1083 // set innermost value 1084 deepestMap[lastKey] = value 1085 } 1086 1087 // Set sets the value for the key in the override regiser. 1088 // Set is case-insensitive for a key. 1089 // Will be used instead of values obtained via 1090 // flags, config file, ENV, default, or key/value store. 1091 func Set(key string, value interface{}) { v.Set(key, value) } 1092 func (v *Viper) Set(key string, value interface{}) { 1093 // If alias passed in, then set the proper override 1094 key = v.realKey(strings.ToLower(key)) 1095 value = toCaseInsensitiveValue(value) 1096 1097 path := strings.Split(key, v.keyDelim) 1098 lastKey := strings.ToLower(path[len(path)-1]) 1099 deepestMap := deepSearch(v.override, path[0:len(path)-1]) 1100 1101 // set innermost value 1102 deepestMap[lastKey] = value 1103 } 1104 1105 // ReadInConfig will discover and load the configuration file from disk 1106 // and key/value stores, searching in one of the defined paths. 1107 func ReadInConfig() error { return v.ReadInConfig() } 1108 func (v *Viper) ReadInConfig() error { 1109 jww.INFO.Println("Attempting to read in config file") 1110 filename, err := v.getConfigFile() 1111 if err != nil { 1112 return err 1113 } 1114 1115 if !stringInSlice(v.getConfigType(), SupportedExts) { 1116 return UnsupportedConfigError(v.getConfigType()) 1117 } 1118 1119 file, err := afero.ReadFile(v.fs, filename) 1120 if err != nil { 1121 return err 1122 } 1123 1124 config := make(map[string]interface{}) 1125 1126 err = v.unmarshalReader(bytes.NewReader(file), config) 1127 if err != nil { 1128 return err 1129 } 1130 1131 v.config = config 1132 return nil 1133 } 1134 1135 // MergeInConfig merges a new configuration with an existing config. 1136 func MergeInConfig() error { return v.MergeInConfig() } 1137 func (v *Viper) MergeInConfig() error { 1138 jww.INFO.Println("Attempting to merge in config file") 1139 filename, err := v.getConfigFile() 1140 if err != nil { 1141 return err 1142 } 1143 1144 if !stringInSlice(v.getConfigType(), SupportedExts) { 1145 return UnsupportedConfigError(v.getConfigType()) 1146 } 1147 1148 file, err := afero.ReadFile(v.fs, filename) 1149 if err != nil { 1150 return err 1151 } 1152 1153 return v.MergeConfig(bytes.NewReader(file)) 1154 } 1155 1156 // ReadConfig will read a configuration file, setting existing keys to nil if the 1157 // key does not exist in the file. 1158 func ReadConfig(in io.Reader) error { return v.ReadConfig(in) } 1159 func (v *Viper) ReadConfig(in io.Reader) error { 1160 v.config = make(map[string]interface{}) 1161 return v.unmarshalReader(in, v.config) 1162 } 1163 1164 // MergeConfig merges a new configuration with an existing config. 1165 func MergeConfig(in io.Reader) error { return v.MergeConfig(in) } 1166 func (v *Viper) MergeConfig(in io.Reader) error { 1167 if v.config == nil { 1168 v.config = make(map[string]interface{}) 1169 } 1170 cfg := make(map[string]interface{}) 1171 if err := v.unmarshalReader(in, cfg); err != nil { 1172 return err 1173 } 1174 mergeMaps(cfg, v.config, nil) 1175 return nil 1176 } 1177 1178 func keyExists(k string, m map[string]interface{}) string { 1179 lk := strings.ToLower(k) 1180 for mk := range m { 1181 lmk := strings.ToLower(mk) 1182 if lmk == lk { 1183 return mk 1184 } 1185 } 1186 return "" 1187 } 1188 1189 func castToMapStringInterface( 1190 src map[interface{}]interface{}) map[string]interface{} { 1191 tgt := map[string]interface{}{} 1192 for k, v := range src { 1193 tgt[fmt.Sprintf("%v", k)] = v 1194 } 1195 return tgt 1196 } 1197 1198 func castMapStringToMapInterface(src map[string]string) map[string]interface{} { 1199 tgt := map[string]interface{}{} 1200 for k, v := range src { 1201 tgt[k] = v 1202 } 1203 return tgt 1204 } 1205 1206 func castMapFlagToMapInterface(src map[string]FlagValue) map[string]interface{} { 1207 tgt := map[string]interface{}{} 1208 for k, v := range src { 1209 tgt[k] = v 1210 } 1211 return tgt 1212 } 1213 1214 // mergeMaps merges two maps. The `itgt` parameter is for handling go-yaml's 1215 // insistence on parsing nested structures as `map[interface{}]interface{}` 1216 // instead of using a `string` as the key for nest structures beyond one level 1217 // deep. Both map types are supported as there is a go-yaml fork that uses 1218 // `map[string]interface{}` instead. 1219 func mergeMaps( 1220 src, tgt map[string]interface{}, itgt map[interface{}]interface{}) { 1221 for sk, sv := range src { 1222 tk := keyExists(sk, tgt) 1223 if tk == "" { 1224 jww.TRACE.Printf("tk=\"\", tgt[%s]=%v", sk, sv) 1225 tgt[sk] = sv 1226 if itgt != nil { 1227 itgt[sk] = sv 1228 } 1229 continue 1230 } 1231 1232 tv, ok := tgt[tk] 1233 if !ok { 1234 jww.TRACE.Printf("tgt[%s] != ok, tgt[%s]=%v", tk, sk, sv) 1235 tgt[sk] = sv 1236 if itgt != nil { 1237 itgt[sk] = sv 1238 } 1239 continue 1240 } 1241 1242 svType := reflect.TypeOf(sv) 1243 tvType := reflect.TypeOf(tv) 1244 if svType != tvType { 1245 jww.ERROR.Printf( 1246 "svType != tvType; key=%s, st=%v, tt=%v, sv=%v, tv=%v", 1247 sk, svType, tvType, sv, tv) 1248 continue 1249 } 1250 1251 jww.TRACE.Printf("processing key=%s, st=%v, tt=%v, sv=%v, tv=%v", 1252 sk, svType, tvType, sv, tv) 1253 1254 switch ttv := tv.(type) { 1255 case map[interface{}]interface{}: 1256 jww.TRACE.Printf("merging maps (must convert)") 1257 tsv := sv.(map[interface{}]interface{}) 1258 ssv := castToMapStringInterface(tsv) 1259 stv := castToMapStringInterface(ttv) 1260 mergeMaps(ssv, stv, ttv) 1261 case map[string]interface{}: 1262 jww.TRACE.Printf("merging maps") 1263 mergeMaps(sv.(map[string]interface{}), ttv, nil) 1264 default: 1265 jww.TRACE.Printf("setting value") 1266 tgt[tk] = sv 1267 if itgt != nil { 1268 itgt[tk] = sv 1269 } 1270 } 1271 } 1272 } 1273 1274 // ReadRemoteConfig attempts to get configuration from a remote source 1275 // and read it in the remote configuration registry. 1276 func ReadRemoteConfig() error { return v.ReadRemoteConfig() } 1277 func (v *Viper) ReadRemoteConfig() error { 1278 return v.getKeyValueConfig() 1279 } 1280 1281 func WatchRemoteConfig() error { return v.WatchRemoteConfig() } 1282 func (v *Viper) WatchRemoteConfig() error { 1283 return v.watchKeyValueConfig() 1284 } 1285 1286 func (v *Viper) WatchRemoteConfigOnChannel() error { 1287 return v.watchKeyValueConfigOnChannel() 1288 } 1289 1290 // Unmarshal a Reader into a map. 1291 // Should probably be an unexported function. 1292 func unmarshalReader(in io.Reader, c map[string]interface{}) error { 1293 return v.unmarshalReader(in, c) 1294 } 1295 1296 func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error { 1297 return unmarshallConfigReader(in, c, v.getConfigType()) 1298 } 1299 1300 func (v *Viper) insensitiviseMaps() { 1301 insensitiviseMap(v.config) 1302 insensitiviseMap(v.defaults) 1303 insensitiviseMap(v.override) 1304 insensitiviseMap(v.kvstore) 1305 } 1306 1307 // Retrieve the first found remote configuration. 1308 func (v *Viper) getKeyValueConfig() error { 1309 if RemoteConfig == nil { 1310 return RemoteConfigError("Enable the remote features by doing a blank import of the viper/remote package: '_ github.com/spf13/viper/remote'") 1311 } 1312 1313 for _, rp := range v.remoteProviders { 1314 val, err := v.getRemoteConfig(rp) 1315 if err != nil { 1316 continue 1317 } 1318 v.kvstore = val 1319 return nil 1320 } 1321 return RemoteConfigError("No Files Found") 1322 } 1323 1324 func (v *Viper) getRemoteConfig(provider RemoteProvider) (map[string]interface{}, error) { 1325 reader, err := RemoteConfig.Get(provider) 1326 if err != nil { 1327 return nil, err 1328 } 1329 err = v.unmarshalReader(reader, v.kvstore) 1330 return v.kvstore, err 1331 } 1332 1333 // Retrieve the first found remote configuration. 1334 func (v *Viper) watchKeyValueConfigOnChannel() error { 1335 for _, rp := range v.remoteProviders { 1336 respc, _ := RemoteConfig.WatchChannel(rp) 1337 //Todo: Add quit channel 1338 go func(rc <-chan *RemoteResponse) { 1339 for { 1340 b := <-rc 1341 reader := bytes.NewReader(b.Value) 1342 v.unmarshalReader(reader, v.kvstore) 1343 } 1344 }(respc) 1345 return nil 1346 } 1347 return RemoteConfigError("No Files Found") 1348 } 1349 1350 // Retrieve the first found remote configuration. 1351 func (v *Viper) watchKeyValueConfig() error { 1352 for _, rp := range v.remoteProviders { 1353 val, err := v.watchRemoteConfig(rp) 1354 if err != nil { 1355 continue 1356 } 1357 v.kvstore = val 1358 return nil 1359 } 1360 return RemoteConfigError("No Files Found") 1361 } 1362 1363 func (v *Viper) watchRemoteConfig(provider RemoteProvider) (map[string]interface{}, error) { 1364 reader, err := RemoteConfig.Watch(provider) 1365 if err != nil { 1366 return nil, err 1367 } 1368 err = v.unmarshalReader(reader, v.kvstore) 1369 return v.kvstore, err 1370 } 1371 1372 // AllKeys returns all keys holding a value, regardless of where they are set. 1373 // Nested keys are returned with a v.keyDelim (= ".") separator 1374 func AllKeys() []string { return v.AllKeys() } 1375 func (v *Viper) AllKeys() []string { 1376 m := map[string]bool{} 1377 // add all paths, by order of descending priority to ensure correct shadowing 1378 m = v.flattenAndMergeMap(m, castMapStringToMapInterface(v.aliases), "") 1379 m = v.flattenAndMergeMap(m, v.override, "") 1380 m = v.mergeFlatMap(m, castMapFlagToMapInterface(v.pflags)) 1381 m = v.mergeFlatMap(m, castMapStringToMapInterface(v.env)) 1382 m = v.flattenAndMergeMap(m, v.config, "") 1383 m = v.flattenAndMergeMap(m, v.kvstore, "") 1384 m = v.flattenAndMergeMap(m, v.defaults, "") 1385 1386 // convert set of paths to list 1387 a := []string{} 1388 for x := range m { 1389 a = append(a, x) 1390 } 1391 return a 1392 } 1393 1394 // flattenAndMergeMap recursively flattens the given map into a map[string]bool 1395 // of key paths (used as a set, easier to manipulate than a []string): 1396 // - each path is merged into a single key string, delimited with v.keyDelim (= ".") 1397 // - if a path is shadowed by an earlier value in the initial shadow map, 1398 // it is skipped. 1399 // The resulting set of paths is merged to the given shadow set at the same time. 1400 func (v *Viper) flattenAndMergeMap(shadow map[string]bool, m map[string]interface{}, prefix string) map[string]bool { 1401 if shadow != nil && prefix != "" && shadow[prefix] { 1402 // prefix is shadowed => nothing more to flatten 1403 return shadow 1404 } 1405 if shadow == nil { 1406 shadow = make(map[string]bool) 1407 } 1408 1409 var m2 map[string]interface{} 1410 if prefix != "" { 1411 prefix += v.keyDelim 1412 } 1413 for k, val := range m { 1414 fullKey := prefix + k 1415 switch val.(type) { 1416 case map[string]interface{}: 1417 m2 = val.(map[string]interface{}) 1418 case map[interface{}]interface{}: 1419 m2 = cast.ToStringMap(val) 1420 default: 1421 // immediate value 1422 shadow[strings.ToLower(fullKey)] = true 1423 continue 1424 } 1425 // recursively merge to shadow map 1426 shadow = v.flattenAndMergeMap(shadow, m2, fullKey) 1427 } 1428 return shadow 1429 } 1430 1431 // mergeFlatMap merges the given maps, excluding values of the second map 1432 // shadowed by values from the first map. 1433 func (v *Viper) mergeFlatMap(shadow map[string]bool, m map[string]interface{}) map[string]bool { 1434 // scan keys 1435 outer: 1436 for k, _ := range m { 1437 path := strings.Split(k, v.keyDelim) 1438 // scan intermediate paths 1439 var parentKey string 1440 for i := 1; i < len(path); i++ { 1441 parentKey = strings.Join(path[0:i], v.keyDelim) 1442 if shadow[parentKey] { 1443 // path is shadowed, continue 1444 continue outer 1445 } 1446 } 1447 // add key 1448 shadow[strings.ToLower(k)] = true 1449 } 1450 return shadow 1451 } 1452 1453 // AllSettings merges all settings and returns them as a map[string]interface{}. 1454 func AllSettings() map[string]interface{} { return v.AllSettings() } 1455 func (v *Viper) AllSettings() map[string]interface{} { 1456 m := map[string]interface{}{} 1457 // start from the list of keys, and construct the map one value at a time 1458 for _, k := range v.AllKeys() { 1459 value := v.Get(k) 1460 if value == nil { 1461 // should not happen, since AllKeys() returns only keys holding a value, 1462 // check just in case anything changes 1463 continue 1464 } 1465 path := strings.Split(k, v.keyDelim) 1466 lastKey := strings.ToLower(path[len(path)-1]) 1467 deepestMap := deepSearch(m, path[0:len(path)-1]) 1468 // set innermost value 1469 deepestMap[lastKey] = value 1470 } 1471 return m 1472 } 1473 1474 // SetFs sets the filesystem to use to read configuration. 1475 func SetFs(fs afero.Fs) { v.SetFs(fs) } 1476 func (v *Viper) SetFs(fs afero.Fs) { 1477 v.fs = fs 1478 } 1479 1480 // SetConfigName sets name for the config file. 1481 // Does not include extension. 1482 func SetConfigName(in string) { v.SetConfigName(in) } 1483 func (v *Viper) SetConfigName(in string) { 1484 if in != "" { 1485 v.configName = in 1486 v.configFile = "" 1487 } 1488 } 1489 1490 // SetConfigType sets the type of the configuration returned by the 1491 // remote source, e.g. "json". 1492 func SetConfigType(in string) { v.SetConfigType(in) } 1493 func (v *Viper) SetConfigType(in string) { 1494 if in != "" { 1495 v.configType = in 1496 } 1497 } 1498 1499 func (v *Viper) getConfigType() string { 1500 if v.configType != "" { 1501 return v.configType 1502 } 1503 1504 cf, err := v.getConfigFile() 1505 if err != nil { 1506 return "" 1507 } 1508 1509 ext := filepath.Ext(cf) 1510 1511 if len(ext) > 1 { 1512 return ext[1:] 1513 } 1514 1515 return "" 1516 } 1517 1518 func (v *Viper) getConfigFile() (string, error) { 1519 // if explicitly set, then use it 1520 if v.configFile != "" { 1521 return v.configFile, nil 1522 } 1523 1524 cf, err := v.findConfigFile() 1525 if err != nil { 1526 return "", err 1527 } 1528 1529 v.configFile = cf 1530 return v.getConfigFile() 1531 } 1532 1533 func (v *Viper) searchInPath(in string) (filename string) { 1534 jww.DEBUG.Println("Searching for config in ", in) 1535 for _, ext := range SupportedExts { 1536 jww.DEBUG.Println("Checking for", filepath.Join(in, v.configName+"."+ext)) 1537 if b, _ := exists(filepath.Join(in, v.configName+"."+ext)); b { 1538 jww.DEBUG.Println("Found: ", filepath.Join(in, v.configName+"."+ext)) 1539 return filepath.Join(in, v.configName+"."+ext) 1540 } 1541 } 1542 1543 return "" 1544 } 1545 1546 // Search all configPaths for any config file. 1547 // Returns the first path that exists (and is a config file). 1548 func (v *Viper) findConfigFile() (string, error) { 1549 jww.INFO.Println("Searching for config in ", v.configPaths) 1550 1551 for _, cp := range v.configPaths { 1552 file := v.searchInPath(cp) 1553 if file != "" { 1554 return file, nil 1555 } 1556 } 1557 return "", ConfigFileNotFoundError{v.configName, fmt.Sprintf("%s", v.configPaths)} 1558 } 1559 1560 // Debug prints all configuration registries for debugging 1561 // purposes. 1562 func Debug() { v.Debug() } 1563 func (v *Viper) Debug() { 1564 fmt.Printf("Aliases:\n%#v\n", v.aliases) 1565 fmt.Printf("Override:\n%#v\n", v.override) 1566 fmt.Printf("PFlags:\n%#v\n", v.pflags) 1567 fmt.Printf("Env:\n%#v\n", v.env) 1568 fmt.Printf("Key/Value Store:\n%#v\n", v.kvstore) 1569 fmt.Printf("Config:\n%#v\n", v.config) 1570 fmt.Printf("Defaults:\n%#v\n", v.defaults) 1571 }