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