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