mirror of
https://github.com/spf13/viper.git
synced 2024-04-21 12:31:38 +00:00
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab3a50c0ce |
@@ -26,7 +26,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: "1.21"
|
||||
|
||||
- name: Build
|
||||
run: go build .
|
||||
@@ -44,8 +44,8 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest, macos-latest, windows-latest]
|
||||
go: ['1.19', '1.20', '1.21']
|
||||
tags: ['', 'finder']
|
||||
go: ["1.19", "1.20", "1.21"]
|
||||
tags: ["", "finder", "viper_bind_struct"]
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
@@ -75,7 +75,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: "1.21"
|
||||
|
||||
- name: Lint
|
||||
uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
//go:build viper_bind_struct
|
||||
|
||||
package features
|
||||
|
||||
const BindStruct = true
|
||||
@@ -0,0 +1,5 @@
|
||||
//go:build !viper_bind_struct
|
||||
|
||||
package features
|
||||
|
||||
const BindStruct = false
|
||||
@@ -48,6 +48,7 @@ import (
|
||||
"github.com/spf13/viper/internal/encoding/json"
|
||||
"github.com/spf13/viper/internal/encoding/toml"
|
||||
"github.com/spf13/viper/internal/encoding/yaml"
|
||||
"github.com/spf13/viper/internal/features"
|
||||
)
|
||||
|
||||
// ConfigMarshalError happens when failing to marshal the configuration.
|
||||
@@ -1114,26 +1115,25 @@ func Unmarshal(rawVal any, opts ...DecoderConfigOption) error {
|
||||
}
|
||||
|
||||
func (v *Viper) Unmarshal(rawVal any, opts ...DecoderConfigOption) error {
|
||||
// TODO: make this optional?
|
||||
structKeys, err := v.decodeStructKeys(rawVal, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
keys := v.AllKeys()
|
||||
|
||||
if features.BindStruct {
|
||||
// TODO: make this optional?
|
||||
structKeys, err := v.decodeStructKeys(rawVal, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
keys = append(keys, structKeys...)
|
||||
}
|
||||
|
||||
// TODO: struct keys should be enough?
|
||||
return decode(v.getSettings(append(v.AllKeys(), structKeys...)), defaultDecoderConfig(rawVal, opts...))
|
||||
return decode(v.getSettings(keys), defaultDecoderConfig(rawVal, opts...))
|
||||
}
|
||||
|
||||
func (v *Viper) decodeStructKeys(input any, opts ...DecoderConfigOption) ([]string, error) {
|
||||
var structKeyMap map[string]any
|
||||
|
||||
rv := reflect.ValueOf(input)
|
||||
for rv.Kind() == reflect.Ptr {
|
||||
rv = reflect.Indirect(rv)
|
||||
}
|
||||
|
||||
input = rv.Interface()
|
||||
|
||||
err := decode(input, defaultDecoderConfig(&structKeyMap, opts...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1186,14 +1186,20 @@ func (v *Viper) UnmarshalExact(rawVal any, opts ...DecoderConfigOption) error {
|
||||
config := defaultDecoderConfig(rawVal, opts...)
|
||||
config.ErrorUnused = true
|
||||
|
||||
// TODO: make this optional?
|
||||
structKeys, err := v.decodeStructKeys(rawVal, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
keys := v.AllKeys()
|
||||
|
||||
if features.BindStruct {
|
||||
// TODO: make this optional?
|
||||
structKeys, err := v.decodeStructKeys(rawVal, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
keys = append(keys, structKeys...)
|
||||
}
|
||||
|
||||
// TODO: struct keys should be enough?
|
||||
return decode(v.getSettings(append(v.AllKeys(), structKeys...)), config)
|
||||
return decode(v.getSettings(keys), config)
|
||||
}
|
||||
|
||||
// BindPFlags binds a full flag set to the configuration, using each flag's long
|
||||
|
||||
+5
-42
@@ -28,6 +28,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/spf13/viper/internal/features"
|
||||
"github.com/spf13/viper/internal/testutil"
|
||||
)
|
||||
|
||||
@@ -956,6 +957,10 @@ func TestUnmarshalWithDecoderOptions(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestUnmarshalWithAutomaticEnv(t *testing.T) {
|
||||
if !features.BindStruct {
|
||||
t.Skip("binding struct is not enabled")
|
||||
}
|
||||
|
||||
t.Setenv("PORT", "1313")
|
||||
t.Setenv("NAME", "Steve")
|
||||
t.Setenv("DURATION", "1s1ms")
|
||||
@@ -1080,48 +1085,6 @@ func TestUnmarshalWithAutomaticEnv(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestUnmarshalIndirection(t *testing.T) {
|
||||
v := New()
|
||||
|
||||
v.Set("foo", "bar")
|
||||
|
||||
type config struct {
|
||||
Foo string
|
||||
}
|
||||
|
||||
var C config
|
||||
|
||||
CC := &C
|
||||
CCC := &CC
|
||||
|
||||
err := v.Unmarshal(&CCC)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, config{"bar"}, C)
|
||||
}
|
||||
|
||||
func TestUnmarshalInterface(t *testing.T) {
|
||||
v := New()
|
||||
|
||||
v.Set("foo", "bar")
|
||||
|
||||
type someInterface interface {
|
||||
Foo() string
|
||||
}
|
||||
|
||||
type config struct {
|
||||
Foo string
|
||||
Fooer someInterface
|
||||
}
|
||||
|
||||
var C config
|
||||
|
||||
err := v.Unmarshal(&C)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, config{Foo: "bar"}, C)
|
||||
}
|
||||
|
||||
func TestBindPFlags(t *testing.T) {
|
||||
v := New() // create independent Viper object
|
||||
flagSet := pflag.NewFlagSet("test", pflag.ContinueOnError)
|
||||
|
||||
Reference in New Issue
Block a user