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