Merge branch 'master' of https://github.com/spf13/viper into GetStringEnv

This commit is contained in:
Nathan Trujillo 2020-09-18 11:14:23 -07:00
commit bcab3ff5ff
10 changed files with 214 additions and 67 deletions

View file

@ -9,10 +9,11 @@ on:
jobs: jobs:
build: build:
name: Build name: Build
runs-on: ubuntu-latest runs-on: ${{ matrix.os }}
strategy: strategy:
matrix: matrix:
go: ['1.11', '1.12', '1.13', '1.14'] os: [ubuntu-latest, macos-latest]
go: ['1.11', '1.12', '1.13', '1.14', '1.15']
env: env:
VERBOSE: 1 VERBOSE: 1
GOFLAGS: -mod=readonly GOFLAGS: -mod=readonly

View file

@ -1,27 +1,76 @@
run:
timeout: 5m
linters-settings: linters-settings:
gci:
local-prefixes: github.com/spf13/viper
golint: golint:
min-confidence: 0.1 min-confidence: 0
goimports: goimports:
local-prefixes: github.com/spf13/viper local-prefixes: github.com/spf13/viper
linters: linters:
enable-all: true disable-all: true
disable: enable:
- funlen - bodyclose
- maligned - deadcode
- dogsled
- dupl
- exhaustive
- exportloopref
- gci
- goconst
- gofmt
- gofumpt
- goimports
- golint
- goprintffuncname
- govet
- ineffassign
- misspell
- nakedret
- noctx
- nolintlint
- prealloc
- rowserrcheck
- sqlclosecheck
- staticcheck
- structcheck
- stylecheck
- typecheck
- unconvert
- unparam
- unused
- varcheck
- whitespace
# TODO: fix me # fixme
- wsl # - errcheck
- gochecknoinits # - gochecknoglobals
- gosimple # - gochecknoinits
- gochecknoglobals # - gocognit
- errcheck # - gocritic
- lll # - gocyclo
- godox # - godot
- scopelint # - gosec
- gocyclo # - gosimple
- gocognit # - lll
- gocritic # - nlreturn
# - scopelint
service: # unused
golangci-lint-version: 1.21.x # - depguard
# - goheader
# - gomodguard
# don't enable:
# - asciicheck
# - funlen
# - godox
# - goerr113
# - gomnd
# - interfacer
# - maligned
# - nestif
# - testpackage
# - wsl

View file

@ -15,8 +15,8 @@ TEST_FORMAT = short-verbose
endif endif
# Dependency versions # Dependency versions
GOTESTSUM_VERSION = 0.4.0 GOTESTSUM_VERSION = 0.5.3
GOLANGCI_VERSION = 1.21.0 GOLANGCI_VERSION = 1.31.0
# Add the ability to override some variables # Add the ability to override some variables
# Use with care # Use with care

View file

