github.com/endophage/viper@v0.0.0-20160111150723-a212099cbe6f/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 a 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 "fmt" 25 "io" 26 "io/ioutil" 27 "log" 28 "os" 29 "path/filepath" 30 "reflect" 31 "strings" 32 "time" 33 34 "github.com/kr/pretty" 35 "github.com/mitchellh/mapstructure" 36 "github.com/spf13/cast" 37 jww "github.com/spf13/jwalterweatherman" 38 "github.com/spf13/pflag" 39 "gopkg.in/fsnotify.v1" 40 ) 41 42 var v *Viper 43 44 func init() { 45 v = New() 46 } 47 48 type remoteConfigFactory interface { 49 Get(rp RemoteProvider) (io.Reader, error) 50 Watch(rp RemoteProvider) (io.Reader, error) 51 } 52 53 // RemoteConfig is optional, see the remote package 54 var RemoteConfig remoteConfigFactory 55 56 // Denotes encountering an unsupported 57 // configuration filetype. 58 type UnsupportedConfigError string 59 60 // Returns the formatted configuration error. 61 func (str UnsupportedConfigError) Error() string { 62 return fmt.Sprintf("Unsupported Config Type %q", string(str)) 63 } 64 65 // Denotes encountering an unsupported remote 66 // provider. Currently only etcd and Consul are 67 // supported. 68 type UnsupportedRemoteProviderError string 69 70 // Returns the formatted remote provider error. 71 func (str UnsupportedRemoteProviderError) Error() string { 72 return fmt.Sprintf("Unsupported Remote Provider Type %q", string(str)) 73 } 74 75 // Denotes encountering an error while trying to 76 // pull the configuration from the remote provider. 77 type RemoteConfigError string 78 79 // Returns the formatted remote provider error 80 func (rce RemoteConfigError) Error() string { 81 return fmt.Sprintf("Remote Configurations Error: %s", string(rce)) 82 } 83 84 // Denotes failing to find configuration file. 85 type ConfigFileNotFoundError struct { 86 name, locations string 87 } 88 89 // Returns the formatted configuration error. 90 func (fnfe ConfigFileNotFoundError) Error() string { 91 return fmt.Sprintf("Config File %q Not Found in %q", fnfe.name, fnfe.locations) 92 } 93 94 // Viper is a prioritized configuration registry. It 95 // maintains a set of configuration sources, fetches 96 // values to populate those, and provides them according 97 // to the source's priority. 98 // The priority of the sources is the following: 99 // 1. overrides 100 // 2. flags 101 // 3. env. variables 102 // 4. config file 103 // 5. key/value store 104 // 6. defaults 105 // 106 // For example, if values from the following sources were loaded: 107 // 108 // Defaults : { 109 // "secret": "", 110 // "user": "default", 111 // "endpoint": "https://localhost" 112 // } 113 // Config : { 114 // "user": "root" 115 // "secret": "defaultsecret" 116 // } 117 // Env : { 118 // "secret": "somesecretkey" 119 // } 120 // 121 // The resulting config will have the following values: 122 // 123 // { 124 // "secret": "somesecretkey", 125 // "user": "root", 126 // "endpoint": "https://localhost" 127 // } 128 type Viper struct { 129 // Delimiter that separates a list of keys 130 // used to access a nested value in one go 131 keyDelim string 132 133 // A set of paths to look for the config file in 134 configPaths []string 135 136 // A set of remote providers to search for the configuration 137 remoteProviders []*defaultRemoteProvider 138 139 // Name of file to look for inside the path 140 configName string 141 configFile string 142 configType string 143 envPrefix string 144 145 automaticEnvApplied bool 146 envKeyReplacer *strings.Replacer 147 148 config map[string]interface{} 149 override map[string]interface{} 150 defaults map[string]interface{} 151 kvstore map[string]interface{} 152 pflags map[string]FlagValue 153 env map[string]string 154 aliases map[string]string 155 typeByDefValue bool 156 157 onConfigChange func(fsnotify.Event) 158 } 159 160 // Returns an initialized Viper instance. 161 func New() *Viper { 162 v := new(Viper) 163 v.keyDelim = "." 164 v.configName = "config" 165 v.config = make(map[string]interface{}) 166 v.override = make(map[string]interface{}) 167 v.defaults = make(map[string]interface{}) 168 v.kvstore = make(map[string]interface{}) 169 v.pflags = make(map[string]FlagValue) 170 v.env = make(map[string]string) 171 v.aliases = make(map[string]string) 172 v.typeByDefValue = false 173 174 return v 175 } 176 177 // Intended for testing, will reset all to default settings. 178 // In the public interface for the viper package so applications 179 // can use it in their testing as well. 180 func Reset() { 181 v = New() 182 SupportedExts = []string{"json", "toml", "yaml", "yml", "hcl"} 183 SupportedRemoteProviders = []string{"etcd", "consul"} 184 } 185 186 type defaultRemoteProvider struct { 187 provider string 188 endpoint string 189 path string 190 secretKeyring string 191 } 192 193 func (rp defaultRemoteProvider) Provider() string { 194 return rp.provider 195 } 196 197 func (rp defaultRemoteProvider) Endpoint() string { 198 return rp.endpoint 199 } 200 201 func (rp defaultRemoteProvider) Path() string { 202 return rp.path 203 } 204 205 func (rp defaultRemoteProvider) SecretKeyring() string { 206 return rp.secretKeyring 207 } 208 209 // RemoteProvider stores the configuration necessary 210 // to connect to a remote key/value store. 211 // Optional secretKeyring to unencrypt encrypted values 212 // can be provided. 213 type RemoteProvider interface { 214 Provider() string 215 Endpoint() string 216 Path() string 217 SecretKeyring() string 218 } 219 220 // Universally supported extensions. 221 var SupportedExts []string = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl"} 222 223 // Universally supported remote providers. 224 var SupportedRemoteProviders []string = []string{"etcd", "consul"} 225 226 func OnConfigChange(run func(in fsnotify.Event)) { v.OnConfigChange(run) } 227 func (v *Viper) OnConfigChange(run func(in fsnotify.Event)) { 228 v.onConfigChange = run 229 } 230 231 func WatchConfig() { v.WatchConfig() } 232 func (v *Viper) WatchConfig() { 233 go func() { 234 watcher, err := fsnotify.NewWatcher() 235 if err != nil { 236 log.Fatal(err) 237 } 238 defer watcher.Close() 239 240 // we have to watch the entire directory to pick up renames/atomic saves in a cross-platform way 241 configFile := filepath.Clean(v.getConfigFile()) 242 configDir, _ := filepath.Split(configFile) 243 244 done := make(chan bool) 245 go func() { 246 for { 247 select { 248 case event := <-watcher.Events: 249 // we only care about the config file 250 if filepath.Clean(event.Name) == configFile { 251 if event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Create == fsnotify.Create { 252 err := v.ReadInConfig() 253 if err != nil { 254 log.Println("error:", err) 255 } 256 v.onConfigChange(event) 257 } 258 } 259 case err := <-watcher.Errors: 260 log.Println("error:", err) 261 } 262 } 263 }() 264 265 watcher.Add(configDir) 266 <-done 267 }() 268 } 269 270 // Explicitly define the path, name and extension of the config file 271 // Viper will use this and not check any of the config paths 272 func SetConfigFile(in string) { v.SetConfigFile(in) } 273 func (v *Viper) SetConfigFile(in string) { 274 if in != "" { 275 v.configFile = in 276 } 277 } 278 279 // Define a prefix that ENVIRONMENT variables will use. 280 // E.g. if your prefix is "spf", the env registry 281 // will look for env. variables that start with "SPF_" 282 func SetEnvPrefix(in string) { v.SetEnvPrefix(in) } 283 func (v *Viper) SetEnvPrefix(in string) { 284 if in != "" { 285 v.envPrefix = in 286 } 287 } 288 289 func (v *Viper) mergeWithEnvPrefix(in string) string { 290 if v.envPrefix != "" { 291 return strings.ToUpper(v.envPrefix + "_" + in) 292 } 293 294 return strings.ToUpper(in) 295 } 296 297 // TODO: should getEnv logic be moved into find(). Can generalize the use of 298 // rewriting keys many things, Ex: Get('someKey') -> some_key 299 // (cammel case to snake case for JSON keys perhaps) 300 301 // getEnv s a wrapper around os.Getenv which replaces characters in the original 302 // key. This allows env vars which have different keys then the config object 303 // keys 304 func (v *Viper) getEnv(key string) string { 305 if v.envKeyReplacer != nil { 306 key = v.envKeyReplacer.Replace(key) 307 } 308 return os.Getenv(key) 309 } 310 311 // Return the file used to populate the config registry 312 func ConfigFileUsed() string { return v.ConfigFileUsed() } 313 func (v *Viper) ConfigFileUsed() string { return v.configFile } 314 315 // Add a path for Viper to search for the config file in. 316 // Can be called multiple times to define multiple search paths. 317 func AddConfigPath(in string) { v.AddConfigPath(in) } 318 func (v *Viper) AddConfigPath(in string) { 319 if in != "" { 320 absin := absPathify(in) 321 jww.INFO.Println("adding", absin, "to paths to search") 322 if !stringInSlice(absin, v.configPaths) { 323 v.configPaths = append(v.configPaths, absin) 324 } 325 } 326 } 327 328 // AddRemoteProvider adds a remote configuration source. 329 // Remote Providers are searched in the order they are added. 330 // provider is a string value, "etcd" or "consul" are currently supported. 331 // endpoint is the url. etcd requires http://ip:port consul requires ip:port 332 // path is the path in the k/v store to retrieve configuration 333 // To retrieve a config file called myapp.json from /configs/myapp.json 334 // you should set path to /configs and set config name (SetConfigName()) to 335 // "myapp" 336 func AddRemoteProvider(provider, endpoint, path string) error { 337 return v.AddRemoteProvider(provider, endpoint, path) 338 } 339 func (v *Viper) AddRemoteProvider(provider, endpoint, path string) error { 340 if !stringInSlice(provider, SupportedRemoteProviders) { 341 return UnsupportedRemoteProviderError(provider) 342 } 343 if provider != "" && endpoint != "" { 344 jww.INFO.Printf("adding %s:%s to remote provider list", provider, endpoint) 345 rp := &defaultRemoteProvider{ 346 endpoint: endpoint, 347 provider: provider, 348 path: path, 349 } 350 if !v.providerPathExists(rp) { 351 v.remoteProviders = append(v.remoteProviders, rp) 352 } 353 } 354 return nil 355 } 356 357 // AddSecureRemoteProvider adds a remote configuration source. 358 // Secure Remote Providers are searched in the order they are added. 359 // provider is a string value, "etcd" or "consul" are currently supported. 360 // endpoint is the url. etcd requires http://ip:port consul requires ip:port 361 // secretkeyring is the filepath to your openpgp secret keyring. e.g. /etc/secrets/myring.gpg 362 // path is the path in the k/v store to retrieve configuration 363 // To retrieve a config file called myapp.json from /configs/myapp.json 364 // you should set path to /configs and set config name (SetConfigName()) to 365 // "myapp" 366 // Secure Remote Providers are implemented with github.com/xordataexchange/crypt 367 func AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error { 368 return v.AddSecureRemoteProvider(provider, endpoint, path, secretkeyring) 369 } 370 371 func (v *Viper) AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error { 372 if !stringInSlice(provider, SupportedRemoteProviders) { 373 return UnsupportedRemoteProviderError(provider) 374 } 375 if provider != "" && endpoint != "" { 376 jww.INFO.Printf("adding %s:%s to remote provider list", provider, endpoint) 377 rp := &defaultRemoteProvider{ 378 endpoint: endpoint, 379 provider: provider, 380 path: path, 381 secretKeyring: secretkeyring, 382 } 383 if !v.providerPathExists(rp) { 384 v.remoteProviders = append(v.remoteProviders, rp) 385 } 386 } 387 return nil 388 } 389 390 func (v *Viper) providerPathExists(p *defaultRemoteProvider) bool { 391 for _, y := range v.remoteProviders { 392 if reflect.DeepEqual(y, p) { 393 return true 394 } 395 } 396 return false 397 } 398 399 func (v *Viper) searchMap(source map[string]interface{}, path []string) interface{} { 400 401 if len(path) == 0 { 402 return source 403 } 404 405 var ok bool 406 var next interface{} 407 for k, v := range source { 408 if strings.ToLower(k) == strings.ToLower(path[0]) { 409 ok = true 410 next = v 411 break 412 } 413 } 414 415 if ok { 416 switch next.(type) { 417 case map[interface{}]interface{}: 418 return v.searchMap(cast.ToStringMap(next), path[1:]) 419 case map[string]interface{}: 420 // Type assertion is safe here since it is only reached 421 // if the type of `next` is the same as the type being asserted 422 return v.searchMap(next.(map[string]interface{}), path[1:]) 423 default: 424 return next 425 } 426 } else { 427 return nil 428 } 429 } 430 431 // SetTypeByDefaultValue enables or disables the inference of a key value's 432 // type when the Get function is used based upon a key's default value as 433 // opposed to the value returned based on the normal fetch logic. 434 // 435 // For example, if a key has a default value of []string{} and the same key 436 // is set via an environment variable to "a b c", a call to the Get function 437 // would return a string slice for the key if the key's type is inferred by 438 // the default value and the Get function would return: 439 // 440 // []string {"a", "b", "c"} 441 // 442 // Otherwise the Get function would return: 443 // 444 // "a b c" 445 func SetTypeByDefaultValue(enable bool) { v.SetTypeByDefaultValue(enable) } 446 func (v *Viper) SetTypeByDefaultValue(enable bool) { 447 v.typeByDefValue = enable 448 } 449 450 // Viper is essentially repository for configurations 451 // Get can retrieve any value given the key to use 452 // Get has the behavior of returning the value associated with the first 453 // place from where it is set. Viper will check in the following order: 454 // override, flag, env, config file, key/value store, default 455 // 456 // Get returns an interface. For a specific value use one of the Get____ methods. 457 func Get(key string) interface{} { return v.Get(key) } 458 func (v *Viper) Get(key string) interface{} { 459 path := strings.Split(key, v.keyDelim) 460 461 lcaseKey := strings.ToLower(key) 462 val := v.find(lcaseKey) 463 464 if val == nil { 465 source := v.find(strings.ToLower(path[0])) 466 if source != nil { 467 if reflect.TypeOf(source).Kind() == reflect.Map { 468 val = v.searchMap(cast.ToStringMap(source), path[1:]) 469 } 470 } 471 } 472 473 // if no other value is returned and a flag does exist for the value, 474 // get the flag's value even if the flag's value has not changed 475 if val == nil { 476 if flag, exists := v.pflags[lcaseKey]; exists { 477 jww.TRACE.Println(key, "get pflag default", val) 478 switch flag.ValueType() { 479 case "int", "int8", "int16", "int32", "int64": 480 val = cast.ToInt(flag.ValueString()) 481 case "bool": 482 val = cast.ToBool(flag.ValueString()) 483 default: 484 val = flag.ValueString() 485 } 486 } 487 } 488 489 if val == nil { 490 return nil 491 } 492 493 var valType interface{} 494 if !v.typeByDefValue { 495 valType = val 496 } else { 497 defVal, defExists := v.defaults[lcaseKey] 498 if defExists { 499 valType = defVal 500 } else { 501 valType = val 502 } 503 } 504 505 switch valType.(type) { 506 case bool: 507 return cast.ToBool(val) 508 case string: 509 return cast.ToString(val) 510 case int64, int32, int16, int8, int: 511 return cast.ToInt(val) 512 case float64, float32: 513 return cast.ToFloat64(val) 514 case time.Time: 515 return cast.ToTime(val) 516 case time.Duration: 517 return cast.ToDuration(val) 518 case []string: 519 return cast.ToStringSlice(val) 520 } 521 return val 522 } 523 524 // Returns new Viper instance representing a sub tree of this instance 525 func Sub(key string) *Viper { return v.Sub(key) } 526 func (v *Viper) Sub(key string) *Viper { 527 subv := New() 528 data := v.Get(key) 529 if reflect.TypeOf(data).Kind() == reflect.Map { 530 subv.config = cast.ToStringMap(data) 531 return subv 532 } else { 533 return nil 534 } 535 } 536 537 // Returns the value associated with the key as a string 538 func GetString(key string) string { return v.GetString(key) } 539 func (v *Viper) GetString(key string) string { 540 return cast.ToString(v.Get(key)) 541 } 542 543 // Returns the value associated with the key asa boolean 544 func GetBool(key string) bool { return v.GetBool(key) } 545 func (v *Viper) GetBool(key string) bool { 546 return cast.ToBool(v.Get(key)) 547 } 548 549 // Returns the value associated with the key as an integer 550 func GetInt(key string) int { return v.GetInt(key) } 551 func (v *Viper) GetInt(key string) int { 552 return cast.ToInt(v.Get(key)) 553 } 554 555 // Returns the value associated with the key as a float64 556 func GetFloat64(key string) float64 { return v.GetFloat64(key) } 557 func (v *Viper) GetFloat64(key string) float64 { 558 return cast.ToFloat64(v.Get(key)) 559 } 560 561 // Returns the value associated with the key as time 562 func GetTime(key string) time.Time { return v.GetTime(key) } 563 func (v *Viper) GetTime(key string) time.Time { 564 return cast.ToTime(v.Get(key)) 565 } 566 567 // Returns the value associated with the key as a duration 568 func GetDuration(key string) time.Duration { return v.GetDuration(key) } 569 func (v *Viper) GetDuration(key string) time.Duration { 570 return cast.ToDuration(v.Get(key)) 571 } 572 573 // Returns the value associated with the key as a slice of strings 574 func GetStringSlice(key string) []string { return v.GetStringSlice(key) } 575 func (v *Viper) GetStringSlice(key string) []string { 576 return cast.ToStringSlice(v.Get(key)) 577 } 578 579 // Returns the value associated with the key as a map of interfaces 580 func GetStringMap(key string) map[string]interface{} { return v.GetStringMap(key) } 581 func (v *Viper) GetStringMap(key string) map[string]interface{} { 582 return cast.ToStringMap(v.Get(key)) 583 } 584 585 // Returns the value associated with the key as a map of strings 586 func GetStringMapString(key string) map[string]string { return v.GetStringMapString(key) } 587 func (v *Viper) GetStringMapString(key string) map[string]string { 588 return cast.ToStringMapString(v.Get(key)) 589 } 590 591 // Returns the value associated with the key as a map to a slice of strings. 592 func GetStringMapStringSlice(key string) map[string][]string { return v.GetStringMapStringSlice(key) } 593 func (v *Viper) GetStringMapStringSlice(key string) map[string][]string { 594 return cast.ToStringMapStringSlice(v.Get(key)) 595 } 596 597 // Returns the size of the value associated with the given key 598 // in bytes. 599 func GetSizeInBytes(key string) uint { return v.GetSizeInBytes(key) } 600 func (v *Viper) GetSizeInBytes(key string) uint { 601 sizeStr := cast.ToString(v.Get(key)) 602 return parseSizeInBytes(sizeStr) 603 } 604 605 // Takes a single key and unmarshals it into a Struct 606 func UnmarshalKey(key string, rawVal interface{}) error { return v.UnmarshalKey(key, rawVal) } 607 func (v *Viper) UnmarshalKey(key string, rawVal interface{}) error { 608 return mapstructure.Decode(v.Get(key), rawVal) 609 } 610 611 // Unmarshals the config into a Struct. Make sure that the tags 612 // on the fields of the structure are properly set. 613 func Unmarshal(rawVal interface{}) error { return v.Unmarshal(rawVal) } 614 func (v *Viper) Unmarshal(rawVal interface{}) error { 615 err := mapstructure.WeakDecode(v.AllSettings(), rawVal) 616 617 if err != nil { 618 return err 619 } 620 621 v.insensitiviseMaps() 622 623 return nil 624 } 625 626 // Bind a full flag set to the configuration, using each flag's long 627 // name as the config key. 628 func BindPFlags(flags *pflag.FlagSet) (err error) { return v.BindPFlags(flags) } 629 func (v *Viper) BindPFlags(flags *pflag.FlagSet) (err error) { 630 return v.BindFlagValues(pflagValueSet{flags}) 631 } 632 633 // Bind a specific key to a pflag (as used by cobra) 634 // Example(where serverCmd is a Cobra instance): 635 // 636 // serverCmd.Flags().Int("port", 1138, "Port to run Application server on") 637 // Viper.BindPFlag("port", serverCmd.Flags().Lookup("port")) 638 // 639 func BindPFlag(key string, flag *pflag.Flag) (err error) { return v.BindPFlag(key, flag) } 640 func (v *Viper) BindPFlag(key string, flag *pflag.Flag) (err error) { 641 return v.BindFlagValue(key, pflagValue{flag}) 642 } 643 644 // Bind a full FlagValue set to the configuration, using each flag's long 645 // name as the config key. 646 func BindFlagValues(flags FlagValueSet) (err error) { return v.BindFlagValues(flags) } 647 func (v *Viper) BindFlagValues(flags FlagValueSet) (err error) { 648 flags.VisitAll(func(flag FlagValue) { 649 if err = v.BindFlagValue(flag.Name(), flag); err != nil { 650 return 651 } 652 }) 653 return nil 654 } 655 656 // Bind a specific key to a FlagValue. 657 // Example(where serverCmd is a Cobra instance): 658 // 659 // serverCmd.Flags().Int("port", 1138, "Port to run Application server on") 660 // Viper.BindFlagValue("port", serverCmd.Flags().Lookup("port")) 661 // 662 func BindFlagValue(key string, flag FlagValue) (err error) { return v.BindFlagValue(key, flag) } 663 func (v *Viper) BindFlagValue(key string, flag FlagValue) (err error) { 664 if flag == nil { 665 return fmt.Errorf("flag for %q is nil", key) 666 } 667 v.pflags[strings.ToLower(key)] = flag 668 return nil 669 } 670 671 // Binds a Viper key to a ENV variable 672 // ENV variables are case sensitive 673 // If only a key is provided, it will use the env key matching the key, uppercased. 674 // EnvPrefix will be used when set when env name is not provided. 675 func BindEnv(input ...string) (err error) { return v.BindEnv(input...) } 676 func (v *Viper) BindEnv(input ...string) (err error) { 677 var key, envkey string 678 if len(input) == 0 { 679 return fmt.Errorf("BindEnv missing key to bind to") 680 } 681 682 key = strings.ToLower(input[0]) 683 684 if len(input) == 1 { 685 envkey = v.mergeWithEnvPrefix(key) 686 } else { 687 envkey = input[1] 688 } 689 690 v.env[key] = envkey 691 692 return nil 693 } 694 695 // Given a key, find the value 696 // Viper will check in the following order: 697 // flag, env, config file, key/value store, default 698 // Viper will check to see if an alias exists first 699 func (v *Viper) find(key string) interface{} { 700 var val interface{} 701 var exists bool 702 703 // if the requested key is an alias, then return the proper key 704 key = v.realKey(key) 705 706 // PFlag Override first 707 flag, exists := v.pflags[key] 708 if exists && flag.HasChanged() { 709 jww.TRACE.Println(key, "found in override (via pflag):", flag.ValueString()) 710 switch flag.ValueType() { 711 case "int", "int8", "int16", "int32", "int64": 712 return cast.ToInt(flag.ValueString()) 713 case "bool": 714 return cast.ToBool(flag.ValueString()) 715 default: 716 return flag.ValueString() 717 } 718 } 719 720 val, exists = v.override[key] 721 if exists { 722 jww.TRACE.Println(key, "found in override:", val) 723 return val 724 } 725 726 if v.automaticEnvApplied { 727 // even if it hasn't been registered, if automaticEnv is used, 728 // check any Get request 729 if val = v.getEnv(v.mergeWithEnvPrefix(key)); val != "" { 730 jww.TRACE.Println(key, "found in environment with val:", val) 731 return val 732 } 733 } 734 735 envkey, exists := v.env[key] 736 if exists { 737 jww.TRACE.Println(key, "registered as env var", envkey) 738 if val = v.getEnv(envkey); val != "" { 739 jww.TRACE.Println(envkey, "found in environment with val:", val) 740 return val 741 } else { 742 jww.TRACE.Println(envkey, "env value unset:") 743 } 744 } 745 746 val, exists = v.config[key] 747 if exists { 748 jww.TRACE.Println(key, "found in config:", val) 749 return val 750 } 751 752 // Test for nested config parameter 753 if strings.Contains(key, v.keyDelim) { 754 path := strings.Split(key, v.keyDelim) 755 756 source := v.find(path[0]) 757 if source != nil { 758 if reflect.TypeOf(source).Kind() == reflect.Map { 759 val := v.searchMap(cast.ToStringMap(source), path[1:]) 760 jww.TRACE.Println(key, "found in nested config:", val) 761 return val 762 } 763 } 764 } 765 766 val, exists = v.kvstore[key] 767 if exists { 768 jww.TRACE.Println(key, "found in key/value store:", val) 769 return val 770 } 771 772 val, exists = v.defaults[key] 773 if exists { 774 jww.TRACE.Println(key, "found in defaults:", val) 775 return val 776 } 777 778 return nil 779 } 780 781 // Check to see if the key has been set in any of the data locations 782 func IsSet(key string) bool { return v.IsSet(key) } 783 func (v *Viper) IsSet(key string) bool { 784 path := strings.Split(key, v.keyDelim) 785 786 lcaseKey := strings.ToLower(key) 787 val := v.find(lcaseKey) 788 789 if val == nil { 790 source := v.find(strings.ToLower(path[0])) 791 if source != nil { 792 if reflect.TypeOf(source).Kind() == reflect.Map { 793 val = v.searchMap(cast.ToStringMap(source), path[1:]) 794 } 795 } 796 } 797 798 return val != nil 799 } 800 801 // Have Viper check ENV variables for all 802 // keys set in config, default & flags 803 func AutomaticEnv() { v.AutomaticEnv() } 804 func (v *Viper) AutomaticEnv() { 805 v.automaticEnvApplied = true 806 } 807 808 // SetEnvKeyReplacer sets the strings.Replacer on the viper object 809 // Useful for mapping an environmental variable to a key that does 810 // not match it. 811 func SetEnvKeyReplacer(r *strings.Replacer) { v.SetEnvKeyReplacer(r) } 812 func (v *Viper) SetEnvKeyReplacer(r *strings.Replacer) { 813 v.envKeyReplacer = r 814 } 815 816 // Aliases provide another accessor for the same key. 817 // This enables one to change a name without breaking the application 818 func RegisterAlias(alias string, key string) { v.RegisterAlias(alias, key) } 819 func (v *Viper) RegisterAlias(alias string, key string) { 820 v.registerAlias(alias, strings.ToLower(key)) 821 } 822 823 func (v *Viper) registerAlias(alias string, key string) { 824 alias = strings.ToLower(alias) 825 if alias != key && alias != v.realKey(key) { 826 _, exists := v.aliases[alias] 827 828 if !exists { 829 // if we alias something that exists in one of the maps to another 830 // name, we'll never be able to get that value using the original 831 // name, so move the config value to the new realkey. 832 if val, ok := v.config[alias]; ok { 833 delete(v.config, alias) 834 v.config[key] = val 835 } 836 if val, ok := v.kvstore[alias]; ok { 837 delete(v.kvstore, alias) 838 v.kvstore[key] = val 839 } 840 if val, ok := v.defaults[alias]; ok { 841 delete(v.defaults, alias) 842 v.defaults[key] = val 843 } 844 if val, ok := v.override[alias]; ok { 845 delete(v.override, alias) 846 v.override[key] = val 847 } 848 v.aliases[alias] = key 849 } 850 } else { 851 jww.WARN.Println("Creating circular reference alias", alias, key, v.realKey(key)) 852 } 853 } 854 855 func (v *Viper) realKey(key string) string { 856 newkey, exists := v.aliases[key] 857 if exists { 858 jww.DEBUG.Println("Alias", key, "to", newkey) 859 return v.realKey(newkey) 860 } else { 861 return key 862 } 863 } 864 865 // Check to see if the given key (or an alias) is in the config file 866 func InConfig(key string) bool { return v.InConfig(key) } 867 func (v *Viper) InConfig(key string) bool { 868 // if the requested key is an alias, then return the proper key 869 key = v.realKey(key) 870 871 _, exists := v.config[key] 872 return exists 873 } 874 875 // Set the default value for this key. 876 // Default only used when no value is provided by the user via flag, config or ENV. 877 func SetDefault(key string, value interface{}) { v.SetDefault(key, value) } 878 func (v *Viper) SetDefault(key string, value interface{}) { 879 // If alias passed in, then set the proper default 880 key = v.realKey(strings.ToLower(key)) 881 v.defaults[key] = value 882 } 883 884 // Sets the value for the key in the override regiser. 885 // Will be used instead of values obtained via 886 // flags, config file, ENV, default, or key/value store 887 func Set(key string, value interface{}) { v.Set(key, value) } 888 func (v *Viper) Set(key string, value interface{}) { 889 // If alias passed in, then set the proper override 890 key = v.realKey(strings.ToLower(key)) 891 v.override[key] = value 892 } 893 894 // Viper will discover and load the configuration file from disk 895 // and key/value stores, searching in one of the defined paths. 896 func ReadInConfig() error { return v.ReadInConfig() } 897 func (v *Viper) ReadInConfig() error { 898 jww.INFO.Println("Attempting to read in config file") 899 if !stringInSlice(v.getConfigType(), SupportedExts) { 900 return UnsupportedConfigError(v.getConfigType()) 901 } 902 903 file, err := ioutil.ReadFile(v.getConfigFile()) 904 if err != nil { 905 return err 906 } 907 908 v.config = make(map[string]interface{}) 909 910 return v.unmarshalReader(bytes.NewReader(file), v.config) 911 } 912 913 // MergeInConfig merges a new configuration with an existing config. 914 func MergeInConfig() error { return v.MergeInConfig() } 915 func (v *Viper) MergeInConfig() error { 916 jww.INFO.Println("Attempting to merge in config file") 917 if !stringInSlice(v.getConfigType(), SupportedExts) { 918 return UnsupportedConfigError(v.getConfigType()) 919 } 920 921 file, err := ioutil.ReadFile(v.getConfigFile()) 922 if err != nil { 923 return err 924 } 925 926 return v.MergeConfig(bytes.NewReader(file)) 927 } 928 929 // Viper will read a configuration file, setting existing keys to nil if the 930 // key does not exist in the file. 931 func ReadConfig(in io.Reader) error { return v.ReadConfig(in) } 932 func (v *Viper) ReadConfig(in io.Reader) error { 933 v.config = make(map[string]interface{}) 934 return v.unmarshalReader(in, v.config) 935 } 936 937 // MergeConfig merges a new configuration with an existing config. 938 func MergeConfig(in io.Reader) error { return v.MergeConfig(in) } 939 func (v *Viper) MergeConfig(in io.Reader) error { 940 if v.config == nil { 941 v.config = make(map[string]interface{}) 942 } 943 cfg := make(map[string]interface{}) 944 if err := v.unmarshalReader(in, cfg); err != nil { 945 return err 946 } 947 mergeMaps(cfg, v.config, nil) 948 return nil 949 } 950 951 func keyExists(k string, m map[string]interface{}) string { 952 lk := strings.ToLower(k) 953 for mk := range m { 954 lmk := strings.ToLower(mk) 955 if lmk == lk { 956 return mk 957 } 958 } 959 return "" 960 } 961 962 func castToMapStringInterface( 963 src map[interface{}]interface{}) map[string]interface{} { 964 tgt := map[string]interface{}{} 965 for k, v := range src { 966 tgt[fmt.Sprintf("%v", k)] = v 967 } 968 return tgt 969 } 970 971 // mergeMaps merges two maps. The `itgt` parameter is for handling go-yaml's 972 // insistence on parsing nested structures as `map[interface{}]interface{}` 973 // instead of using a `string` as the key for nest structures beyond one level 974 // deep. Both map types are supported as there is a go-yaml fork that uses 975 // `map[string]interface{}` instead. 976 func mergeMaps( 977 src, tgt map[string]interface{}, itgt map[interface{}]interface{}) { 978 for sk, sv := range src { 979 tk := keyExists(sk, tgt) 980 if tk == "" { 981 jww.TRACE.Printf("tk=\"\", tgt[%s]=%v", sk, sv) 982 tgt[sk] = sv 983 if itgt != nil { 984 itgt[sk] = sv 985 } 986 continue 987 } 988 989 tv, ok := tgt[tk] 990 if !ok { 991 jww.TRACE.Printf("tgt[%s] != ok, tgt[%s]=%v", tk, sk, sv) 992 tgt[sk] = sv 993 if itgt != nil { 994 itgt[sk] = sv 995 } 996 continue 997 } 998 999 svType := reflect.TypeOf(sv) 1000 tvType := reflect.TypeOf(tv) 1001 if svType != tvType { 1002 jww.ERROR.Printf( 1003 "svType != tvType; key=%s, st=%v, tt=%v, sv=%v, tv=%v", 1004 sk, svType, tvType, sv, tv) 1005 continue 1006 } 1007 1008 jww.TRACE.Printf("processing key=%s, st=%v, tt=%v, sv=%v, tv=%v", 1009 sk, svType, tvType, sv, tv) 1010 1011 switch ttv := tv.(type) { 1012 case map[interface{}]interface{}: 1013 jww.TRACE.Printf("merging maps (must convert)") 1014 tsv := sv.(map[interface{}]interface{}) 1015 ssv := castToMapStringInterface(tsv) 1016 stv := castToMapStringInterface(ttv) 1017 mergeMaps(ssv, stv, ttv) 1018 case map[string]interface{}: 1019 jww.TRACE.Printf("merging maps") 1020 mergeMaps(sv.(map[string]interface{}), ttv, nil) 1021 default: 1022 jww.TRACE.Printf("setting value") 1023 tgt[tk] = sv 1024 if itgt != nil { 1025 itgt[tk] = sv 1026 } 1027 } 1028 } 1029 } 1030 1031 // func ReadBufConfig(buf *bytes.Buffer) error { return v.ReadBufConfig(buf) } 1032 // func (v *Viper) ReadBufConfig(buf *bytes.Buffer) error { 1033 // v.config = make(map[string]interface{}) 1034 // return v.unmarshalReader(buf, v.config) 1035 // } 1036 1037 // Attempts to get configuration from a remote source 1038 // and read it in the remote configuration registry. 1039 func ReadRemoteConfig() error { return v.ReadRemoteConfig() } 1040 func (v *Viper) ReadRemoteConfig() error { 1041 err := v.getKeyValueConfig() 1042 if err != nil { 1043 return err 1044 } 1045 return nil 1046 } 1047 1048 func WatchRemoteConfig() error { return v.WatchRemoteConfig() } 1049 func (v *Viper) WatchRemoteConfig() error { 1050 err := v.watchKeyValueConfig() 1051 if err != nil { 1052 return err 1053 } 1054 return nil 1055 } 1056 1057 // Unmarshall a Reader into a map 1058 // Should probably be an unexported function 1059 func unmarshalReader(in io.Reader, c map[string]interface{}) error { 1060 return v.unmarshalReader(in, c) 1061 } 1062 1063 func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error { 1064 return unmarshallConfigReader(in, c, v.getConfigType()) 1065 } 1066 1067 func (v *Viper) insensitiviseMaps() { 1068 insensitiviseMap(v.config) 1069 insensitiviseMap(v.defaults) 1070 insensitiviseMap(v.override) 1071 insensitiviseMap(v.kvstore) 1072 } 1073 1074 // retrieve the first found remote configuration 1075 func (v *Viper) getKeyValueConfig() error { 1076 if RemoteConfig == nil { 1077 return RemoteConfigError("Enable the remote features by doing a blank import of the viper/remote package: '_ github.com/spf13/viper/remote'") 1078 } 1079 1080 for _, rp := range v.remoteProviders { 1081 val, err := v.getRemoteConfig(rp) 1082 if err != nil { 1083 continue 1084 } 1085 v.kvstore = val 1086 return nil 1087 } 1088 return RemoteConfigError("No Files Found") 1089 } 1090 1091 func (v *Viper) getRemoteConfig(provider *defaultRemoteProvider) (map[string]interface{}, error) { 1092 1093 reader, err := RemoteConfig.Get(provider) 1094 if err != nil { 1095 return nil, err 1096 } 1097 err = v.unmarshalReader(reader, v.kvstore) 1098 return v.kvstore, err 1099 } 1100 1101 // retrieve the first found remote configuration 1102 func (v *Viper) watchKeyValueConfig() error { 1103 for _, rp := range v.remoteProviders { 1104 val, err := v.watchRemoteConfig(rp) 1105 if err != nil { 1106 continue 1107 } 1108 v.kvstore = val 1109 return nil 1110 } 1111 return RemoteConfigError("No Files Found") 1112 } 1113 1114 func (v *Viper) watchRemoteConfig(provider *defaultRemoteProvider) (map[string]interface{}, error) { 1115 reader, err := RemoteConfig.Watch(provider) 1116 if err != nil { 1117 return nil, err 1118 } 1119 err = v.unmarshalReader(reader, v.kvstore) 1120 return v.kvstore, err 1121 } 1122 1123 // Return all keys regardless where they are set 1124 func AllKeys() []string { return v.AllKeys() } 1125 func (v *Viper) AllKeys() []string { 1126 m := map[string]struct{}{} 1127 1128 for key, _ := range v.defaults { 1129 m[strings.ToLower(key)] = struct{}{} 1130 } 1131 1132 for key, _ := range v.pflags { 1133 m[strings.ToLower(key)] = struct{}{} 1134 } 1135 1136 for key, _ := range v.env { 1137 m[strings.ToLower(key)] = struct{}{} 1138 } 1139 1140 for key, _ := range v.config { 1141 m[strings.ToLower(key)] = struct{}{} 1142 } 1143 1144 for key, _ := range v.kvstore { 1145 m[strings.ToLower(key)] = struct{}{} 1146 } 1147 1148 for key, _ := range v.override { 1149 m[strings.ToLower(key)] = struct{}{} 1150 } 1151 1152 a := []string{} 1153 for x, _ := range m { 1154 a = append(a, x) 1155 } 1156 1157 return a 1158 } 1159 1160 // Return all settings as a map[string]interface{} 1161 func AllSettings() map[string]interface{} { return v.AllSettings() } 1162 func (v *Viper) AllSettings() map[string]interface{} { 1163 m := map[string]interface{}{} 1164 for _, x := range v.AllKeys() { 1165 m[x] = v.Get(x) 1166 } 1167 1168 return m 1169 } 1170 1171 // Name for the config file. 1172 // Does not include extension. 1173 func SetConfigName(in string) { v.SetConfigName(in) } 1174 func (v *Viper) SetConfigName(in string) { 1175 if in != "" { 1176 v.configName = in 1177 } 1178 } 1179 1180 // Sets the type of the configuration returned by the 1181 // remote source, e.g. "json". 1182 func SetConfigType(in string) { v.SetConfigType(in) } 1183 func (v *Viper) SetConfigType(in string) { 1184 if in != "" { 1185 v.configType = in 1186 } 1187 } 1188 1189 func (v *Viper) getConfigType() string { 1190 if v.configType != "" { 1191 return v.configType 1192 } 1193 1194 cf := v.getConfigFile() 1195 ext := filepath.Ext(cf) 1196 1197 if len(ext) > 1 { 1198 return ext[1:] 1199 } else { 1200 return "" 1201 } 1202 } 1203 1204 func (v *Viper) getConfigFile() string { 1205 // if explicitly set, then use it 1206 if v.configFile != "" { 1207 return v.configFile 1208 } 1209 1210 cf, err := v.findConfigFile() 1211 if err != nil { 1212 return "" 1213 } 1214 1215 v.configFile = cf 1216 return v.getConfigFile() 1217 } 1218 1219 func (v *Viper) searchInPath(in string) (filename string) { 1220 jww.DEBUG.Println("Searching for config in ", in) 1221 for _, ext := range SupportedExts { 1222 jww.DEBUG.Println("Checking for", filepath.Join(in, v.configName+"."+ext)) 1223 if b, _ := exists(filepath.Join(in, v.configName+"."+ext)); b { 1224 jww.DEBUG.Println("Found: ", filepath.Join(in, v.configName+"."+ext)) 1225 return filepath.Join(in, v.configName+"."+ext) 1226 } 1227 } 1228 1229 return "" 1230 } 1231 1232 // search all configPaths for any config file. 1233 // Returns the first path that exists (and is a config file) 1234 func (v *Viper) findConfigFile() (string, error) { 1235 1236 jww.INFO.Println("Searching for config in ", v.configPaths) 1237 1238 for _, cp := range v.configPaths { 1239 file := v.searchInPath(cp) 1240 if file != "" { 1241 return file, nil 1242 } 1243 } 1244 return "", ConfigFileNotFoundError{v.configName, fmt.Sprintf("%s", v.configPaths)} 1245 } 1246 1247 // Prints all configuration registries for debugging 1248 // purposes. 1249 func Debug() { v.Debug() } 1250 func (v *Viper) Debug() { 1251 fmt.Println("Aliases:") 1252 pretty.Println(v.aliases) 1253 fmt.Println("Override:") 1254 pretty.Println(v.override) 1255 fmt.Println("PFlags") 1256 pretty.Println(v.pflags) 1257 fmt.Println("Env:") 1258 pretty.Println(v.env) 1259 fmt.Println("Key/Value Store:") 1260 pretty.Println(v.kvstore) 1261 fmt.Println("Config:") 1262 pretty.Println(v.config) 1263 fmt.Println("Defaults:") 1264 pretty.Println(v.defaults) 1265 }