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