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