1 // Copyright © 2014 Steve Francia <spf@spf13.com>.
3 // Use of this source code is governed by an MIT-style
4 // license that can be found in the LICENSE file.
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.
11 // Each item takes precedence over the item below it:
34 "github.com/fsnotify/fsnotify"
35 "github.com/mitchellh/mapstructure"
36 "github.com/spf13/afero"
37 "github.com/spf13/cast"
38 jww "github.com/spf13/jwalterweatherman"
39 "github.com/spf13/pflag"
44 type RemoteResponse struct {
53 type remoteConfigFactory interface {
54 Get(rp RemoteProvider) (io.Reader, error)
55 Watch(rp RemoteProvider) (io.Reader, error)
56 WatchChannel(rp RemoteProvider) (<-chan *RemoteResponse, chan bool)
59 // RemoteConfig is optional, see the remote package
60 var RemoteConfig remoteConfigFactory
62 // UnsupportedConfigError denotes encountering an unsupported
63 // configuration filetype.
64 type UnsupportedConfigError string
66 // Error returns the formatted configuration error.
67 func (str UnsupportedConfigError) Error() string {
68 return fmt.Sprintf("Unsupported Config Type %q", string(str))
71 // UnsupportedRemoteProviderError denotes encountering an unsupported remote
72 // provider. Currently only etcd and Consul are supported.
73 type UnsupportedRemoteProviderError string
75 // Error returns the formatted remote provider error.
76 func (str UnsupportedRemoteProviderError) Error() string {
77 return fmt.Sprintf("Unsupported Remote Provider Type %q", string(str))
80 // RemoteConfigError denotes encountering an error while trying to
81 // pull the configuration from the remote provider.
82 type RemoteConfigError string
84 // Error returns the formatted remote provider error
85 func (rce RemoteConfigError) Error() string {
86 return fmt.Sprintf("Remote Configurations Error: %s", string(rce))
89 // ConfigFileNotFoundError denotes failing to find configuration file.
90 type ConfigFileNotFoundError struct {
91 name, locations string
94 // Error returns the formatted configuration error.
95 func (fnfe ConfigFileNotFoundError) Error() string {
96 return fmt.Sprintf("Config File %q Not Found in %q", fnfe.name, fnfe.locations)
99 // Viper is a prioritized configuration registry. It
100 // maintains a set of configuration sources, fetches
101 // values to populate those, and provides them according
102 // to the source's priority.
103 // The priority of the sources is the following:
108 // 5. key/value store
111 // For example, if values from the following sources were loaded:
115 // "user": "default",
116 // "endpoint": "https://localhost"
120 // "secret": "defaultsecret"
123 // "secret": "somesecretkey"
126 // The resulting config will have the following values:
129 // "secret": "somesecretkey",
131 // "endpoint": "https://localhost"
134 // Delimiter that separates a list of keys
135 // used to access a nested value in one go
138 // A set of paths to look for the config file in
141 // The filesystem to read config from.
144 // A set of remote providers to search for the configuration
145 remoteProviders []*defaultRemoteProvider
147 // Name of file to look for inside the path
153 automaticEnvApplied bool
154 envKeyReplacer *strings.Replacer
156 config map[string]interface{}
157 override map[string]interface{}
158 defaults map[string]interface{}
159 kvstore map[string]interface{}
160 pflags map[string]FlagValue
161 env map[string]string
162 aliases map[string]string
165 onConfigChange func(fsnotify.Event)
168 // New returns an initialized Viper instance.
172 v.configName = "config"
173 v.fs = afero.NewOsFs()
174 v.config = make(map[string]interface{})
175 v.override = make(map[string]interface{})
176 v.defaults = make(map[string]interface{})
177 v.kvstore = make(map[string]interface{})
178 v.pflags = make(map[string]FlagValue)
179 v.env = make(map[string]string)
180 v.aliases = make(map[string]string)
181 v.typeByDefValue = false
186 // Intended for testing, will reset all to default settings.
187 // In the public interface for the viper package so applications
188 // can use it in their testing as well.
191 SupportedExts = []string{"json", "toml", "yaml", "yml", "hcl"}
192 SupportedRemoteProviders = []string{"etcd", "consul"}
195 type defaultRemoteProvider struct {
202 func (rp defaultRemoteProvider) Provider() string {
206 func (rp defaultRemoteProvider) Endpoint() string {
210 func (rp defaultRemoteProvider) Path() string {
214 func (rp defaultRemoteProvider) SecretKeyring() string {
215 return rp.secretKeyring
218 // RemoteProvider stores the configuration necessary
219 // to connect to a remote key/value store.
220 // Optional secretKeyring to unencrypt encrypted values
222 type RemoteProvider interface {
226 SecretKeyring() string
229 // SupportedExts are universally supported extensions.
230 var SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl"}
232 // SupportedRemoteProviders are universally supported remote providers.
233 var SupportedRemoteProviders = []string{"etcd", "consul"}
235 func OnConfigChange(run func(in fsnotify.Event)) { v.OnConfigChange(run) }
236 func (v *Viper) OnConfigChange(run func(in fsnotify.Event)) {
237 v.onConfigChange = run
240 func WatchConfig() { v.WatchConfig() }
241 func (v *Viper) WatchConfig() {
243 watcher, err := fsnotify.NewWatcher()
247 defer watcher.Close()
249 // we have to watch the entire directory to pick up renames/atomic saves in a cross-platform way
250 filename, err := v.getConfigFile()
252 log.Println("error:", err)
256 configFile := filepath.Clean(filename)
257 configDir, _ := filepath.Split(configFile)
259 done := make(chan bool)
263 case event := <-watcher.Events:
264 // we only care about the config file
265 if filepath.Clean(event.Name) == configFile {
266 if event.Op&fsnotify.Write == fsnotify.Write || event.Op&fsnotify.Create == fsnotify.Create {
267 err := v.ReadInConfig()
269 log.Println("error:", err)
271 v.onConfigChange(event)
274 case err := <-watcher.Errors:
275 log.Println("error:", err)
280 watcher.Add(configDir)
285 // SetConfigFile explicitly defines the path, name and extension of the config file.
286 // Viper will use this and not check any of the config paths.
287 func SetConfigFile(in string) { v.SetConfigFile(in) }
288 func (v *Viper) SetConfigFile(in string) {
294 // SetEnvPrefix defines a prefix that ENVIRONMENT variables will use.
295 // E.g. if your prefix is "spf", the env registry will look for env
296 // variables that start with "SPF_".
297 func SetEnvPrefix(in string) { v.SetEnvPrefix(in) }
298 func (v *Viper) SetEnvPrefix(in string) {
304 func (v *Viper) mergeWithEnvPrefix(in string) string {
305 if v.envPrefix != "" {
306 return strings.ToUpper(v.envPrefix + "_" + in)
309 return strings.ToUpper(in)
312 // TODO: should getEnv logic be moved into find(). Can generalize the use of
313 // rewriting keys many things, Ex: Get('someKey') -> some_key
314 // (camel case to snake case for JSON keys perhaps)
316 // getEnv is a wrapper around os.Getenv which replaces characters in the original
317 // key. This allows env vars which have different keys than the config object
319 func (v *Viper) getEnv(key string) string {
320 if v.envKeyReplacer != nil {
321 key = v.envKeyReplacer.Replace(key)
323 return os.Getenv(key)
326 // ConfigFileUsed returns the file used to populate the config registry.
327 func ConfigFileUsed() string { return v.ConfigFileUsed() }
328 func (v *Viper) ConfigFileUsed() string { return v.configFile }
330 // AddConfigPath adds a path for Viper to search for the config file in.
331 // Can be called multiple times to define multiple search paths.
332 func AddConfigPath(in string) { v.AddConfigPath(in) }
333 func (v *Viper) AddConfigPath(in string) {
335 absin := absPathify(in)
336 jww.INFO.Println("adding", absin, "to paths to search")
337 if !stringInSlice(absin, v.configPaths) {
338 v.configPaths = append(v.configPaths, absin)
343 // AddRemoteProvider adds a remote configuration source.
344 // Remote Providers are searched in the order they are added.
345 // provider is a string value, "etcd" or "consul" are currently supported.
346 // endpoint is the url. etcd requires http://ip:port consul requires ip:port
347 // path is the path in the k/v store to retrieve configuration
348 // To retrieve a config file called myapp.json from /configs/myapp.json
349 // you should set path to /configs and set config name (SetConfigName()) to
351 func AddRemoteProvider(provider, endpoint, path string) error {
352 return v.AddRemoteProvider(provider, endpoint, path)
354 func (v *Viper) AddRemoteProvider(provider, endpoint, path string) error {
355 if !stringInSlice(provider, SupportedRemoteProviders) {
356 return UnsupportedRemoteProviderError(provider)
358 if provider != "" && endpoint != "" {
359 jww.INFO.Printf("adding %s:%s to remote provider list", provider, endpoint)
360 rp := &defaultRemoteProvider{
365 if !v.providerPathExists(rp) {
366 v.remoteProviders = append(v.remoteProviders, rp)
372 // AddSecureRemoteProvider adds a remote configuration source.
373 // Secure Remote Providers are searched in the order they are added.
374 // provider is a string value, "etcd" or "consul" are currently supported.
375 // endpoint is the url. etcd requires http://ip:port consul requires ip:port
376 // secretkeyring is the filepath to your openpgp secret keyring. e.g. /etc/secrets/myring.gpg
377 // path is the path in the k/v store to retrieve configuration
378 // To retrieve a config file called myapp.json from /configs/myapp.json
379 // you should set path to /configs and set config name (SetConfigName()) to
381 // Secure Remote Providers are implemented with github.com/xordataexchange/crypt
382 func AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error {
383 return v.AddSecureRemoteProvider(provider, endpoint, path, secretkeyring)
386 func (v *Viper) AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error {
387 if !stringInSlice(provider, SupportedRemoteProviders) {
388 return UnsupportedRemoteProviderError(provider)
390 if provider != "" && endpoint != "" {
391 jww.INFO.Printf("adding %s:%s to remote provider list", provider, endpoint)
392 rp := &defaultRemoteProvider{
396 secretKeyring: secretkeyring,
398 if !v.providerPathExists(rp) {
399 v.remoteProviders = append(v.remoteProviders, rp)
405 func (v *Viper) providerPathExists(p *defaultRemoteProvider) bool {
406 for _, y := range v.remoteProviders {
407 if reflect.DeepEqual(y, p) {
414 // searchMap recursively searches for a value for path in source map.
415 // Returns nil if not found.
416 // Note: This assumes that the path entries and map keys are lower cased.
417 func (v *Viper) searchMap(source map[string]interface{}, path []string) interface{} {
422 next, ok := source[path[0]]
431 case map[interface{}]interface{}:
432 return v.searchMap(cast.ToStringMap(next), path[1:])
433 case map[string]interface{}:
434 // Type assertion is safe here since it is only reached
435 // if the type of `next` is the same as the type being asserted
436 return v.searchMap(next.(map[string]interface{}), path[1:])
438 // got a value but nested key expected, return "nil" for not found
445 // searchMapWithPathPrefixes recursively searches for a value for path in source map.
447 // While searchMap() considers each path element as a single map key, this
448 // function searches for, and prioritizes, merged path elements.
449 // e.g., if in the source, "foo" is defined with a sub-key "bar", and "foo.bar"
450 // is also defined, this latter value is returned for path ["foo", "bar"].
452 // This should be useful only at config level (other maps may not contain dots
455 // Note: This assumes that the path entries and map keys are lower cased.
456 func (v *Viper) searchMapWithPathPrefixes(source map[string]interface{}, path []string) interface{} {
461 // search for path prefixes, starting from the longest one
462 for i := len(path); i > 0; i-- {
463 prefixKey := strings.ToLower(strings.Join(path[0:i], v.keyDelim))
465 next, ok := source[prefixKey]
475 case map[interface{}]interface{}:
476 val = v.searchMapWithPathPrefixes(cast.ToStringMap(next), path[i:])
477 case map[string]interface{}:
478 // Type assertion is safe here since it is only reached
479 // if the type of `next` is the same as the type being asserted
480 val = v.searchMapWithPathPrefixes(next.(map[string]interface{}), path[i:])
482 // got a value but nested key expected, do nothing and look for next prefix
494 // isPathShadowedInDeepMap makes sure the given path is not shadowed somewhere
495 // on its path in the map.
496 // e.g., if "foo.bar" has a value in the given map, it “shadows”
497 // "foo.bar.baz" in a lower-priority map
498 func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]interface{}) string {
499 var parentVal interface{}
500 for i := 1; i < len(path); i++ {
501 parentVal = v.searchMap(m, path[0:i])
502 if parentVal == nil {
503 // not found, no need to add more path elements
506 switch parentVal.(type) {
507 case map[interface{}]interface{}:
509 case map[string]interface{}:
512 // parentVal is a regular value which shadows "path"
513 return strings.Join(path[0:i], v.keyDelim)
519 // isPathShadowedInFlatMap makes sure the given path is not shadowed somewhere
520 // in a sub-path of the map.
521 // e.g., if "foo.bar" has a value in the given map, it “shadows”
522 // "foo.bar.baz" in a lower-priority map
523 func (v *Viper) isPathShadowedInFlatMap(path []string, mi interface{}) string {
525 var m map[string]interface{}
527 case map[string]string, map[string]FlagValue:
528 m = cast.ToStringMap(mi)
535 for i := 1; i < len(path); i++ {
536 parentKey = strings.Join(path[0:i], v.keyDelim)
537 if _, ok := m[parentKey]; ok {
544 // isPathShadowedInAutoEnv makes sure the given path is not shadowed somewhere
545 // in the environment, when automatic env is on.
546 // e.g., if "foo.bar" has a value in the environment, it “shadows”
547 // "foo.bar.baz" in a lower-priority map
548 func (v *Viper) isPathShadowedInAutoEnv(path []string) string {
551 for i := 1; i < len(path); i++ {
552 parentKey = strings.Join(path[0:i], v.keyDelim)
553 if val = v.getEnv(v.mergeWithEnvPrefix(parentKey)); val != "" {
560 // SetTypeByDefaultValue enables or disables the inference of a key value's
561 // type when the Get function is used based upon a key's default value as
562 // opposed to the value returned based on the normal fetch logic.
564 // For example, if a key has a default value of []string{} and the same key
565 // is set via an environment variable to "a b c", a call to the Get function
566 // would return a string slice for the key if the key's type is inferred by
567 // the default value and the Get function would return:
569 // []string {"a", "b", "c"}
571 // Otherwise the Get function would return:
574 func SetTypeByDefaultValue(enable bool) { v.SetTypeByDefaultValue(enable) }
575 func (v *Viper) SetTypeByDefaultValue(enable bool) {
576 v.typeByDefValue = enable
579 // GetViper gets the global Viper instance.
580 func GetViper() *Viper {
584 // Get can retrieve any value given the key to use.
585 // Get is case-insensitive for a key.
586 // Get has the behavior of returning the value associated with the first
587 // place from where it is set. Viper will check in the following order:
588 // override, flag, env, config file, key/value store, default
590 // Get returns an interface. For a specific value use one of the Get____ methods.
591 func Get(key string) interface{} { return v.Get(key) }
592 func (v *Viper) Get(key string) interface{} {
593 lcaseKey := strings.ToLower(key)
594 val := v.find(lcaseKey)
599 if v.typeByDefValue {
600 // TODO(bep) this branch isn't covered by a single test.
602 path := strings.Split(lcaseKey, v.keyDelim)
603 defVal := v.searchMap(v.defaults, path)
608 switch valType.(type) {
610 return cast.ToBool(val)
612 return cast.ToString(val)
613 case int64, int32, int16, int8, int:
614 return cast.ToInt(val)
615 case float64, float32:
616 return cast.ToFloat64(val)
618 return cast.ToTime(val)
620 return cast.ToDuration(val)
622 return cast.ToStringSlice(val)
629 // Sub returns new Viper instance representing a sub tree of this instance.
630 // Sub is case-insensitive for a key.
631 func Sub(key string) *Viper { return v.Sub(key) }
632 func (v *Viper) Sub(key string) *Viper {
639 if reflect.TypeOf(data).Kind() == reflect.Map {
640 subv.config = cast.ToStringMap(data)
646 // GetString returns the value associated with the key as a string.
647 func GetString(key string) string { return v.GetString(key) }
648 func (v *Viper) GetString(key string) string {
649 return cast.ToString(v.Get(key))
652 // GetBool returns the value associated with the key as a boolean.
653 func GetBool(key string) bool { return v.GetBool(key) }
654 func (v *Viper) GetBool(key string) bool {
655 return cast.ToBool(v.Get(key))
658 // GetInt returns the value associated with the key as an integer.
659 func GetInt(key string) int { return v.GetInt(key) }
660 func (v *Viper) GetInt(key string) int {
661 return cast.ToInt(v.Get(key))
664 // GetInt64 returns the value associated with the key as an integer.
665 func GetInt64(key string) int64 { return v.GetInt64(key) }
666 func (v *Viper) GetInt64(key string) int64 {
667 return cast.ToInt64(v.Get(key))
670 // GetFloat64 returns the value associated with the key as a float64.
671 func GetFloat64(key string) float64 { return v.GetFloat64(key) }
672 func (v *Viper) GetFloat64(key string) float64 {
673 return cast.ToFloat64(v.Get(key))
676 // GetTime returns the value associated with the key as time.
677 func GetTime(key string) time.Time { return v.GetTime(key) }
678 func (v *Viper) GetTime(key string) time.Time {
679 return cast.ToTime(v.Get(key))
682 // GetDuration returns the value associated with the key as a duration.
683 func GetDuration(key string) time.Duration { return v.GetDuration(key) }
684 func (v *Viper) GetDuration(key string) time.Duration {
685 return cast.ToDuration(v.Get(key))
688 // GetStringSlice returns the value associated with the key as a slice of strings.
689 func GetStringSlice(key string) []string { return v.GetStringSlice(key) }
690 func (v *Viper) GetStringSlice(key string) []string {
691 return cast.ToStringSlice(v.Get(key))
694 // GetStringMap returns the value associated with the key as a map of interfaces.
695 func GetStringMap(key string) map[string]interface{} { return v.GetStringMap(key) }
696 func (v *Viper) GetStringMap(key string) map[string]interface{} {
697 return cast.ToStringMap(v.Get(key))
700 // GetStringMapString returns the value associated with the key as a map of strings.
701 func GetStringMapString(key string) map[string]string { return v.GetStringMapString(key) }
702 func (v *Viper) GetStringMapString(key string) map[string]string {
703 return cast.ToStringMapString(v.Get(key))
706 // GetStringMapStringSlice returns the value associated with the key as a map to a slice of strings.
707 func GetStringMapStringSlice(key string) map[string][]string { return v.GetStringMapStringSlice(key) }
708 func (v *Viper) GetStringMapStringSlice(key string) map[string][]string {
709 return cast.ToStringMapStringSlice(v.Get(key))
712 // GetSizeInBytes returns the size of the value associated with the given key
714 func GetSizeInBytes(key string) uint { return v.GetSizeInBytes(key) }
715 func (v *Viper) GetSizeInBytes(key string) uint {
716 sizeStr := cast.ToString(v.Get(key))
717 return parseSizeInBytes(sizeStr)
720 // UnmarshalKey takes a single key and unmarshals it into a Struct.
721 func UnmarshalKey(key string, rawVal interface{}) error { return v.UnmarshalKey(key, rawVal) }
722 func (v *Viper) UnmarshalKey(key string, rawVal interface{}) error {
723 err := decode(v.Get(key), defaultDecoderConfig(rawVal))
729 v.insensitiviseMaps()
734 // Unmarshal unmarshals the config into a Struct. Make sure that the tags
735 // on the fields of the structure are properly set.
736 func Unmarshal(rawVal interface{}) error { return v.Unmarshal(rawVal) }
737 func (v *Viper) Unmarshal(rawVal interface{}) error {
738 err := decode(v.AllSettings(), defaultDecoderConfig(rawVal))
744 v.insensitiviseMaps()
749 // defaultDecoderConfig returns default mapsstructure.DecoderConfig with suppot
750 // of time.Duration values & string slices
751 func defaultDecoderConfig(output interface{}) *mapstructure.DecoderConfig {
752 return &mapstructure.DecoderConfig{
755 WeaklyTypedInput: true,
756 DecodeHook: mapstructure.ComposeDecodeHookFunc(
757 mapstructure.StringToTimeDurationHookFunc(),
758 mapstructure.StringToSliceHookFunc(","),
763 // A wrapper around mapstructure.Decode that mimics the WeakDecode functionality
764 func decode(input interface{}, config *mapstructure.DecoderConfig) error {
765 decoder, err := mapstructure.NewDecoder(config)
769 return decoder.Decode(input)
772 // UnmarshalExact unmarshals the config into a Struct, erroring if a field is nonexistent
773 // in the destination struct.
774 func (v *Viper) UnmarshalExact(rawVal interface{}) error {
775 config := defaultDecoderConfig(rawVal)
776 config.ErrorUnused = true
778 err := decode(v.AllSettings(), config)
784 v.insensitiviseMaps()
789 // BindPFlags binds a full flag set to the configuration, using each flag's long
790 // name as the config key.
791 func BindPFlags(flags *pflag.FlagSet) error { return v.BindPFlags(flags) }
792 func (v *Viper) BindPFlags(flags *pflag.FlagSet) error {
793 return v.BindFlagValues(pflagValueSet{flags})
796 // BindPFlag binds a specific key to a pflag (as used by cobra).
797 // Example (where serverCmd is a Cobra instance):
799 // serverCmd.Flags().Int("port", 1138, "Port to run Application server on")
800 // Viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))
802 func BindPFlag(key string, flag *pflag.Flag) error { return v.BindPFlag(key, flag) }
803 func (v *Viper) BindPFlag(key string, flag *pflag.Flag) error {
804 return v.BindFlagValue(key, pflagValue{flag})
807 // BindFlagValues binds a full FlagValue set to the configuration, using each flag's long
808 // name as the config key.
809 func BindFlagValues(flags FlagValueSet) error { return v.BindFlagValues(flags) }
810 func (v *Viper) BindFlagValues(flags FlagValueSet) (err error) {
811 flags.VisitAll(func(flag FlagValue) {
812 if err = v.BindFlagValue(flag.Name(), flag); err != nil {
819 // BindFlagValue binds a specific key to a FlagValue.
820 // Example (where serverCmd is a Cobra instance):
822 // serverCmd.Flags().Int("port", 1138, "Port to run Application server on")
823 // Viper.BindFlagValue("port", serverCmd.Flags().Lookup("port"))
825 func BindFlagValue(key string, flag FlagValue) error { return v.BindFlagValue(key, flag) }
826 func (v *Viper) BindFlagValue(key string, flag FlagValue) error {
828 return fmt.Errorf("flag for %q is nil", key)
830 v.pflags[strings.ToLower(key)] = flag
834 // BindEnv binds a Viper key to a ENV variable.
835 // ENV variables are case sensitive.
836 // If only a key is provided, it will use the env key matching the key, uppercased.
837 // EnvPrefix will be used when set when env name is not provided.
838 func BindEnv(input ...string) error { return v.BindEnv(input...) }
839 func (v *Viper) BindEnv(input ...string) error {
840 var key, envkey string
842 return fmt.Errorf("BindEnv missing key to bind to")
845 key = strings.ToLower(input[0])
848 envkey = v.mergeWithEnvPrefix(key)
858 // Given a key, find the value.
859 // Viper will check in the following order:
860 // flag, env, config file, key/value store, default.
861 // Viper will check to see if an alias exists first.
862 // Note: this assumes a lower-cased key given.
863 func (v *Viper) find(lcaseKey string) interface{} {
868 path = strings.Split(lcaseKey, v.keyDelim)
869 nested = len(path) > 1
872 // compute the path through the nested maps to the nested value
873 if nested && v.isPathShadowedInDeepMap(path, castMapStringToMapInterface(v.aliases)) != "" {
877 // if the requested key is an alias, then return the proper key
878 lcaseKey = v.realKey(lcaseKey)
879 path = strings.Split(lcaseKey, v.keyDelim)
880 nested = len(path) > 1
882 // Set() override first
883 val = v.searchMap(v.override, path)
887 if nested && v.isPathShadowedInDeepMap(path, v.override) != "" {
891 // PFlag override next
892 flag, exists := v.pflags[lcaseKey]
893 if exists && flag.HasChanged() {
894 switch flag.ValueType() {
895 case "int", "int8", "int16", "int32", "int64":
896 return cast.ToInt(flag.ValueString())
898 return cast.ToBool(flag.ValueString())
900 s := strings.TrimPrefix(flag.ValueString(), "[")
901 s = strings.TrimSuffix(s, "]")
902 res, _ := readAsCSV(s)
905 return flag.ValueString()
908 if nested && v.isPathShadowedInFlatMap(path, v.pflags) != "" {
913 if v.automaticEnvApplied {
914 // even if it hasn't been registered, if automaticEnv is used,
915 // check any Get request
916 if val = v.getEnv(v.mergeWithEnvPrefix(lcaseKey)); val != "" {
919 if nested && v.isPathShadowedInAutoEnv(path) != "" {
923 envkey, exists := v.env[lcaseKey]
925 if val = v.getEnv(envkey); val != "" {
929 if nested && v.isPathShadowedInFlatMap(path, v.env) != "" {
934 val = v.searchMapWithPathPrefixes(v.config, path)
938 if nested && v.isPathShadowedInDeepMap(path, v.config) != "" {
943 val = v.searchMap(v.kvstore, path)
947 if nested && v.isPathShadowedInDeepMap(path, v.kvstore) != "" {
952 val = v.searchMap(v.defaults, path)
956 if nested && v.isPathShadowedInDeepMap(path, v.defaults) != "" {
960 // last chance: if no other value is returned and a flag does exist for the value,
961 // get the flag's value even if the flag's value has not changed
962 if flag, exists := v.pflags[lcaseKey]; exists {
963 switch flag.ValueType() {
964 case "int", "int8", "int16", "int32", "int64":
965 return cast.ToInt(flag.ValueString())
967 return cast.ToBool(flag.ValueString())
969 s := strings.TrimPrefix(flag.ValueString(), "[")
970 s = strings.TrimSuffix(s, "]")
971 res, _ := readAsCSV(s)
974 return flag.ValueString()
977 // last item, no need to check shadowing
982 func readAsCSV(val string) ([]string, error) {
984 return []string{}, nil
986 stringReader := strings.NewReader(val)
987 csvReader := csv.NewReader(stringReader)
988 return csvReader.Read()
991 // IsSet checks to see if the key has been set in any of the data locations.
992 // IsSet is case-insensitive for a key.
993 func IsSet(key string) bool { return v.IsSet(key) }
994 func (v *Viper) IsSet(key string) bool {
995 lcaseKey := strings.ToLower(key)
996 val := v.find(lcaseKey)
1000 // AutomaticEnv has Viper check ENV variables for all.
1001 // keys set in config, default & flags
1002 func AutomaticEnv() { v.AutomaticEnv() }
1003 func (v *Viper) AutomaticEnv() {
1004 v.automaticEnvApplied = true
1007 // SetEnvKeyReplacer sets the strings.Replacer on the viper object
1008 // Useful for mapping an environmental variable to a key that does
1010 func SetEnvKeyReplacer(r *strings.Replacer) { v.SetEnvKeyReplacer(r) }
1011 func (v *Viper) SetEnvKeyReplacer(r *strings.Replacer) {
1012 v.envKeyReplacer = r
1015 // Aliases provide another accessor for the same key.
1016 // This enables one to change a name without breaking the application
1017 func RegisterAlias(alias string, key string) { v.RegisterAlias(alias, key) }
1018 func (v *Viper) RegisterAlias(alias string, key string) {
1019 v.registerAlias(alias, strings.ToLower(key))
1022 func (v *Viper) registerAlias(alias string, key string) {
1023 alias = strings.ToLower(alias)
1024 if alias != key && alias != v.realKey(key) {
1025 _, exists := v.aliases[alias]
1028 // if we alias something that exists in one of the maps to another
1029 // name, we'll never be able to get that value using the original
1030 // name, so move the config value to the new realkey.
1031 if val, ok := v.config[alias]; ok {
1032 delete(v.config, alias)
1035 if val, ok := v.kvstore[alias]; ok {
1036 delete(v.kvstore, alias)
1037 v.kvstore[key] = val
1039 if val, ok := v.defaults[alias]; ok {
1040 delete(v.defaults, alias)
1041 v.defaults[key] = val
1043 if val, ok := v.override[alias]; ok {
1044 delete(v.override, alias)
1045 v.override[key] = val
1047 v.aliases[alias] = key
1050 jww.WARN.Println("Creating circular reference alias", alias, key, v.realKey(key))
1054 func (v *Viper) realKey(key string) string {
1055 newkey, exists := v.aliases[key]
1057 jww.DEBUG.Println("Alias", key, "to", newkey)
1058 return v.realKey(newkey)
1063 // InConfig checks to see if the given key (or an alias) is in the config file.
1064 func InConfig(key string) bool { return v.InConfig(key) }
1065 func (v *Viper) InConfig(key string) bool {
1066 // if the requested key is an alias, then return the proper key
1067 key = v.realKey(key)
1069 _, exists := v.config[key]
1073 // SetDefault sets the default value for this key.
1074 // SetDefault is case-insensitive for a key.
1075 // Default only used when no value is provided by the user via flag, config or ENV.
1076 func SetDefault(key string, value interface{}) { v.SetDefault(key, value) }
1077 func (v *Viper) SetDefault(key string, value interface{}) {
1078 // If alias passed in, then set the proper default
1079 key = v.realKey(strings.ToLower(key))
1080 value = toCaseInsensitiveValue(value)
1082 path := strings.Split(key, v.keyDelim)
1083 lastKey := strings.ToLower(path[len(path)-1])
1084 deepestMap := deepSearch(v.defaults, path[0:len(path)-1])
1086 // set innermost value
1087 deepestMap[lastKey] = value
1090 // Set sets the value for the key in the override regiser.
1091 // Set is case-insensitive for a key.
1092 // Will be used instead of values obtained via
1093 // flags, config file, ENV, default, or key/value store.
1094 func Set(key string, value interface{}) { v.Set(key, value) }
1095 func (v *Viper) Set(key string, value interface{}) {
1096 // If alias passed in, then set the proper override
1097 key = v.realKey(strings.ToLower(key))
1098 value = toCaseInsensitiveValue(value)
1100 path := strings.Split(key, v.keyDelim)
1101 lastKey := strings.ToLower(path[len(path)-1])
1102 deepestMap := deepSearch(v.override, path[0:len(path)-1])
1104 // set innermost value
1105 deepestMap[lastKey] = value
1108 // ReadInConfig will discover and load the configuration file from disk
1109 // and key/value stores, searching in one of the defined paths.
1110 func ReadInConfig() error { return v.ReadInConfig() }
1111 func (v *Viper) ReadInConfig() error {
1112 jww.INFO.Println("Attempting to read in config file")
1113 filename, err := v.getConfigFile()
1118 if !stringInSlice(v.getConfigType(), SupportedExts) {
1119 return UnsupportedConfigError(v.getConfigType())
1122 file, err := afero.ReadFile(v.fs, filename)
1127 config := make(map[string]interface{})
1129 err = v.unmarshalReader(bytes.NewReader(file), config)
1138 // MergeInConfig merges a new configuration with an existing config.
1139 func MergeInConfig() error { return v.MergeInConfig() }
1140 func (v *Viper) MergeInConfig() error {
1141 jww.INFO.Println("Attempting to merge in config file")
1142 filename, err := v.getConfigFile()
1147 if !stringInSlice(v.getConfigType(), SupportedExts) {
1148 return UnsupportedConfigError(v.getConfigType())
1151 file, err := afero.ReadFile(v.fs, filename)
1156 return v.MergeConfig(bytes.NewReader(file))
1159 // ReadConfig will read a configuration file, setting existing keys to nil if the
1160 // key does not exist in the file.
1161 func ReadConfig(in io.Reader) error { return v.ReadConfig(in) }
1162 func (v *Viper) ReadConfig(in io.Reader) error {
1163 v.config = make(map[string]interface{})
1164 return v.unmarshalReader(in, v.config)
1167 // MergeConfig merges a new configuration with an existing config.
1168 func MergeConfig(in io.Reader) error { return v.MergeConfig(in) }
1169 func (v *Viper) MergeConfig(in io.Reader) error {
1170 if v.config == nil {
1171 v.config = make(map[string]interface{})
1173 cfg := make(map[string]interface{})
1174 if err := v.unmarshalReader(in, cfg); err != nil {
1177 mergeMaps(cfg, v.config, nil)
1181 func keyExists(k string, m map[string]interface{}) string {
1182 lk := strings.ToLower(k)
1184 lmk := strings.ToLower(mk)
1192 func castToMapStringInterface(
1193 src map[interface{}]interface{}) map[string]interface{} {
1194 tgt := map[string]interface{}{}
1195 for k, v := range src {
1196 tgt[fmt.Sprintf("%v", k)] = v
1201 func castMapStringToMapInterface(src map[string]string) map[string]interface{} {
1202 tgt := map[string]interface{}{}
1203 for k, v := range src {
1209 func castMapFlagToMapInterface(src map[string]FlagValue) map[string]interface{} {
1210 tgt := map[string]interface{}{}
1211 for k, v := range src {
1217 // mergeMaps merges two maps. The `itgt` parameter is for handling go-yaml's
1218 // insistence on parsing nested structures as `map[interface{}]interface{}`
1219 // instead of using a `string` as the key for nest structures beyond one level
1220 // deep. Both map types are supported as there is a go-yaml fork that uses
1221 // `map[string]interface{}` instead.
1223 src, tgt map[string]interface{}, itgt map[interface{}]interface{}) {
1224 for sk, sv := range src {
1225 tk := keyExists(sk, tgt)
1227 jww.TRACE.Printf("tk=\"\", tgt[%s]=%v", sk, sv)
1237 jww.TRACE.Printf("tgt[%s] != ok, tgt[%s]=%v", tk, sk, sv)
1245 svType := reflect.TypeOf(sv)
1246 tvType := reflect.TypeOf(tv)
1247 if svType != tvType {
1249 "svType != tvType; key=%s, st=%v, tt=%v, sv=%v, tv=%v",
1250 sk, svType, tvType, sv, tv)
1254 jww.TRACE.Printf("processing key=%s, st=%v, tt=%v, sv=%v, tv=%v",
1255 sk, svType, tvType, sv, tv)
1257 switch ttv := tv.(type) {
1258 case map[interface{}]interface{}:
1259 jww.TRACE.Printf("merging maps (must convert)")
1260 tsv := sv.(map[interface{}]interface{})
1261 ssv := castToMapStringInterface(tsv)
1262 stv := castToMapStringInterface(ttv)
1263 mergeMaps(ssv, stv, ttv)
1264 case map[string]interface{}:
1265 jww.TRACE.Printf("merging maps")
1266 mergeMaps(sv.(map[string]interface{}), ttv, nil)
1268 jww.TRACE.Printf("setting value")
1277 // ReadRemoteConfig attempts to get configuration from a remote source
1278 // and read it in the remote configuration registry.
1279 func ReadRemoteConfig() error { return v.ReadRemoteConfig() }
1280 func (v *Viper) ReadRemoteConfig() error {
1281 return v.getKeyValueConfig()
1284 func WatchRemoteConfig() error { return v.WatchRemoteConfig() }
1285 func (v *Viper) WatchRemoteConfig() error {
1286 return v.watchKeyValueConfig()
1289 func (v *Viper) WatchRemoteConfigOnChannel() error {
1290 return v.watchKeyValueConfigOnChannel()
1293 // Unmarshal a Reader into a map.
1294 // Should probably be an unexported function.
1295 func unmarshalReader(in io.Reader, c map[string]interface{}) error {
1296 return v.unmarshalReader(in, c)
1299 func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error {
1300 return unmarshallConfigReader(in, c, v.getConfigType())
1303 func (v *Viper) insensitiviseMaps() {
1304 insensitiviseMap(v.config)
1305 insensitiviseMap(v.defaults)
1306 insensitiviseMap(v.override)
1307 insensitiviseMap(v.kvstore)
1310 // Retrieve the first found remote configuration.
1311 func (v *Viper) getKeyValueConfig() error {
1312 if RemoteConfig == nil {
1313 return RemoteConfigError("Enable the remote features by doing a blank import of the viper/remote package: '_ github.com/spf13/viper/remote'")
1316 for _, rp := range v.remoteProviders {
1317 val, err := v.getRemoteConfig(rp)
1324 return RemoteConfigError("No Files Found")
1327 func (v *Viper) getRemoteConfig(provider RemoteProvider) (map[string]interface{}, error) {
1328 reader, err := RemoteConfig.Get(provider)
1332 err = v.unmarshalReader(reader, v.kvstore)
1333 return v.kvstore, err
1336 // Retrieve the first found remote configuration.
1337 func (v *Viper) watchKeyValueConfigOnChannel() error {
1338 for _, rp := range v.remoteProviders {
1339 respc, _ := RemoteConfig.WatchChannel(rp)
1340 //Todo: Add quit channel
1341 go func(rc <-chan *RemoteResponse) {
1344 reader := bytes.NewReader(b.Value)
1345 v.unmarshalReader(reader, v.kvstore)
1350 return RemoteConfigError("No Files Found")
1353 // Retrieve the first found remote configuration.
1354 func (v *Viper) watchKeyValueConfig() error {
1355 for _, rp := range v.remoteProviders {
1356 val, err := v.watchRemoteConfig(rp)
1363 return RemoteConfigError("No Files Found")
1366 func (v *Viper) watchRemoteConfig(provider RemoteProvider) (map[string]interface{}, error) {
1367 reader, err := RemoteConfig.Watch(provider)
1371 err = v.unmarshalReader(reader, v.kvstore)
1372 return v.kvstore, err
1375 // AllKeys returns all keys holding a value, regardless of where they are set.
1376 // Nested keys are returned with a v.keyDelim (= ".") separator
1377 func AllKeys() []string { return v.AllKeys() }
1378 func (v *Viper) AllKeys() []string {
1379 m := map[string]bool{}
1380 // add all paths, by order of descending priority to ensure correct shadowing
1381 m = v.flattenAndMergeMap(m, castMapStringToMapInterface(v.aliases), "")
1382 m = v.flattenAndMergeMap(m, v.override, "")
1383 m = v.mergeFlatMap(m, castMapFlagToMapInterface(v.pflags))
1384 m = v.mergeFlatMap(m, castMapStringToMapInterface(v.env))
1385 m = v.flattenAndMergeMap(m, v.config, "")
1386 m = v.flattenAndMergeMap(m, v.kvstore, "")
1387 m = v.flattenAndMergeMap(m, v.defaults, "")
1389 // convert set of paths to list
1397 // flattenAndMergeMap recursively flattens the given map into a map[string]bool
1398 // of key paths (used as a set, easier to manipulate than a []string):
1399 // - each path is merged into a single key string, delimited with v.keyDelim (= ".")
1400 // - if a path is shadowed by an earlier value in the initial shadow map,
1402 // The resulting set of paths is merged to the given shadow set at the same time.
1403 func (v *Viper) flattenAndMergeMap(shadow map[string]bool, m map[string]interface{}, prefix string) map[string]bool {
1404 if shadow != nil && prefix != "" && shadow[prefix] {
1405 // prefix is shadowed => nothing more to flatten
1409 shadow = make(map[string]bool)
1412 var m2 map[string]interface{}
1414 prefix += v.keyDelim
1416 for k, val := range m {
1417 fullKey := prefix + k
1419 case map[string]interface{}:
1420 m2 = val.(map[string]interface{})
1421 case map[interface{}]interface{}:
1422 m2 = cast.ToStringMap(val)
1425 shadow[strings.ToLower(fullKey)] = true
1428 // recursively merge to shadow map
1429 shadow = v.flattenAndMergeMap(shadow, m2, fullKey)
1434 // mergeFlatMap merges the given maps, excluding values of the second map
1435 // shadowed by values from the first map.
1436 func (v *Viper) mergeFlatMap(shadow map[string]bool, m map[string]interface{}) map[string]bool {
1439 for k, _ := range m {
1440 path := strings.Split(k, v.keyDelim)
1441 // scan intermediate paths
1442 var parentKey string
1443 for i := 1; i < len(path); i++ {
1444 parentKey = strings.Join(path[0:i], v.keyDelim)
1445 if shadow[parentKey] {
1446 // path is shadowed, continue
1451 shadow[strings.ToLower(k)] = true
1456 // AllSettings merges all settings and returns them as a map[string]interface{}.
1457 func AllSettings() map[string]interface{} { return v.AllSettings() }
1458 func (v *Viper) AllSettings() map[string]interface{} {
1459 m := map[string]interface{}{}
1460 // start from the list of keys, and construct the map one value at a time
1461 for _, k := range v.AllKeys() {
1464 // should not happen, since AllKeys() returns only keys holding a value,
1465 // check just in case anything changes
1468 path := strings.Split(k, v.keyDelim)
1469 lastKey := strings.ToLower(path[len(path)-1])
1470 deepestMap := deepSearch(m, path[0:len(path)-1])
1471 // set innermost value
1472 deepestMap[lastKey] = value
1477 // SetFs sets the filesystem to use to read configuration.
1478 func SetFs(fs afero.Fs) { v.SetFs(fs) }
1479 func (v *Viper) SetFs(fs afero.Fs) {
1483 // SetConfigName sets name for the config file.
1484 // Does not include extension.
1485 func SetConfigName(in string) { v.SetConfigName(in) }
1486 func (v *Viper) SetConfigName(in string) {
1493 // SetConfigType sets the type of the configuration returned by the
1494 // remote source, e.g. "json".
1495 func SetConfigType(in string) { v.SetConfigType(in) }
1496 func (v *Viper) SetConfigType(in string) {
1502 func (v *Viper) getConfigType() string {
1503 if v.configType != "" {
1507 cf, err := v.getConfigFile()
1512 ext := filepath.Ext(cf)
1521 func (v *Viper) getConfigFile() (string, error) {
1522 // if explicitly set, then use it
1523 if v.configFile != "" {
1524 return v.configFile, nil
1527 cf, err := v.findConfigFile()
1533 return v.getConfigFile()
1536 func (v *Viper) searchInPath(in string) (filename string) {
1537 jww.DEBUG.Println("Searching for config in ", in)
1538 for _, ext := range SupportedExts {
1539 jww.DEBUG.Println("Checking for", filepath.Join(in, v.configName+"."+ext))
1540 if b, _ := exists(filepath.Join(in, v.configName+"."+ext)); b {
1541 jww.DEBUG.Println("Found: ", filepath.Join(in, v.configName+"."+ext))
1542 return filepath.Join(in, v.configName+"."+ext)
1549 // Search all configPaths for any config file.
1550 // Returns the first path that exists (and is a config file).
1551 func (v *Viper) findConfigFile() (string, error) {
1552 jww.INFO.Println("Searching for config in ", v.configPaths)
1554 for _, cp := range v.configPaths {
1555 file := v.searchInPath(cp)
1560 return "", ConfigFileNotFoundError{v.configName, fmt.Sprintf("%s", v.configPaths)}
1563 // Debug prints all configuration registries for debugging
1565 func Debug() { v.Debug() }
1566 func (v *Viper) Debug() {
1567 fmt.Printf("Aliases:\n%#v\n", v.aliases)
1568 fmt.Printf("Override:\n%#v\n", v.override)
1569 fmt.Printf("PFlags:\n%#v\n", v.pflags)
1570 fmt.Printf("Env:\n%#v\n", v.env)
1571 fmt.Printf("Key/Value Store:\n%#v\n", v.kvstore)
1572 fmt.Printf("Config:\n%#v\n", v.config)
1573 fmt.Printf("Defaults:\n%#v\n", v.defaults)