mirror of
https://github.com/spf13/viper
synced 2024-06-28 22:59:08 +00:00
Compare commits
9 commits
2a4be09743
...
6807ca3ed5
Author | SHA1 | Date | |
---|---|---|---|
|
6807ca3ed5 | ||
|
ea35b92596 | ||
|
3d32668ee5 | ||
|
d539b7a246 | ||
|
33920bee87 | ||
|
ec459a1935 | ||
|
bd3d203553 | ||
|
ad27eabd6a | ||
|
e5316b8387 |
12
.github/workflows/ci.yaml
vendored
12
.github/workflows/ci.yaml
vendored
|
@ -21,7 +21,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||||
|
@ -49,7 +49,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||||
|
@ -70,7 +70,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||||
|
|
||||||
- name: Set up Go
|
- name: Set up Go
|
||||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||||
|
@ -88,7 +88,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||||
|
|
||||||
- name: Set up Nix
|
- name: Set up Nix
|
||||||
uses: cachix/install-nix-action@8887e596b4ee1134dae06b98d573bd674693f47c # v26
|
uses: cachix/install-nix-action@8887e596b4ee1134dae06b98d573bd674693f47c # v26
|
||||||
|
@ -109,7 +109,7 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||||
|
|
||||||
- name: Dependency Review
|
- name: Dependency Review
|
||||||
uses: actions/dependency-review-action@733dd5d4a5203f238c33806593ec0f5fc5343d8c # v4.2.4
|
uses: actions/dependency-review-action@5bbc3ba658137598168acb2ab73b21c432dd411b # v4.2.5
|
||||||
|
|
8
.github/workflows/codeql-analysis.yaml
vendored
8
.github/workflows/codeql-analysis.yaml
vendored
|
@ -39,11 +39,11 @@ jobs:
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 # v4.1.2
|
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9
|
uses: github/codeql-action/init@8f596b4ae3cb3c588a5c46780b86dd53fef16c52 # v3.25.2
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
|
@ -54,7 +54,7 @@ jobs:
|
||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9
|
uses: github/codeql-action/autobuild@8f596b4ae3cb3c588a5c46780b86dd53fef16c52 # v3.25.2
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 https://git.io/JvXDl
|
# 📚 https://git.io/JvXDl
|
||||||
|
@ -68,5 +68,5 @@ jobs:
|
||||||
# make release
|
# make release
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9
|
uses: github/codeql-action/analyze@8f596b4ae3cb3c588a5c46780b86dd53fef16c52 # v3.25.2
|
||||||
|
|
||||||
|
|
4
go.mod
4
go.mod
|
@ -7,7 +7,7 @@ require (
|
||||||
github.com/hashicorp/hcl v1.0.0
|
github.com/hashicorp/hcl v1.0.0
|
||||||
github.com/magiconair/properties v1.8.7
|
github.com/magiconair/properties v1.8.7
|
||||||
github.com/mitchellh/mapstructure v1.5.0
|
github.com/mitchellh/mapstructure v1.5.0
|
||||||
github.com/pelletier/go-toml/v2 v2.2.0
|
github.com/pelletier/go-toml/v2 v2.2.1
|
||||||
github.com/sagikazarmark/crypt v0.19.0
|
github.com/sagikazarmark/crypt v0.19.0
|
||||||
github.com/sagikazarmark/locafero v0.4.0
|
github.com/sagikazarmark/locafero v0.4.0
|
||||||
github.com/sagikazarmark/slog-shim v0.1.0
|
github.com/sagikazarmark/slog-shim v0.1.0
|
||||||
|
@ -77,7 +77,7 @@ require (
|
||||||
go.uber.org/zap v1.21.0 // indirect
|
go.uber.org/zap v1.21.0 // indirect
|
||||||
golang.org/x/crypto v0.21.0 // indirect
|
golang.org/x/crypto v0.21.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||||
golang.org/x/net v0.22.0 // indirect
|
golang.org/x/net v0.23.0 // indirect
|
||||||
golang.org/x/oauth2 v0.18.0 // indirect
|
golang.org/x/oauth2 v0.18.0 // indirect
|
||||||
golang.org/x/sync v0.6.0 // indirect
|
golang.org/x/sync v0.6.0 // indirect
|
||||||
golang.org/x/sys v0.18.0 // indirect
|
golang.org/x/sys v0.18.0 // indirect
|
||||||
|
|
8
go.sum
8
go.sum
|
@ -207,8 +207,8 @@ github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OS
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
|
github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=
|
||||||
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo=
|
github.com/pelletier/go-toml/v2 v2.2.1 h1:9TA9+T8+8CUCO2+WYnDLCgrYi9+omqKXyjDtosvtEhg=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.0/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
github.com/pelletier/go-toml/v2 v2.2.1/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
|
@ -340,8 +340,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
|
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||||
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
|
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
|
||||||
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
|
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
|
||||||
|
|
246
viper.go
246
viper.go
|
@ -206,6 +206,8 @@ type Viper struct {
|
||||||
automaticEnvApplied bool
|
automaticEnvApplied bool
|
||||||
envKeyReplacer StringReplacer
|
envKeyReplacer StringReplacer
|
||||||
allowEmptyEnv bool
|
allowEmptyEnv bool
|
||||||
|
aliasesFirstly bool
|
||||||
|
aliasesStepByStep bool
|
||||||
|
|
||||||
parents []string
|
parents []string
|
||||||
config map[string]any
|
config map[string]any
|
||||||
|
@ -241,6 +243,8 @@ func New() *Viper {
|
||||||
v.pflags = make(map[string]FlagValue)
|
v.pflags = make(map[string]FlagValue)
|
||||||
v.env = make(map[string][]string)
|
v.env = make(map[string][]string)
|
||||||
v.aliases = make(map[string]string)
|
v.aliases = make(map[string]string)
|
||||||
|
v.aliasesFirstly = true
|
||||||
|
v.aliasesStepByStep = false
|
||||||
v.typeByDefValue = false
|
v.typeByDefValue = false
|
||||||
v.logger = slog.New(&discardHandler{})
|
v.logger = slog.New(&discardHandler{})
|
||||||
|
|
||||||
|
@ -539,6 +543,25 @@ func (v *Viper) mergeWithEnvPrefix(in string) string {
|
||||||
return strings.ToUpper(in)
|
return strings.ToUpper(in)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AliasesFirstly changes the order of processing aliases.
|
||||||
|
// If TRUE is passed, values will be searched by alias.
|
||||||
|
// If FALSE is passed, the standard key is processed first,
|
||||||
|
// and if the value is not found, an alias search will be performed.
|
||||||
|
func AliasesFirstly(firstly bool) { v.AliasesFirstly(firstly) }
|
||||||
|
|
||||||
|
func (v *Viper) AliasesFirstly(firstly bool) {
|
||||||
|
v.aliasesFirstly = firstly
|
||||||
|
}
|
||||||
|
|
||||||
|
// AliasesStepByStep changes the processing of nested aliases.
|
||||||
|
// If TRUE is passed, the values will be searched at each nesting level of the alias.
|
||||||
|
// If FALSE is passed, the values will be searched at the last nesting level of the aliases
|
||||||
|
func AliasesStepByStep(enable bool) { v.AliasesStepByStep(enable) }
|
||||||
|
|
||||||
|
func (v *Viper) AliasesStepByStep(enable bool) {
|
||||||
|
v.aliasesStepByStep = enable
|
||||||
|
}
|
||||||
|
|
||||||
// AllowEmptyEnv tells Viper to consider set,
|
// AllowEmptyEnv tells Viper to consider set,
|
||||||
// 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.
|
||||||
|
@ -1294,8 +1317,8 @@ func (v *Viper) MustBindEnv(input ...string) {
|
||||||
// Note: this assumes a lower-cased key given.
|
// Note: this assumes a lower-cased key given.
|
||||||
func (v *Viper) find(lcaseKey string, flagDefault bool) any {
|
func (v *Viper) find(lcaseKey string, flagDefault bool) any {
|
||||||
var (
|
var (
|
||||||
|
lastKey string
|
||||||
val any
|
val any
|
||||||
exists bool
|
|
||||||
path = strings.Split(lcaseKey, v.keyDelim)
|
path = strings.Split(lcaseKey, v.keyDelim)
|
||||||
nested = len(path) > 1
|
nested = len(path) > 1
|
||||||
)
|
)
|
||||||
|
@ -1305,110 +1328,27 @@ func (v *Viper) find(lcaseKey string, flagDefault bool) any {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the requested key is an alias, then return the proper key
|
for lastKey != lcaseKey {
|
||||||
lcaseKey = v.realKey(lcaseKey)
|
if v.aliasesFirstly {
|
||||||
path = strings.Split(lcaseKey, v.keyDelim)
|
// if the requested key is an alias, then return the proper key
|
||||||
nested = len(path) > 1
|
lastKey = lcaseKey
|
||||||
|
lcaseKey = v.realKey(lcaseKey)
|
||||||
// Set() override first
|
path = strings.Split(lcaseKey, v.keyDelim)
|
||||||
val = v.searchMap(v.override, path)
|
nested = len(path) > 1
|
||||||
if val != nil {
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
if nested && v.isPathShadowedInDeepMap(path, v.override) != "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PFlag override next
|
|
||||||
flag, exists := v.pflags[lcaseKey]
|
|
||||||
if exists && flag.HasChanged() {
|
|
||||||
switch flag.ValueType() {
|
|
||||||
case "int", "int8", "int16", "int32", "int64":
|
|
||||||
return cast.ToInt(flag.ValueString())
|
|
||||||
case "bool":
|
|
||||||
return cast.ToBool(flag.ValueString())
|
|
||||||
case "stringSlice", "stringArray":
|
|
||||||
s := strings.TrimPrefix(flag.ValueString(), "[")
|
|
||||||
s = strings.TrimSuffix(s, "]")
|
|
||||||
res, _ := readAsCSV(s)
|
|
||||||
return res
|
|
||||||
case "intSlice":
|
|
||||||
s := strings.TrimPrefix(flag.ValueString(), "[")
|
|
||||||
s = strings.TrimSuffix(s, "]")
|
|
||||||
res, _ := readAsCSV(s)
|
|
||||||
return cast.ToIntSlice(res)
|
|
||||||
case "durationSlice":
|
|
||||||
s := strings.TrimPrefix(flag.ValueString(), "[")
|
|
||||||
s = strings.TrimSuffix(s, "]")
|
|
||||||
slice := strings.Split(s, ",")
|
|
||||||
return cast.ToDurationSlice(slice)
|
|
||||||
case "stringToString":
|
|
||||||
return stringToStringConv(flag.ValueString())
|
|
||||||
case "stringToInt":
|
|
||||||
return stringToIntConv(flag.ValueString())
|
|
||||||
default:
|
|
||||||
return flag.ValueString()
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if nested && v.isPathShadowedInFlatMap(path, v.pflags) != "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Env override next
|
// Set() override first
|
||||||
if v.automaticEnvApplied {
|
val = v.searchMap(v.override, path)
|
||||||
envKey := strings.Join(append(v.parents, lcaseKey), ".")
|
if val != nil {
|
||||||
// even if it hasn't been registered, if automaticEnv is used,
|
|
||||||
// check any Get request
|
|
||||||
if val, ok := v.getEnv(v.mergeWithEnvPrefix(envKey)); ok {
|
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
if nested && v.isPathShadowedInAutoEnv(path) != "" {
|
if nested && v.isPathShadowedInDeepMap(path, v.override) != "" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
|
||||||
envkeys, exists := v.env[lcaseKey]
|
|
||||||
if exists {
|
|
||||||
for _, envkey := range envkeys {
|
|
||||||
if val, ok := v.getEnv(envkey); ok {
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if nested && v.isPathShadowedInFlatMap(path, v.env) != "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Config file next
|
// PFlag override next
|
||||||
val = v.searchIndexableWithPathPrefixes(v.config, path)
|
flag, exists := v.pflags[lcaseKey]
|
||||||
if val != nil {
|
if exists && flag.HasChanged() {
|
||||||
return val
|
|
||||||
}
|
|
||||||
if nested && v.isPathShadowedInDeepMap(path, v.config) != "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// K/V store next
|
|
||||||
val = v.searchMap(v.kvstore, path)
|
|
||||||
if val != nil {
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
if nested && v.isPathShadowedInDeepMap(path, v.kvstore) != "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default next
|
|
||||||
val = v.searchMap(v.defaults, path)
|
|
||||||
if val != nil {
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
if nested && v.isPathShadowedInDeepMap(path, v.defaults) != "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if flagDefault {
|
|
||||||
// last chance: if no value is found and a flag does exist for the key,
|
|
||||||
// get the flag's default value even if the flag's value has not been set.
|
|
||||||
if flag, exists := v.pflags[lcaseKey]; exists {
|
|
||||||
switch flag.ValueType() {
|
switch flag.ValueType() {
|
||||||
case "int", "int8", "int16", "int32", "int64":
|
case "int", "int8", "int16", "int32", "int64":
|
||||||
return cast.ToInt(flag.ValueString())
|
return cast.ToInt(flag.ValueString())
|
||||||
|
@ -1424,20 +1364,116 @@ func (v *Viper) find(lcaseKey string, flagDefault bool) any {
|
||||||
s = strings.TrimSuffix(s, "]")
|
s = strings.TrimSuffix(s, "]")
|
||||||
res, _ := readAsCSV(s)
|
res, _ := readAsCSV(s)
|
||||||
return cast.ToIntSlice(res)
|
return cast.ToIntSlice(res)
|
||||||
case "stringToString":
|
|
||||||
return stringToStringConv(flag.ValueString())
|
|
||||||
case "stringToInt":
|
|
||||||
return stringToIntConv(flag.ValueString())
|
|
||||||
case "durationSlice":
|
case "durationSlice":
|
||||||
s := strings.TrimPrefix(flag.ValueString(), "[")
|
s := strings.TrimPrefix(flag.ValueString(), "[")
|
||||||
s = strings.TrimSuffix(s, "]")
|
s = strings.TrimSuffix(s, "]")
|
||||||
slice := strings.Split(s, ",")
|
slice := strings.Split(s, ",")
|
||||||
return cast.ToDurationSlice(slice)
|
return cast.ToDurationSlice(slice)
|
||||||
|
case "stringToString":
|
||||||
|
return stringToStringConv(flag.ValueString())
|
||||||
|
case "stringToInt":
|
||||||
|
return stringToIntConv(flag.ValueString())
|
||||||
default:
|
default:
|
||||||
return flag.ValueString()
|
return flag.ValueString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// last item, no need to check shadowing
|
if nested && v.isPathShadowedInFlatMap(path, v.pflags) != "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Env override next
|
||||||
|
if v.automaticEnvApplied {
|
||||||
|
envKey := strings.Join(append(v.parents, lcaseKey), ".")
|
||||||
|
// even if it hasn't been registered, if automaticEnv is used,
|
||||||
|
// check any Get request
|
||||||
|
if val, ok := v.getEnv(v.mergeWithEnvPrefix(envKey)); ok {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
if nested && v.isPathShadowedInAutoEnv(path) != "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
envkeys, exists := v.env[lcaseKey]
|
||||||
|
if exists {
|
||||||
|
for _, envkey := range envkeys {
|
||||||
|
if val, ok := v.getEnv(envkey); ok {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if nested && v.isPathShadowedInFlatMap(path, v.env) != "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config file next
|
||||||
|
val = v.searchIndexableWithPathPrefixes(v.config, path)
|
||||||
|
if val != nil {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
if nested && v.isPathShadowedInDeepMap(path, v.config) != "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// K/V store next
|
||||||
|
val = v.searchMap(v.kvstore, path)
|
||||||
|
if val != nil {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
if nested && v.isPathShadowedInDeepMap(path, v.kvstore) != "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default next
|
||||||
|
val = v.searchMap(v.defaults, path)
|
||||||
|
if val != nil {
|
||||||
|
return val
|
||||||
|
}
|
||||||
|
if nested && v.isPathShadowedInDeepMap(path, v.defaults) != "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if flagDefault {
|
||||||
|
// last chance: if no value is found and a flag does exist for the key,
|
||||||
|
// get the flag's default value even if the flag's value has not been set.
|
||||||
|
if flag, exists := v.pflags[lcaseKey]; exists {
|
||||||
|
switch flag.ValueType() {
|
||||||
|
case "int", "int8", "int16", "int32", "int64":
|
||||||
|
return cast.ToInt(flag.ValueString())
|
||||||
|
case "bool":
|
||||||
|
return cast.ToBool(flag.ValueString())
|
||||||
|
case "stringSlice", "stringArray":
|
||||||
|
s := strings.TrimPrefix(flag.ValueString(), "[")
|
||||||
|
s = strings.TrimSuffix(s, "]")
|
||||||
|
res, _ := readAsCSV(s)
|
||||||
|
return res
|
||||||
|
case "intSlice":
|
||||||
|
s := strings.TrimPrefix(flag.ValueString(), "[")
|
||||||
|
s = strings.TrimSuffix(s, "]")
|
||||||
|
res, _ := readAsCSV(s)
|
||||||
|
return cast.ToIntSlice(res)
|
||||||
|
case "stringToString":
|
||||||
|
return stringToStringConv(flag.ValueString())
|
||||||
|
case "stringToInt":
|
||||||
|
return stringToIntConv(flag.ValueString())
|
||||||
|
case "durationSlice":
|
||||||
|
s := strings.TrimPrefix(flag.ValueString(), "[")
|
||||||
|
s = strings.TrimSuffix(s, "]")
|
||||||
|
slice := strings.Split(s, ",")
|
||||||
|
return cast.ToDurationSlice(slice)
|
||||||
|
default:
|
||||||
|
return flag.ValueString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// last item, no need to check shadowing
|
||||||
|
|
||||||
|
if !v.aliasesFirstly {
|
||||||
|
// if the requested key is an alias, then return the proper key
|
||||||
|
lastKey = lcaseKey
|
||||||
|
lcaseKey = v.realKey(lcaseKey)
|
||||||
|
path = strings.Split(lcaseKey, v.keyDelim)
|
||||||
|
nested = len(path) > 1
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -1571,7 +1607,9 @@ func (v *Viper) realKey(key string) string {
|
||||||
newkey, exists := v.aliases[key]
|
newkey, exists := v.aliases[key]
|
||||||
if exists {
|
if exists {
|
||||||
v.logger.Debug("key is an alias", "alias", key, "to", newkey)
|
v.logger.Debug("key is an alias", "alias", key, "to", newkey)
|
||||||
|
if v.aliasesStepByStep {
|
||||||
|
return newkey
|
||||||
|
}
|
||||||
return v.realKey(newkey)
|
return v.realKey(newkey)
|
||||||
}
|
}
|
||||||
return key
|
return key
|
||||||
|
|
Loading…
Reference in a new issue