bug fix: maps are not guaranteed to have consistent key ordering - always look in the order of AddConfigPath

IntelliJ reformat code
simplify cascade lookup
This commit is contained in:
Bill Robbins 2015-02-08 20:21:37 -06:00
parent 64fc762506
commit e69822897f

View file

@ -125,6 +125,7 @@ var SupportedRemoteProviders []string = []string{"etcd", "consul"}
// Explicitly define the path, name and extension of the config file // Explicitly define the path, name and extension of the config file
// Viper will use this and not check any of the config paths // Viper will use this and not check any of the config paths
func SetConfigFile(in string) { v.SetConfigFile(in) } func SetConfigFile(in string) { v.SetConfigFile(in) }
func (v *viper) SetConfigFile(in string) { func (v *viper) SetConfigFile(in string) {
if in != "" { if in != "" {
v.configFile = in v.configFile = in
@ -133,6 +134,7 @@ func (v *viper) SetConfigFile(in string) {
// Define a prefix that ENVIRONMENT variables will use. // Define a prefix that ENVIRONMENT variables will use.
func SetEnvPrefix(in string) { v.SetEnvPrefix(in) } func SetEnvPrefix(in string) { v.SetEnvPrefix(in) }
func (v *viper) SetEnvPrefix(in string) { func (v *viper) SetEnvPrefix(in string) {
if in != "" { if in != "" {
v.envPrefix = in v.envPrefix = in
@ -156,11 +158,13 @@ func (v *viper) mergeWithEnvPrefix(in string) string {
// Return the config file used // Return the config file used
func ConfigFileUsed() string { return v.ConfigFileUsed() } func ConfigFileUsed() string { return v.ConfigFileUsed() }
func (v *viper) ConfigFileUsed() string { return v.configFile } func (v *viper) ConfigFileUsed() string { return v.configFile }
// Add a path for viper to search for the config file in. // Add a path for viper to search for the config file in.
// Can be called multiple times to define multiple search paths. // Can be called multiple times to define multiple search paths.
func AddConfigPath(in string) { v.AddConfigPath(in) } func AddConfigPath(in string) { v.AddConfigPath(in) }
func (v *viper) AddConfigPath(in string) { func (v *viper) AddConfigPath(in string) {
if in != "" { if in != "" {
absin := absPathify(in) absin := absPathify(in)
@ -182,6 +186,7 @@ func (v *viper) AddConfigPath(in string) {
func AddRemoteProvider(provider, endpoint, path string) error { func AddRemoteProvider(provider, endpoint, path string) error {
return v.AddRemoteProvider(provider, endpoint, path) return v.AddRemoteProvider(provider, endpoint, path)
} }
func (v *viper) AddRemoteProvider(provider, endpoint, path string) error { func (v *viper) AddRemoteProvider(provider, endpoint, path string) error {
if !stringInSlice(provider, SupportedRemoteProviders) { if !stringInSlice(provider, SupportedRemoteProviders) {
return UnsupportedRemoteProviderError(provider) return UnsupportedRemoteProviderError(provider)
@ -249,6 +254,7 @@ func (v *viper) providerPathExists(p *remoteProvider) bool {
// //
// Get returns an interface. For a specific value use one of the Get____ methods. // Get returns an interface. For a specific value use one of the Get____ methods.
func Get(key string) interface{} { return v.Get(key) } func Get(key string) interface{} { return v.Get(key) }
func (v *viper) Get(key string) interface{} { func (v *viper) Get(key string) interface{} {
key = strings.ToLower(key) key = strings.ToLower(key)
val := v.find(key) val := v.find(key)
@ -275,53 +281,63 @@ func (v *viper) Get(key string) interface{} {
} }
func GetString(key string) string { return v.GetString(key) } func GetString(key string) string { return v.GetString(key) }
func (v *viper) GetString(key string) string { func (v *viper) GetString(key string) string {
return cast.ToString(v.Get(key)) return cast.ToString(v.Get(key))
} }
func GetBool(key string) bool { return v.GetBool(key) } func GetBool(key string) bool { return v.GetBool(key) }
func (v *viper) GetBool(key string) bool { func (v *viper) GetBool(key string) bool {
return cast.ToBool(v.Get(key)) return cast.ToBool(v.Get(key))
} }
func GetInt(key string) int { return v.GetInt(key) } func GetInt(key string) int { return v.GetInt(key) }
func (v *viper) GetInt(key string) int { func (v *viper) GetInt(key string) int {
return cast.ToInt(v.Get(key)) return cast.ToInt(v.Get(key))
} }
func GetFloat64(key string) float64 { return v.GetFloat64(key) } func GetFloat64(key string) float64 { return v.GetFloat64(key) }
func (v *viper) GetFloat64(key string) float64 { func (v *viper) GetFloat64(key string) float64 {
return cast.ToFloat64(v.Get(key)) return cast.ToFloat64(v.Get(key))
} }
func GetTime(key string) time.Time { return v.GetTime(key) } func GetTime(key string) time.Time { return v.GetTime(key) }
func (v *viper) GetTime(key string) time.Time { func (v *viper) GetTime(key string) time.Time {
return cast.ToTime(v.Get(key)) return cast.ToTime(v.Get(key))
} }
func GetStringSlice(key string) []string { return v.GetStringSlice(key) } func GetStringSlice(key string) []string { return v.GetStringSlice(key) }
func (v *viper) GetStringSlice(key string) []string { func (v *viper) GetStringSlice(key string) []string {
return cast.ToStringSlice(v.Get(key)) return cast.ToStringSlice(v.Get(key))
} }
func GetStringMap(key string) map[string]interface{} { return v.GetStringMap(key) } func GetStringMap(key string) map[string]interface{} { return v.GetStringMap(key) }
func (v *viper) GetStringMap(key string) map[string]interface{} { func (v *viper) GetStringMap(key string) map[string]interface{} {
return cast.ToStringMap(v.Get(key)) return cast.ToStringMap(v.Get(key))
} }
func GetStringMapString(key string) map[string]string { return v.GetStringMapString(key) } func GetStringMapString(key string) map[string]string { return v.GetStringMapString(key) }
func (v *viper) GetStringMapString(key string) map[string]string { func (v *viper) GetStringMapString(key string) map[string]string {
return cast.ToStringMapString(v.Get(key)) return cast.ToStringMapString(v.Get(key))
} }
// Takes a single key and marshals it into a Struct // Takes a single key and marshals it into a Struct
func MarshalKey(key string, rawVal interface{}) error { return v.MarshalKey(key, rawVal) } func MarshalKey(key string, rawVal interface{}) error { return v.MarshalKey(key, rawVal) }
func (v *viper) MarshalKey(key string, rawVal interface{}) error { func (v *viper) MarshalKey(key string, rawVal interface{}) error {
return mapstructure.Decode(v.Get(key), rawVal) return mapstructure.Decode(v.Get(key), rawVal)
} }
// Marshals the config into a Struct // Marshals the config into a Struct
func Marshal(rawVal interface{}) error { return v.Marshal(rawVal) } func Marshal(rawVal interface{}) error { return v.Marshal(rawVal) }
func (v *viper) Marshal(rawVal interface{}) error { func (v *viper) Marshal(rawVal interface{}) error {
err := mapstructure.Decode(v.defaults, rawVal) err := mapstructure.Decode(v.defaults, rawVal)
if err != nil { if err != nil {
@ -351,6 +367,7 @@ func (v *viper) Marshal(rawVal interface{}) error {
// viper.BindPFlag("port", serverCmd.Flags().Lookup("port")) // viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))
// //
func BindPFlag(key string, flag *pflag.Flag) (err error) { return v.BindPFlag(key, flag) } func BindPFlag(key string, flag *pflag.Flag) (err error) { return v.BindPFlag(key, flag) }
func (v *viper) BindPFlag(key string, flag *pflag.Flag) (err error) { func (v *viper) BindPFlag(key string, flag *pflag.Flag) (err error) {
if flag == nil { if flag == nil {
return fmt.Errorf("flag for %q is nil", key) return fmt.Errorf("flag for %q is nil", key)
@ -373,6 +390,7 @@ func (v *viper) BindPFlag(key string, flag *pflag.Flag) (err error) {
// If only a key is provided, it will use the env key matching the key, uppercased. // If only a key is provided, it will use the env key matching the key, uppercased.
// EnvPrefix will be used when set when env name is not provided. // EnvPrefix will be used when set when env name is not provided.
func BindEnv(input ...string) (err error) { return v.BindEnv(input...) } func BindEnv(input ...string) (err error) { return v.BindEnv(input...) }
func (v *viper) BindEnv(input ...string) (err error) { func (v *viper) BindEnv(input ...string) (err error) {
var key, envkey string var key, envkey string
if len(input) == 0 { if len(input) == 0 {
@ -471,49 +489,54 @@ func (v *viper) find(key string) interface{} {
func (v *viper) findCascading(key string) (interface{}, bool, string) { func (v *viper) findCascading(key string) (interface{}, bool, string) {
if( v.cascadingConfigs != nil ){
for file,config := range v.cascadingConfigs {
result := config[key]
if( result != nil ){
return result,true,file
}
}
}
v.cascadingConfigs = make(map[string]map[string]interface{})
configFiles := v.findAllConfigFiles() configFiles := v.findAllConfigFiles()
for _, configFile := range configFiles {
if(v.cascadingConfigs[configFile] != nil){ if ( v.cascadingConfigs == nil) {
//already cached v.cascadingConfigs = make(map[string]map[string]interface{})
continue
} }
jww.TRACE.Printf("Looking in %s for key %s",configFile,key) for _, configFile := range configFiles {
file, err := ioutil.ReadFile(configFile) config := v.cascadingConfigs[configFile]
if err != nil {
if ( config == nil ) {
var err error
config,err = readConfigFile(configFile)
if( err != nil){
jww.ERROR.Print(err) jww.ERROR.Print(err)
continue continue
} }
jww.TRACE.Printf("marshalling %s for cascading",configFile)
var config = make(map[string]interface{})
marshallConfigReader(bytes.NewReader(file), config, filepath.Ext(configFile)[1:])
v.cascadingConfigs[configFile] = config v.cascadingConfigs[configFile] = config
}
jww.TRACE.Printf("Looking in %s for key %s", configFile, key)
result := config[key] result := config[key]
if ( result != nil ) { if ( result != nil ) {
return result, true, configFile return result, true, configFile
} }
} }
return "", false, "" return "", false, ""
} }
func readConfigFile(configFile string) (map[string]interface{},error) {
jww.TRACE.Printf("marshalling %s ", configFile)
file, err := ioutil.ReadFile(configFile)
if err != nil {
return nil,err
}
var config = make(map[string]interface{})
marshallConfigReader(bytes.NewReader(file), config, filepath.Ext(configFile)[1:])
return config,nil
}
// Check to see if the key has been set in any of the data locations // Check to see if the key has been set in any of the data locations
func IsSet(key string) bool { return v.IsSet(key) } func IsSet(key string) bool { return v.IsSet(key) }
func (v *viper) IsSet(key string) bool { func (v *viper) IsSet(key string) bool {
t := v.Get(key) t := v.Get(key)
return t != nil return t != nil
@ -522,6 +545,7 @@ func (v *viper) IsSet(key string) bool {
// Have viper check ENV variables for all // Have viper check ENV variables for all
// keys set in config, default & flags // keys set in config, default & flags
func AutomaticEnv() { v.AutomaticEnv() } func AutomaticEnv() { v.AutomaticEnv() }
func (v *viper) AutomaticEnv() { func (v *viper) AutomaticEnv() {
v.automaticEnvApplied = true v.automaticEnvApplied = true
} }
@ -529,6 +553,7 @@ func (v *viper) AutomaticEnv() {
// Aliases provide another accessor for the same key. // Aliases provide another accessor for the same key.
// This enables one to change a name without breaking the application // This enables one to change a name without breaking the application
func RegisterAlias(alias string, key string) { v.RegisterAlias(alias, key) } func RegisterAlias(alias string, key string) { v.RegisterAlias(alias, key) }
func (v *viper) RegisterAlias(alias string, key string) { func (v *viper) RegisterAlias(alias string, key string) {
v.registerAlias(alias, strings.ToLower(key)) v.registerAlias(alias, strings.ToLower(key))
} }
@ -577,6 +602,7 @@ func (v *viper) realKey(key string) string {
// Check to see if the given key (or an alias) is in the config file // Check to see if the given key (or an alias) is in the config file
func InConfig(key string) bool { return v.InConfig(key) } func InConfig(key string) bool { return v.InConfig(key) }
func (v *viper) InConfig(key string) bool { func (v *viper) InConfig(key string) bool {
// if the requested key is an alias, then return the proper key // if the requested key is an alias, then return the proper key
key = v.realKey(key) key = v.realKey(key)
@ -588,6 +614,7 @@ func (v *viper) InConfig(key string) bool {
// Set the default value for this key. // Set the default value for this key.
// Default only used when no value is provided by the user via flag, config or ENV. // Default only used when no value is provided by the user via flag, config or ENV.
func SetDefault(key string, value interface{}) { v.SetDefault(key, value) } func SetDefault(key string, value interface{}) { v.SetDefault(key, value) }
func (v *viper) SetDefault(key string, value interface{}) { func (v *viper) SetDefault(key string, value interface{}) {
// If alias passed in, then set the proper default // If alias passed in, then set the proper default
key = v.realKey(strings.ToLower(key)) key = v.realKey(strings.ToLower(key))
@ -598,6 +625,7 @@ func (v *viper) SetDefault(key string, value interface{}) {
// Will be used instead of values obtained via // Will be used instead of values obtained via
// config file, ENV, default, or key/value store // config file, ENV, default, or key/value store
func Set(key string, value interface{}) { v.Set(key, value) } func Set(key string, value interface{}) { v.Set(key, value) }
func (v *viper) Set(key string, value interface{}) { func (v *viper) Set(key string, value interface{}) {
// If alias passed in, then set the proper override // If alias passed in, then set the proper override
key = v.realKey(strings.ToLower(key)) key = v.realKey(strings.ToLower(key))
@ -607,6 +635,7 @@ func (v *viper) Set(key string, value interface{}) {
// Viper will discover and load the configuration file from disk // Viper will discover and load the configuration file from disk
// and key/value stores, searching in one of the defined paths. // and key/value stores, searching in one of the defined paths.
func ReadInConfig() error { return v.ReadInConfig() } func ReadInConfig() error { return v.ReadInConfig() }
func (v *viper) ReadInConfig() error { func (v *viper) ReadInConfig() error {
jww.INFO.Println("Attempting to read in config file") jww.INFO.Println("Attempting to read in config file")
if !stringInSlice(v.getConfigType(), SupportedExts) { if !stringInSlice(v.getConfigType(), SupportedExts) {
@ -623,6 +652,7 @@ func (v *viper) ReadInConfig() error {
} }
func ReadRemoteConfig() error { return v.ReadRemoteConfig() } func ReadRemoteConfig() error { return v.ReadRemoteConfig() }
func (v *viper) ReadRemoteConfig() error { func (v *viper) ReadRemoteConfig() error {
err := v.getKeyValueConfig() err := v.getKeyValueConfig()
if err != nil { if err != nil {
@ -634,6 +664,7 @@ func (v *viper) ReadRemoteConfig() error {
// Marshall a Reader into a map // Marshall a Reader into a map
// Should probably be an unexported function // Should probably be an unexported function
func marshalReader(in io.Reader, c map[string]interface{}) { v.marshalReader(in, c) } func marshalReader(in io.Reader, c map[string]interface{}) { v.marshalReader(in, c) }
func (v *viper) marshalReader(in io.Reader, c map[string]interface{}) { func (v *viper) marshalReader(in io.Reader, c map[string]interface{}) {
marshallConfigReader(in, c, v.getConfigType()) marshallConfigReader(in, c, v.getConfigType())
} }
@ -694,6 +725,7 @@ func (v *viper) getRemoteConfig(provider *remoteProvider) (map[string]interface{
// Return all keys regardless where they are set // Return all keys regardless where they are set
func AllKeys() []string { return v.AllKeys() } func AllKeys() []string { return v.AllKeys() }
func (v *viper) AllKeys() []string { func (v *viper) AllKeys() []string {
m := map[string]struct{}{} m := map[string]struct{}{}
@ -723,6 +755,7 @@ func (v *viper) AllKeys() []string {
// Return all settings as a map[string]interface{} // Return all settings as a map[string]interface{}
func AllSettings() map[string]interface{} { return v.AllSettings() } func AllSettings() map[string]interface{} { return v.AllSettings() }
func (v *viper) AllSettings() map[string]interface{} { func (v *viper) AllSettings() map[string]interface{} {
m := map[string]interface{}{} m := map[string]interface{}{}
for _, x := range v.AllKeys() { for _, x := range v.AllKeys() {
@ -735,6 +768,7 @@ func (v *viper) AllSettings() map[string]interface{} {
// Name for the config file. // Name for the config file.
// Does not include extension. // Does not include extension.
func SetConfigName(in string) { v.SetConfigName(in) } func SetConfigName(in string) { v.SetConfigName(in) }
func (v *viper) SetConfigName(in string) { func (v *viper) SetConfigName(in string) {
if in != "" { if in != "" {
v.configName = in v.configName = in
@ -742,6 +776,7 @@ func (v *viper) SetConfigName(in string) {
} }
func SetConfigType(in string) { v.SetConfigType(in) } func SetConfigType(in string) { v.SetConfigType(in) }
func (v *viper) SetConfigType(in string) { func (v *viper) SetConfigType(in string) {
if in != "" { if in != "" {
v.configType = in v.configType = in
@ -834,6 +869,7 @@ func (v *viper) findAllConfigFiles() []string {
} }
func Debug() { v.Debug() } func Debug() { v.Debug() }
func (v *viper) Debug() { func (v *viper) Debug() {
fmt.Println("Config:") fmt.Println("Config:")
pretty.Println(v.config) pretty.Println(v.config)