@ -10,13 +10,13 @@ import (
func TestBindFlagValueSet(t *testing.T) { func TestBindFlagValueSet(t *testing.T) {
flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError) flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
var testValues = map[string]*string{ testValues := map[string]*string{
"host": nil, "host": nil,
"port": nil, "port": nil,
"endpoint": nil, "endpoint": nil,
} }
var mutatedTestValues = map[string]string{ mutatedTestValues := map[string]string{
"host": "localhost", "host": "localhost",
"port": "6060", "port": "6060",
"endpoint": "/public", "endpoint": "/public",
@ -44,8 +44,8 @@ func TestBindFlagValueSet(t *testing.T) {
} }
func TestBindFlagValue(t *testing.T) { func TestBindFlagValue(t *testing.T) {
var testString = "testing" testString := "testing"
var testValue = newStringValue(testString, &testString) testValue := newStringValue(testString, &testString)
flag := &pflag.Flag{ flag := &pflag.Flag{
Name: "testflag", Name: "testflag",

View file

@ -78,6 +78,7 @@ func TestNestedOverrides(t *testing.T) {
func overrideDefault(assert *assert.Assertions, firstPath string, firstValue interface{}, secondPath string, secondValue interface{}) *Viper { func overrideDefault(assert *assert.Assertions, firstPath string, firstValue interface{}, secondPath string, secondValue interface{}) *Viper {
return overrideFromLayer(defaultLayer, assert, firstPath, firstValue, secondPath, secondValue) return overrideFromLayer(defaultLayer, assert, firstPath, firstValue, secondPath, secondValue)
} }
func override(assert *assert.Assertions, firstPath string, firstValue interface{}, secondPath string, secondValue interface{}) *Viper { func override(assert *assert.Assertions, firstPath string, firstValue interface{}, secondPath string, secondValue interface{}) *Viper {
return overrideFromLayer(overrideLayer, assert, firstPath, firstValue, secondPath, secondValue) return overrideFromLayer(overrideLayer, assert, firstPath, firstValue, secondPath, secondValue)
} }

View file

@ -11,9 +11,9 @@ import (
"io" "io"
"os" "os"
"github.com/spf13/viper"
crypt "github.com/bketelsen/crypt/config" crypt "github.com/bketelsen/crypt/config"
"github.com/spf13/viper"
) )
type remoteConfigProvider struct{} type remoteConfigProvider struct{}

13
util.go
View file

@ -92,13 +92,22 @@ func insensitiviseMap(m map[string]interface{}) {
func absPathify(inPath string) string { func absPathify(inPath string) string {
jww.INFO.Println("Trying to resolve absolute path to", inPath) jww.INFO.Println("Trying to resolve absolute path to", inPath)
if strings.HasPrefix(inPath, "$HOME") { if inPath == "$HOME" || strings.HasPrefix(inPath, "$HOME"+string(os.PathSeparator)) {
inPath = userHomeDir() + inPath[5:] inPath = userHomeDir() + inPath[5:]
} }
if strings.HasPrefix(inPath, "$") { if strings.HasPrefix(inPath, "$") {
end := strings.Index(inPath, string(os.PathSeparator)) end := strings.Index(inPath, string(os.PathSeparator))
inPath = os.Getenv(inPath[1:end]) + inPath[end:]
var value, suffix string
if end == -1 {
value = os.Getenv(inPath[1:])
} else {
value = os.Getenv(inPath[1:end])
suffix = inPath[end:]
}
inPath = value + suffix
} }
if filepath.IsAbs(inPath) { if filepath.IsAbs(inPath) {

View file

@ -11,6 +11,8 @@
package viper package viper
import ( import (
"os"
"path/filepath"
"reflect" "reflect"
"testing" "testing"
) )
@ -22,14 +24,16 @@ func TestCopyAndInsensitiviseMap(t *testing.T) {
"Bar": map[interface{}]interface { "Bar": map[interface{}]interface {
}{ }{
"ABc": "A", "ABc": "A",
"cDE": "B"}, "cDE": "B",
},
} }
expected = map[string]interface{}{ expected = map[string]interface{}{
"foo": 32, "foo": 32,
"bar": map[string]interface { "bar": map[string]interface {
}{ }{
"abc": "A", "abc": "A",
"cde": "B"}, "cde": "B",
},
} }
) )
@ -52,3 +56,38 @@ func TestCopyAndInsensitiviseMap(t *testing.T) {
t.Fatal("Input map changed") t.Fatal("Input map changed")
} }
} }
func TestAbsPathify(t *testing.T) {
home := userHomeDir()
homer := filepath.Join(home, "homer")
wd, _ := os.Getwd()
os.Setenv("HOMER_ABSOLUTE_PATH", homer)
os.Setenv("VAR_WITH_RELATIVE_PATH", "relative")
tests := []struct {
input string
output string
}{
{"", wd},
{"sub", filepath.Join(wd, "sub")},
{"./", wd},
{"./sub", filepath.Join(wd, "sub")},
{"$HOME", home},
{"$HOME/", home},
{"$HOME/sub", filepath.Join(home, "sub")},
{"$HOMER_ABSOLUTE_PATH", homer},
{"$HOMER_ABSOLUTE_PATH/", homer},
{"$HOMER_ABSOLUTE_PATH/sub", filepath.Join(homer, "sub")},
{"$VAR_WITH_RELATIVE_PATH", filepath.Join(wd, "relative")},
{"$VAR_WITH_RELATIVE_PATH/", filepath.Join(wd, "relative")},
{"$VAR_WITH_RELATIVE_PATH/sub", filepath.Join(wd, "relative", "sub")},
}
for _, test := range tests {
got := absPathify(test.input)
if got != test.output {
t.Errorf("Got %v\nexpected\n%q", got, test.output)
}
}
}

View file

@ -409,6 +409,7 @@ func (v *Viper) WatchConfig() {
// SetConfigFile explicitly defines the path, name and extension of the config file. // SetConfigFile explicitly defines 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
@ -419,6 +420,7 @@ func (v *Viper) SetConfigFile(in string) {
// E.g. if your prefix is "spf", the env registry will look for env // E.g. if your prefix is "spf", the env registry will look for env
// variables that start with "SPF_". // variables that start with "SPF_".
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
@ -437,6 +439,7 @@ func (v *Viper) mergeWithEnvPrefix(in string) string {
// but empty environment variables as valid values instead of falling back. // but empty environment variables as valid values instead of falling back.
// For backward compatibility reasons this is false by default. // For backward compatibility reasons this is false by default.
func AllowEmptyEnv(allowEmptyEnv bool) { v.AllowEmptyEnv(allowEmptyEnv) } func AllowEmptyEnv(allowEmptyEnv bool) { v.AllowEmptyEnv(allowEmptyEnv) }
func (v *Viper) AllowEmptyEnv(allowEmptyEnv bool) { func (v *Viper) AllowEmptyEnv(allowEmptyEnv bool) {
v.allowEmptyEnv = allowEmptyEnv v.allowEmptyEnv = allowEmptyEnv
} }
@ -465,6 +468,7 @@ func (v *Viper) ConfigFileUsed() string { return v.configFile }
// AddConfigPath adds a path for Viper to search for the config file in. // AddConfigPath adds 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)
@ -486,6 +490,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)
@ -706,6 +711,7 @@ func (v *Viper) isPathShadowedInAutoEnv(path []string) string {
// //
// "a b c" // "a b c"
func SetTypeByDefaultValue(enable bool) { v.SetTypeByDefaultValue(enable) } func SetTypeByDefaultValue(enable bool) { v.SetTypeByDefaultValue(enable) }
func (v *Viper) SetTypeByDefaultValue(enable bool) { func (v *Viper) SetTypeByDefaultValue(enable bool) {
v.typeByDefValue = enable v.typeByDefValue = enable
} }
@ -723,6 +729,7 @@ func GetViper() *Viper {
// //
// 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{} {
lcaseKey := strings.ToLower(key) lcaseKey := strings.ToLower(key)
val := v.find(lcaseKey, true) val := v.find(lcaseKey, true)
@ -773,6 +780,7 @@ func (v *Viper) Get(key string) interface{} {
// Sub returns new Viper instance representing a sub tree of this instance. // Sub returns new Viper instance representing a sub tree of this instance.
// Sub is case-insensitive for a key. // Sub is case-insensitive for a key.
func Sub(key string) *Viper { return v.Sub(key) } func Sub(key string) *Viper { return v.Sub(key) }
func (v *Viper) Sub(key string) *Viper { func (v *Viper) Sub(key string) *Viper {
subv := New() subv := New()
data := v.Get(key) data := v.Get(key)
@ -789,6 +797,7 @@ func (v *Viper) Sub(key string) *Viper {
// GetString returns the value associated with the key as a string. // GetString returns the value associated with the key as a string.
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))
} }
@ -801,90 +810,105 @@ func (v *Viper) GetStringEnv(key string) string {
// GetBool returns the value associated with the key as a boolean. // GetBool returns the value associated with the key as a boolean.
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))
} }
// GetInt returns the value associated with the key as an integer. // GetInt returns the value associated with the key as an integer.
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))
} }
// GetInt32 returns the value associated with the key as an integer. // GetInt32 returns the value associated with the key as an integer.
func GetInt32(key string) int32 { return v.GetInt32(key) } func GetInt32(key string) int32 { return v.GetInt32(key) }
func (v *Viper) GetInt32(key string) int32 { func (v *Viper) GetInt32(key string) int32 {
return cast.ToInt32(v.Get(key)) return cast.ToInt32(v.Get(key))
} }
// GetInt64 returns the value associated with the key as an integer. // GetInt64 returns the value associated with the key as an integer.
func GetInt64(key string) int64 { return v.GetInt64(key) } func GetInt64(key string) int64 { return v.GetInt64(key) }
func (v *Viper) GetInt64(key string) int64 { func (v *Viper) GetInt64(key string) int64 {
return cast.ToInt64(v.Get(key)) return cast.ToInt64(v.Get(key))
} }
// GetUint returns the value associated with the key as an unsigned integer. // GetUint returns the value associated with the key as an unsigned integer.
func GetUint(key string) uint { return v.GetUint(key) } func GetUint(key string) uint { return v.GetUint(key) }
func (v *Viper) GetUint(key string) uint { func (v *Viper) GetUint(key string) uint {
return cast.ToUint(v.Get(key)) return cast.ToUint(v.Get(key))
} }
// GetUint32 returns the value associated with the key as an unsigned integer. // GetUint32 returns the value associated with the key as an unsigned integer.
func GetUint32(key string) uint32 { return v.GetUint32(key) } func GetUint32(key string) uint32 { return v.GetUint32(key) }
func (v *Viper) GetUint32(key string) uint32 { func (v *Viper) GetUint32(key string) uint32 {
return cast.ToUint32(v.Get(key)) return cast.ToUint32(v.Get(key))
} }
// GetUint64 returns the value associated with the key as an unsigned integer. // GetUint64 returns the value associated with the key as an unsigned integer.
func GetUint64(key string) uint64 { return v.GetUint64(key) } func GetUint64(key string) uint64 { return v.GetUint64(key) }
func (v *Viper) GetUint64(key string) uint64 { func (v *Viper) GetUint64(key string) uint64 {
return cast.ToUint64(v.Get(key)) return cast.ToUint64(v.Get(key))
} }
// GetFloat64 returns the value associated with the key as a float64. // GetFloat64 returns the value associated with the key as a float64.
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))
} }
// GetTime returns the value associated with the key as time. // GetTime returns the value associated with the key as time.
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))
} }
// GetDuration returns the value associated with the key as a duration. // GetDuration returns the value associated with the key as a duration.
func GetDuration(key string) time.Duration { return v.GetDuration(key) } func GetDuration(key string) time.Duration { return v.GetDuration(key) }
func (v *Viper) GetDuration(key string) time.Duration { func (v *Viper) GetDuration(key string) time.Duration {
return cast.ToDuration(v.Get(key)) return cast.ToDuration(v.Get(key))
} }
// GetIntSlice returns the value associated with the key as a slice of int values. // GetIntSlice returns the value associated with the key as a slice of int values.
func GetIntSlice(key string) []int { return v.GetIntSlice(key) } func GetIntSlice(key string) []int { return v.GetIntSlice(key) }
func (v *Viper) GetIntSlice(key string) []int { func (v *Viper) GetIntSlice(key string) []int {
return cast.ToIntSlice(v.Get(key)) return cast.ToIntSlice(v.Get(key))
} }
// GetStringSlice returns the value associated with the key as a slice of strings. // GetStringSlice returns the value associated with the key as a slice of strings.
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))
} }
// GetStringMap returns the value associated with the key as a map of interfaces. // GetStringMap returns the value associated with the key as a map of interfaces.
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))
} }
// GetStringMapString returns the value associated with the key as a map of strings. // GetStringMapString returns the value associated with the key as a map of strings.
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))
} }
// GetStringMapStringSlice returns the value associated with the key as a map to a slice of strings. // GetStringMapStringSlice returns the value associated with the key as a map to a slice of strings.
func GetStringMapStringSlice(key string) map[string][]string { return v.GetStringMapStringSlice(key) } func GetStringMapStringSlice(key string) map[string][]string { return v.GetStringMapStringSlice(key) }
func (v *Viper) GetStringMapStringSlice(key string) map[string][]string { func (v *Viper) GetStringMapStringSlice(key string) map[string][]string {
return cast.ToStringMapStringSlice(v.Get(key)) return cast.ToStringMapStringSlice(v.Get(key))
} }
@ -892,6 +916,7 @@ func (v *Viper) GetStringMapStringSlice(key string) map[string][]string {
// GetSizeInBytes returns the size of the value associated with the given key // GetSizeInBytes returns the size of the value associated with the given key
// in bytes. // in bytes.
func GetSizeInBytes(key string) uint { return v.GetSizeInBytes(key) } func GetSizeInBytes(key string) uint { return v.GetSizeInBytes(key) }
func (v *Viper) GetSizeInBytes(key string) uint { func (v *Viper) GetSizeInBytes(key string) uint {
sizeStr := cast.ToString(v.Get(key)) sizeStr := cast.ToString(v.Get(key))
return parseSizeInBytes(sizeStr) return parseSizeInBytes(sizeStr)
@ -901,14 +926,9 @@ func (v *Viper) GetSizeInBytes(key string) uint {
func UnmarshalKey(key string, rawVal interface{}, opts ...DecoderConfigOption) error { func UnmarshalKey(key string, rawVal interface{}, opts ...DecoderConfigOption) error {
return v.UnmarshalKey(key, rawVal, opts...) return v.UnmarshalKey(key, rawVal, opts...)
} }
func (v *Viper) UnmarshalKey(key string, rawVal interface{}, opts ...DecoderConfigOption) error { func (v *Viper) UnmarshalKey(key string, rawVal interface{}, opts ...DecoderConfigOption) error {
err := decode(v.Get(key), defaultDecoderConfig(rawVal, opts...)) return decode(v.Get(key), defaultDecoderConfig(rawVal, opts...))
if err != nil {
return err
}
return nil
} }
// Unmarshal unmarshals the config into a Struct. Make sure that the tags // Unmarshal unmarshals the config into a Struct. Make sure that the tags
@ -916,14 +936,9 @@ func (v *Viper) UnmarshalKey(key string, rawVal interface{}, opts ...DecoderConf
func Unmarshal(rawVal interface{}, opts ...DecoderConfigOption) error { func Unmarshal(rawVal interface{}, opts ...DecoderConfigOption) error {
return v.Unmarshal(rawVal, opts...) return v.Unmarshal(rawVal, opts...)
} }
func (v *Viper) Unmarshal(rawVal interface{}, opts ...DecoderConfigOption) error { func (v *Viper) Unmarshal(rawVal interface{}, opts ...DecoderConfigOption) error {
err := decode(v.AllSettings(), defaultDecoderConfig(rawVal, opts...)) return decode(v.AllSettings(), defaultDecoderConfig(rawVal, opts...))
if err != nil {
return err
}
return nil
} }
// defaultDecoderConfig returns default mapsstructure.DecoderConfig with suppot // defaultDecoderConfig returns default mapsstructure.DecoderConfig with suppot
@ -958,22 +973,18 @@ func decode(input interface{}, config *mapstructure.DecoderConfig) error {
func UnmarshalExact(rawVal interface{}, opts ...DecoderConfigOption) error { func UnmarshalExact(rawVal interface{}, opts ...DecoderConfigOption) error {
return v.UnmarshalExact(rawVal, opts...) return v.UnmarshalExact(rawVal, opts...)
} }
func (v *Viper) UnmarshalExact(rawVal interface{}, opts ...DecoderConfigOption) error { func (v *Viper) UnmarshalExact(rawVal interface{}, opts ...DecoderConfigOption) error {
config := defaultDecoderConfig(rawVal, opts...) config := defaultDecoderConfig(rawVal, opts...)
config.ErrorUnused = true config.ErrorUnused = true
err := decode(v.AllSettings(), config) return decode(v.AllSettings(), config)
if err != nil {
return err
}
return nil
} }
// BindPFlags binds a full flag set to the configuration, using each flag's long // BindPFlags binds a full flag set to the configuration, using each flag's long
// name as the config key. // name as the config key.
func BindPFlags(flags *pflag.FlagSet) error { return v.BindPFlags(flags) } func BindPFlags(flags *pflag.FlagSet) error { return v.BindPFlags(flags) }
func (v *Viper) BindPFlags(flags *pflag.FlagSet) error { func (v *Viper) BindPFlags(flags *pflag.FlagSet) error {
return v.BindFlagValues(pflagValueSet{flags}) return v.BindFlagValues(pflagValueSet{flags})
} }
@ -985,6 +996,7 @@ func (v *Viper) BindPFlags(flags *pflag.FlagSet) error {
// Viper.BindPFlag("port", serverCmd.Flags().Lookup("port")) // Viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))
// //
func BindPFlag(key string, flag *pflag.Flag) error { return v.BindPFlag(key, flag) } func BindPFlag(key string, flag *pflag.Flag) error { return v.BindPFlag(key, flag) }
func (v *Viper) BindPFlag(key string, flag *pflag.Flag) error { func (v *Viper) BindPFlag(key string, flag *pflag.Flag) error {
return v.BindFlagValue(key, pflagValue{flag}) return v.BindFlagValue(key, pflagValue{flag})
} }
@ -992,6 +1004,7 @@ func (v *Viper) BindPFlag(key string, flag *pflag.Flag) error {
// BindFlagValues binds a full FlagValue set to the configuration, using each flag's long // BindFlagValues binds a full FlagValue set to the configuration, using each flag's long
// name as the config key. // name as the config key.
func BindFlagValues(flags FlagValueSet) error { return v.BindFlagValues(flags) } func BindFlagValues(flags FlagValueSet) error { return v.BindFlagValues(flags) }
func (v *Viper) BindFlagValues(flags FlagValueSet) (err error) { func (v *Viper) BindFlagValues(flags FlagValueSet) (err error) {
flags.VisitAll(func(flag FlagValue) { flags.VisitAll(func(flag FlagValue) {
if err = v.BindFlagValue(flag.Name(), flag); err != nil { if err = v.BindFlagValue(flag.Name(), flag); err != nil {
@ -1003,6 +1016,7 @@ func (v *Viper) BindFlagValues(flags FlagValueSet) (err error) {
// BindFlagValue binds a specific key to a FlagValue. // BindFlagValue binds a specific key to a FlagValue.
func BindFlagValue(key string, flag FlagValue) error { return v.BindFlagValue(key, flag) } func BindFlagValue(key string, flag FlagValue) error { return v.BindFlagValue(key, flag) }
func (v *Viper) BindFlagValue(key string, flag FlagValue) error { func (v *Viper) BindFlagValue(key string, flag FlagValue) 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)
@ -1016,6 +1030,7 @@ func (v *Viper) BindFlagValue(key string, flag FlagValue) 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) error { return v.BindEnv(input...) } func BindEnv(input ...string) error { return v.BindEnv(input...) }
func (v *Viper) BindEnv(input ...string) error { func (v *Viper) BindEnv(input ...string) error {
var key, envkey string var key, envkey string
if len(input) == 0 { if len(input) == 0 {
@ -1214,6 +1229,7 @@ func stringToStringConv(val string) interface{} {
// IsSet checks to see if the key has been set in any of the data locations. // IsSet checks to see if the key has been set in any of the data locations.
// IsSet is case-insensitive for a key. // IsSet is case-insensitive for a key.
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 {
lcaseKey := strings.ToLower(key) lcaseKey := strings.ToLower(key)
val := v.find(lcaseKey, false) val := v.find(lcaseKey, false)
@ -1223,6 +1239,7 @@ func (v *Viper) IsSet(key string) bool {
// AutomaticEnv has Viper check ENV variables for all. // AutomaticEnv has 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
} }
@ -1231,6 +1248,7 @@ func (v *Viper) AutomaticEnv() {
// Useful for mapping an environmental variable to a key that does // Useful for mapping an environmental variable to a key that does
// not match it. // not match it.
func SetEnvKeyReplacer(r *strings.Replacer) { v.SetEnvKeyReplacer(r) } func SetEnvKeyReplacer(r *strings.Replacer) { v.SetEnvKeyReplacer(r) }
func (v *Viper) SetEnvKeyReplacer(r *strings.Replacer) { func (v *Viper) SetEnvKeyReplacer(r *strings.Replacer) {
v.envKeyReplacer = r v.envKeyReplacer = r
} }
@ -1238,6 +1256,7 @@ func (v *Viper) SetEnvKeyReplacer(r *strings.Replacer) {
// RegisterAlias creates an alias that provides another accessor for the same key. // RegisterAlias creates an alias that provides 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))
} }
@ -1285,6 +1304,7 @@ func (v *Viper) realKey(key string) string {
// InConfig checks to see if the given key (or an alias) is in the config file. // InConfig checks 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)
@ -1297,6 +1317,7 @@ func (v *Viper) InConfig(key string) bool {
// SetDefault is case-insensitive for a key. // SetDefault is case-insensitive for a 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))
@ -1315,6 +1336,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
// flags, config file, ENV, default, or key/value store. // flags, 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))
@ -1331,6 +1353,7 @@ func (v *Viper) Set(key string, value interface{}) {
// ReadInConfig will discover and load the configuration file from disk // ReadInConfig 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")
filename, err := v.getConfigFile() filename, err := v.getConfigFile()
@ -1361,6 +1384,7 @@ func (v *Viper) ReadInConfig() error {
// MergeInConfig merges a new configuration with an existing config. // MergeInConfig merges a new configuration with an existing config.
func MergeInConfig() error { return v.MergeInConfig() } func MergeInConfig() error { return v.MergeInConfig() }
func (v *Viper) MergeInConfig() error { func (v *Viper) MergeInConfig() error {
jww.INFO.Println("Attempting to merge in config file") jww.INFO.Println("Attempting to merge in config file")
filename, err := v.getConfigFile() filename, err := v.getConfigFile()
@ -1383,6 +1407,7 @@ func (v *Viper) MergeInConfig() error {
// ReadConfig will read a configuration file, setting existing keys to nil if the // ReadConfig will read a configuration file, setting existing keys to nil if the
// key does not exist in the file. // key does not exist in the file.
func ReadConfig(in io.Reader) error { return v.ReadConfig(in) } func ReadConfig(in io.Reader) error { return v.ReadConfig(in) }
func (v *Viper) ReadConfig(in io.Reader) error { func (v *Viper) ReadConfig(in io.Reader) error {
v.config = make(map[string]interface{}) v.config = make(map[string]interface{})
return v.unmarshalReader(in, v.config) return v.unmarshalReader(in, v.config)
@ -1390,6 +1415,7 @@ func (v *Viper) ReadConfig(in io.Reader) error {
// MergeConfig merges a new configuration with an existing config. // MergeConfig merges a new configuration with an existing config.
func MergeConfig(in io.Reader) error { return v.MergeConfig(in) } func MergeConfig(in io.Reader) error { return v.MergeConfig(in) }
func (v *Viper) MergeConfig(in io.Reader) error { func (v *Viper) MergeConfig(in io.Reader) error {
cfg := make(map[string]interface{}) cfg := make(map[string]interface{})
if err := v.unmarshalReader(in, cfg); err != nil { if err := v.unmarshalReader(in, cfg); err != nil {
@ -1401,6 +1427,7 @@ func (v *Viper) MergeConfig(in io.Reader) error {
// MergeConfigMap merges the configuration from the map given with an existing config. // MergeConfigMap merges the configuration from the map given with an existing config.
// Note that the map given may be modified. // Note that the map given may be modified.
func MergeConfigMap(cfg map[string]interface{}) error { return v.MergeConfigMap(cfg) } func MergeConfigMap(cfg map[string]interface{}) error { return v.MergeConfigMap(cfg) }
func (v *Viper) MergeConfigMap(cfg map[string]interface{}) error { func (v *Viper) MergeConfigMap(cfg map[string]interface{}) error {
if v.config == nil { if v.config == nil {
v.config = make(map[string]interface{}) v.config = make(map[string]interface{})
@ -1412,6 +1439,7 @@ func (v *Viper) MergeConfigMap(cfg map[string]interface{}) error {
// WriteConfig writes the current configuration to a file. // WriteConfig writes the current configuration to a file.
func WriteConfig() error { return v.WriteConfig() } func WriteConfig() error { return v.WriteConfig() }
func (v *Viper) WriteConfig() error { func (v *Viper) WriteConfig() error {
filename, err := v.getConfigFile() filename, err := v.getConfigFile()
if err != nil { if err != nil {
@ -1422,6 +1450,7 @@ func (v *Viper) WriteConfig() error {
// SafeWriteConfig writes current configuration to file only if the file does not exist. // SafeWriteConfig writes current configuration to file only if the file does not exist.
func SafeWriteConfig() error { return v.SafeWriteConfig() } func SafeWriteConfig() error { return v.SafeWriteConfig() }
func (v *Viper) SafeWriteConfig() error { func (v *Viper) SafeWriteConfig() error {
if len(v.configPaths) < 1 { if len(v.configPaths) < 1 {
return errors.New("missing configuration for 'configPath'") return errors.New("missing configuration for 'configPath'")
@ -1431,12 +1460,14 @@ func (v *Viper) SafeWriteConfig() error {
// WriteConfigAs writes current configuration to a given filename. // WriteConfigAs writes current configuration to a given filename.
func WriteConfigAs(filename string) error { return v.WriteConfigAs(filename) } func WriteConfigAs(filename string) error { return v.WriteConfigAs(filename) }
func (v *Viper) WriteConfigAs(filename string) error { func (v *Viper) WriteConfigAs(filename string) error {
return v.writeConfig(filename, true) return v.writeConfig(filename, true)
} }
// SafeWriteConfigAs writes current configuration to a given filename if it does not exist. // SafeWriteConfigAs writes current configuration to a given filename if it does not exist.
func SafeWriteConfigAs(filename string) error { return v.SafeWriteConfigAs(filename) } func SafeWriteConfigAs(filename string) error { return v.SafeWriteConfigAs(filename) }
func (v *Viper) SafeWriteConfigAs(filename string) error { func (v *Viper) SafeWriteConfigAs(filename string) error {
alreadyExists, err := afero.Exists(v.fs, filename) alreadyExists, err := afero.Exists(v.fs, filename)
if alreadyExists && err == nil { if alreadyExists && err == nil {
@ -1487,6 +1518,7 @@ func (v *Viper) writeConfig(filename string, force bool) error {
func unmarshalReader(in io.Reader, c map[string]interface{}) error { func unmarshalReader(in io.Reader, c map[string]interface{}) error {
return v.unmarshalReader(in, c) return v.unmarshalReader(in, c)
} }
func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error { func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
buf.ReadFrom(in) buf.ReadFrom(in)
@ -1761,6 +1793,7 @@ func mergeMaps(
// ReadRemoteConfig attempts to get configuration from a remote source // ReadRemoteConfig attempts to get configuration from a remote source
// and read it in the remote configuration registry. // and read it in the remote configuration registry.
func ReadRemoteConfig() error { return v.ReadRemoteConfig() } func ReadRemoteConfig() error { return v.ReadRemoteConfig() }
func (v *Viper) ReadRemoteConfig() error { func (v *Viper) ReadRemoteConfig() error {
return v.getKeyValueConfig() return v.getKeyValueConfig()
} }
@ -1783,9 +1816,13 @@ func (v *Viper) getKeyValueConfig() error {
for _, rp := range v.remoteProviders { for _, rp := range v.remoteProviders {
val, err := v.getRemoteConfig(rp) val, err := v.getRemoteConfig(rp)
if err != nil { if err != nil {
jww.ERROR.Printf("get remote config: %s", err)
continue continue
} }
v.kvstore = val v.kvstore = val
return nil return nil
} }
return RemoteConfigError("No Files Found") return RemoteConfigError("No Files Found")
@ -1842,6 +1879,7 @@ func (v *Viper) watchRemoteConfig(provider RemoteProvider) (map[string]interface
// AllKeys returns all keys holding a value, regardless of where they are set. // AllKeys returns all keys holding a value, regardless of where they are set.
// Nested keys are returned with a v.keyDelim separator // Nested keys are returned with a v.keyDelim separator
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]bool{} m := map[string]bool{}
// add all paths, by order of descending priority to ensure correct shadowing // add all paths, by order of descending priority to ensure correct shadowing
@ -1922,6 +1960,7 @@ outer:
// AllSettings merges all settings and returns them as a map[string]interface{}. // AllSettings merges all settings and returns them 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{}{}
// start from the list of keys, and construct the map one value at a time // start from the list of keys, and construct the map one value at a time
@ -1943,6 +1982,7 @@ func (v *Viper) AllSettings() map[string]interface{} {
// SetFs sets the filesystem to use to read configuration. // SetFs sets the filesystem to use to read configuration.
func SetFs(fs afero.Fs) { v.SetFs(fs) } func SetFs(fs afero.Fs) { v.SetFs(fs) }
func (v *Viper) SetFs(fs afero.Fs) { func (v *Viper) SetFs(fs afero.Fs) {
v.fs = fs v.fs = fs
} }
@ -1950,6 +1990,7 @@ func (v *Viper) SetFs(fs afero.Fs) {
// SetConfigName sets name for the config file. // SetConfigName sets 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
@ -1960,6 +2001,7 @@ func (v *Viper) SetConfigName(in string) {
// SetConfigType sets the type of the configuration returned by the // SetConfigType sets the type of the configuration returned by the
// remote source, e.g. "json". // remote source, e.g. "json".
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
@ -1968,6 +2010,7 @@ func (v *Viper) SetConfigType(in string) {
// SetConfigPermissions sets the permissions for the config file. // SetConfigPermissions sets the permissions for the config file.
func SetConfigPermissions(perm os.FileMode) { v.SetConfigPermissions(perm) } func SetConfigPermissions(perm os.FileMode) { v.SetConfigPermissions(perm) }
func (v *Viper) SetConfigPermissions(perm os.FileMode) { func (v *Viper) SetConfigPermissions(perm os.FileMode) {
v.configPermissions = perm.Perm() v.configPermissions = perm.Perm()
} }
@ -2038,6 +2081,7 @@ func (v *Viper) findConfigFile() (string, error) {
// Debug prints all configuration registries for debugging // Debug prints all configuration registries for debugging
// purposes. // purposes.
func Debug() { v.Debug() } func Debug() { v.Debug() }
func (v *Viper) Debug() { func (v *Viper) Debug() {
fmt.Printf("Aliases:\n%#v\n", v.aliases) fmt.Printf("Aliases:\n%#v\n", v.aliases)
fmt.Printf("Override:\n%#v\n", v.override) fmt.Printf("Override:\n%#v\n", v.override)

View file

@ -26,7 +26,6 @@ import (
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
"github.com/spf13/afero" "github.com/spf13/afero"
"github.com/spf13/cast" "github.com/spf13/cast"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
@ -717,7 +716,8 @@ func TestAllKeys(t *testing.T) {
{"key": 1}, {"key": 1},
{"key": 2}, {"key": 2},
{"key": 3}, {"key": 3},
{"key": 4}}, {"key": 4},
},
}, },
}, },
"title_dotenv": "DotEnv Example", "title_dotenv": "DotEnv Example",
@ -851,13 +851,13 @@ func TestBindPFlags(t *testing.T) {
v := New() // create independent Viper object v := New() // create independent Viper object
flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError) flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
var testValues = map[string]*string{ testValues := map[string]*string{
"host": nil, "host": nil,
"port": nil, "port": nil,
"endpoint": nil, "endpoint": nil,
} }
var mutatedTestValues = map[string]string{ mutatedTestValues := map[string]string{
"host": "localhost", "host": "localhost",
"port": "6060", "port": "6060",
"endpoint": "/public", "endpoint": "/public",
@ -974,8 +974,8 @@ func TestBindPFlagsIntSlice(t *testing.T) {
} }
func TestBindPFlag(t *testing.T) { func TestBindPFlag(t *testing.T) {
var testString = "testing" testString := "testing"
var testValue = newStringValue(testString, &testString) testValue := newStringValue(testString, &testString)
flag := &pflag.Flag{ flag := &pflag.Flag{
Name: "testflag", Name: "testflag",
@ -1048,8 +1048,8 @@ func TestBoundCaseSensitivity(t *testing.T) {
assert.Equal(t, "blue", Get("eyes")) assert.Equal(t, "blue", Get("eyes"))
var testString = "green" testString := "green"
var testValue = newStringValue(testString, &testString) testValue := newStringValue(testString, &testString)
flag := &pflag.Flag{ flag := &pflag.Flag{
Name: "eyeballs", Name: "eyeballs",
@ -1128,9 +1128,11 @@ func TestFindsNestedKeys(t *testing.T) {
}, },
map[string]interface{}{ map[string]interface{}{
"type": "Chocolate", "type": "Chocolate",
}, map[string]interface{}{ },
map[string]interface{}{
"type": "Blueberry", "type": "Blueberry",
}, map[string]interface{}{ },
map[string]interface{}{
"type": "Devil's Food", "type": "Devil's Food",
}, },
}, },
@ -1995,7 +1997,8 @@ func TestCaseInsensitiveSet(t *testing.T) {
"Bar": map[interface{}]interface { "Bar": map[interface{}]interface {
}{ }{
"ABc": "A", "ABc": "A",
"cDE": "B"}, "cDE": "B",
},
} }
m2 := map[string]interface{}{ m2 := map[string]interface{}{
@ -2003,7 +2006,8 @@ func TestCaseInsensitiveSet(t *testing.T) {
"Bar": map[interface{}]interface { "Bar": map[interface{}]interface {
}{ }{
"bCd": "A", "bCd": "A",
"eFG": "B"}, "eFG": "B",
},
} }
Set("Given1", m1) Set("Given1", m1)