func (v *Viper) searchMap(source map[string]interface{}, path []string) interface{} { if len(path) == 0 { return source } var ok bool var next interface{} for k, v := range source { if strings.ToLower(k) == strings.ToLower(path[0]) { ok = true next = v break } } if ok { switch next.(type) { case map[interface{}]interface{}: return v.searchMap(cast.ToStringMap(next), path[1:]) case map[string]interface{}: // Type assertion is safe here since it is only reached // if the type of `next` is the same as the type being asserted return v.searchMap(next.(map[string]interface{}), path[1:]) default: return next } } else { return nil } }
func (v *Viper) Sub(key string) *Viper { subv := New() data := v.Get(key) if reflect.TypeOf(data).Kind() == reflect.Map { subv.config = cast.ToStringMap(data) return subv } else { return nil } }
func (v *Viper) IsSet(key string) bool { path := strings.Split(key, v.keyDelim) lcaseKey := strings.ToLower(key) val := v.find(lcaseKey) if val == nil { source := v.find(strings.ToLower(path[0])) if source != nil { if reflect.TypeOf(source).Kind() == reflect.Map { val = v.searchMap(cast.ToStringMap(source), path[1:]) } } } return val != nil }
// Given a key, find the value // Viper will check in the following order: // flag, env, config file, key/value store, default // Viper will check to see if an alias exists first func (v *Viper) find(key string) interface{} { var val interface{} var exists bool // if the requested key is an alias, then return the proper key key = v.realKey(key) // PFlag Override first flag, exists := v.pflags[key] if exists && flag.HasChanged() { jww.TRACE.Println(key, "found in override (via pflag):", flag.ValueString()) switch flag.ValueType() { case "int", "int8", "int16", "int32", "int64": return cast.ToInt(flag.ValueString()) case "bool": return cast.ToBool(flag.ValueString()) default: return flag.ValueString() } } val, exists = v.override[key] if exists { jww.TRACE.Println(key, "found in override:", val) return val } if v.automaticEnvApplied { // even if it hasn't been registered, if automaticEnv is used, // check any Get request if val = v.getEnv(v.mergeWithEnvPrefix(key)); val != "" { jww.TRACE.Println(key, "found in environment with val:", val) return val } } envkey, exists := v.env[key] if exists { jww.TRACE.Println(key, "registered as env var", envkey) if val = v.getEnv(envkey); val != "" { jww.TRACE.Println(envkey, "found in environment with val:", val) return val } else { jww.TRACE.Println(envkey, "env value unset:") } } val, exists = v.config[key] if exists { jww.TRACE.Println(key, "found in config:", val) return val } // Test for nested config parameter if strings.Contains(key, v.keyDelim) { path := strings.Split(key, v.keyDelim) source := v.find(path[0]) if source != nil { if reflect.TypeOf(source).Kind() == reflect.Map { val := v.searchMap(cast.ToStringMap(source), path[1:]) jww.TRACE.Println(key, "found in nested config:", val) return val } } } val, exists = v.kvstore[key] if exists { jww.TRACE.Println(key, "found in key/value store:", val) return val } val, exists = v.defaults[key] if exists { jww.TRACE.Println(key, "found in defaults:", val) return val } return nil }
func (v *Viper) GetStringMap(key string) map[string]interface{} { return cast.ToStringMap(v.Get(key)) }
func (v *Viper) Get(key string) interface{} { path := strings.Split(key, v.keyDelim) lcaseKey := strings.ToLower(key) val := v.find(lcaseKey) if val == nil { source := v.find(strings.ToLower(path[0])) if source != nil { if reflect.TypeOf(source).Kind() == reflect.Map { val = v.searchMap(cast.ToStringMap(source), path[1:]) } } } // if no other value is returned and a flag does exist for the value, // get the flag's value even if the flag's value has not changed if val == nil { if flag, exists := v.pflags[lcaseKey]; exists { jww.TRACE.Println(key, "get pflag default", val) switch flag.ValueType() { case "int", "int8", "int16", "int32", "int64": val = cast.ToInt(flag.ValueString()) case "bool": val = cast.ToBool(flag.ValueString()) default: val = flag.ValueString() } } } if val == nil { return nil } var valType interface{} if !v.typeByDefValue { valType = val } else { defVal, defExists := v.defaults[lcaseKey] if defExists { valType = defVal } else { valType = val } } switch valType.(type) { case bool: return cast.ToBool(val) case string: return cast.ToString(val) case int64, int32, int16, int8, int: return cast.ToInt(val) case float64, float32: return cast.ToFloat64(val) case time.Time: return cast.ToTime(val) case time.Duration: return cast.ToDuration(val) case []string: return cast.ToStringSlice(val) } return val }