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