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