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