Compare commits

...
Author SHA1 Message Date
Mark Sagi-Kazar 80f981797a fix: add back weak string slice hook
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2023-12-19 22:35:12 +01:00
Mark Sagi-Kazar 6ce751eafe chore: update mapstructure
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2023-12-19 22:15:13 +01:00
Mark Sagi-KazarandMárk Sági-Kazár 473a3dfc7f fix!: hide struct binding behind a feature flag
Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
2023-12-18 19:36:22 +01:00
dependabot[bot]andMárk Sági-Kazár 0b0a1104ba build(deps): bump github.com/pelletier/go-toml/v2 from 2.1.0 to 2.1.1
Bumps [github.com/pelletier/go-toml/v2](https://github.com/pelletier/go-toml) from 2.1.0 to 2.1.1.
- [Release notes](https://github.com/pelletier/go-toml/releases)
- [Changelog](https://github.com/pelletier/go-toml/blob/v2/.goreleaser.yaml)
- [Commits](https://github.com/pelletier/go-toml/compare/v2.1.0...v2.1.1)

---
updated-dependencies:
- dependency-name: github.com/pelletier/go-toml/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-15 14:09:38 +01:00
dependabot[bot]andMárk Sági-Kazár fcda1149d6 build(deps): bump github/codeql-action from 2.22.9 to 3.22.11
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.22.9 to 3.22.11.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/c0d1daa7f7e14667747d73a7dbbe8c074bc8bfe2...b374143c1149a9115d881581d29b8390bbcbb59c)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-15 13:41:45 +01:00
dependabot[bot]andMárk Sági-Kazár 9154b900c3 build(deps): bump actions/setup-go from 4.1.0 to 5.0.0
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 4.1.0 to 5.0.0.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/93397bea11091df50f3d7e59dc26a7711a8bcfbe...0c52d547c9bc32b1aa3301fd7a9cb496313a4491)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-08 14:48:22 +01:00
dependabot[bot]andMárk Sági-Kazár 08e4a00949 build(deps): bump github/codeql-action from 2.22.8 to 2.22.9
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2.22.8 to 2.22.9.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/407ffafae6a767df3e0230c3df91b6443ae8df75...c0d1daa7f7e14667747d73a7dbbe8c074bc8bfe2)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-08 14:48:15 +01:00
Filip KrakowskiandMárk Sági-Kazár fb6eb1e8e9 fix: merge missing struct keys inside UnmarshalExact 2023-12-08 14:44:05 +01:00
9 changed files with 111 additions and 24 deletions
+7 -7
View File
@@ -24,9 +24,9 @@ jobs:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Set up Go - name: Set up Go
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with: with:
go-version: '1.21' go-version: "1.21"
- name: Build - name: Build
run: go build . run: go build .
@@ -44,15 +44,15 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
os: [ubuntu-latest, macos-latest, windows-latest] os: [ubuntu-latest, macos-latest, windows-latest]
go: ['1.19', '1.20', '1.21'] go: ["1.19", "1.20", "1.21"]
tags: ['', 'finder'] tags: ["", "finder", "viper_bind_struct"]
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Set up Go - name: Set up Go
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with: with:
go-version: ${{ matrix.go }} go-version: ${{ matrix.go }}
@@ -73,9 +73,9 @@ jobs:
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Set up Go - name: Set up Go
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0 uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with: with:
go-version: '1.21' go-version: "1.21"
- name: Lint - name: Lint
uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0 uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0
+3 -3
View File
@@ -43,7 +43,7 @@ jobs:
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@407ffafae6a767df3e0230c3df91b6443ae8df75 # v2.22.8 uses: github/codeql-action/init@b374143c1149a9115d881581d29b8390bbcbb59c # v3.22.11
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@407ffafae6a767df3e0230c3df91b6443ae8df75 # v2.22.8 uses: github/codeql-action/autobuild@b374143c1149a9115d881581d29b8390bbcbb59c # v3.22.11
# ️ 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@407ffafae6a767df3e0230c3df91b6443ae8df75 # v2.22.8 uses: github/codeql-action/analyze@b374143c1149a9115d881581d29b8390bbcbb59c # v3.22.11
+1 -1
View File
@@ -802,7 +802,7 @@ if err != nil {
} }
``` ```
Viper uses [github.com/mitchellh/mapstructure](https://github.com/mitchellh/mapstructure) under the hood for unmarshaling values which uses `mapstructure` tags by default. Viper uses [github.com/go-viper/mapstructure](https://github.com/go-viper/mapstructure) under the hood for unmarshaling values which uses `mapstructure` tags by default.
### Decoding custom formats ### Decoding custom formats
+3 -2
View File
@@ -4,10 +4,10 @@ go 1.18
require ( require (
github.com/fsnotify/fsnotify v1.7.0 github.com/fsnotify/fsnotify v1.7.0
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1
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/pelletier/go-toml/v2 v2.1.1
github.com/pelletier/go-toml/v2 v2.1.0
github.com/sagikazarmark/crypt v0.17.0 github.com/sagikazarmark/crypt v0.17.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
@@ -49,6 +49,7 @@ require (
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-isatty v0.0.17 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/nats-io/nats.go v1.31.0 // indirect github.com/nats-io/nats.go v1.31.0 // indirect
+4 -2
View File
@@ -58,6 +58,8 @@ github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1 h1:TQcrn6Wq+sKGkpyPvppOz99zsMBaUOKXq6HSv655U1c=
github.com/go-viper/mapstructure/v2 v2.0.0-alpha.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
@@ -197,8 +199,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.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
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=
+5
View File
@@ -0,0 +1,5 @@
//go:build viper_bind_struct
package features
const BindStruct = true
+5
View File
@@ -0,0 +1,5 @@
//go:build !viper_bind_struct
package features
const BindStruct = false
+51 -8
View File
@@ -34,7 +34,7 @@ import (
"time" "time"
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
"github.com/mitchellh/mapstructure" "github.com/go-viper/mapstructure/v2"
slog "github.com/sagikazarmark/slog-shim" slog "github.com/sagikazarmark/slog-shim"
"github.com/spf13/afero" "github.com/spf13/afero"
"github.com/spf13/cast" "github.com/spf13/cast"
@@ -48,6 +48,7 @@ import (
"github.com/spf13/viper/internal/encoding/json" "github.com/spf13/viper/internal/encoding/json"
"github.com/spf13/viper/internal/encoding/toml" "github.com/spf13/viper/internal/encoding/toml"
"github.com/spf13/viper/internal/encoding/yaml" "github.com/spf13/viper/internal/encoding/yaml"
"github.com/spf13/viper/internal/features"
) )
// ConfigMarshalError happens when failing to marshal the configuration. // ConfigMarshalError happens when failing to marshal the configuration.
@@ -1114,14 +1115,20 @@ func Unmarshal(rawVal any, opts ...DecoderConfigOption) error {
} }
func (v *Viper) Unmarshal(rawVal any, opts ...DecoderConfigOption) error { func (v *Viper) Unmarshal(rawVal any, opts ...DecoderConfigOption) error {
// TODO: make this optional? keys := v.AllKeys()
structKeys, err := v.decodeStructKeys(rawVal, opts...)
if err != nil { if features.BindStruct {
return err // 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? // 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) { func (v *Viper) decodeStructKeys(input any, opts ...DecoderConfigOption) ([]string, error) {
@@ -1151,7 +1158,8 @@ func defaultDecoderConfig(output any, opts ...DecoderConfigOption) *mapstructure
WeaklyTypedInput: true, WeaklyTypedInput: true,
DecodeHook: mapstructure.ComposeDecodeHookFunc( DecodeHook: mapstructure.ComposeDecodeHookFunc(
mapstructure.StringToTimeDurationHookFunc(), mapstructure.StringToTimeDurationHookFunc(),
mapstructure.StringToSliceHookFunc(","), // mapstructure.StringToSliceHookFunc(","),
stringToWeakSliceHookFunc(","),
), ),
} }
for _, opt := range opts { for _, opt := range opts {
@@ -1160,6 +1168,28 @@ func defaultDecoderConfig(output any, opts ...DecoderConfigOption) *mapstructure
return c return c
} }
// As of mapstructure v2.0.0 StringToSliceHookFunc checks if the return type is a string slice.
// This function removes that check.
// TODO: implement a function that checks if the value can be converted to the return type and use it instead.
func stringToWeakSliceHookFunc(sep string) mapstructure.DecodeHookFunc {
return func(
f reflect.Type,
t reflect.Type,
data interface{},
) (interface{}, error) {
if f.Kind() != reflect.String || t.Kind() != reflect.Slice {
return data, nil
}
raw := data.(string)
if raw == "" {
return []string{}, nil
}
return strings.Split(raw, sep), nil
}
}
// decode is a wrapper around mapstructure.Decode that mimics the WeakDecode functionality. // decode is a wrapper around mapstructure.Decode that mimics the WeakDecode functionality.
func decode(input any, config *mapstructure.DecoderConfig) error { func decode(input any, config *mapstructure.DecoderConfig) error {
decoder, err := mapstructure.NewDecoder(config) decoder, err := mapstructure.NewDecoder(config)
@@ -1179,7 +1209,20 @@ func (v *Viper) UnmarshalExact(rawVal any, opts ...DecoderConfigOption) error {
config := defaultDecoderConfig(rawVal, opts...) config := defaultDecoderConfig(rawVal, opts...)
config.ErrorUnused = true config.ErrorUnused = true
return decode(v.AllSettings(), config) 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(keys), config)
} }
// 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
+32 -1
View File
@@ -21,13 +21,14 @@ import (
"time" "time"
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
"github.com/mitchellh/mapstructure" "github.com/go-viper/mapstructure/v2"
"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"
"github.com/spf13/viper/internal/features"
"github.com/spf13/viper/internal/testutil" "github.com/spf13/viper/internal/testutil"
) )
@@ -956,6 +957,10 @@ func TestUnmarshalWithDecoderOptions(t *testing.T) {
} }
func TestUnmarshalWithAutomaticEnv(t *testing.T) { func TestUnmarshalWithAutomaticEnv(t *testing.T) {
if !features.BindStruct {
t.Skip("binding struct is not enabled")
}
t.Setenv("PORT", "1313") t.Setenv("PORT", "1313")
t.Setenv("NAME", "Steve") t.Setenv("NAME", "Steve")
t.Setenv("DURATION", "1s1ms") t.Setenv("DURATION", "1s1ms")
@@ -1052,6 +1057,32 @@ func TestUnmarshalWithAutomaticEnv(t *testing.T) {
assert.Error(t, err, "expected viper.Unmarshal to return error due to unset field 'FLAG'") assert.Error(t, err, "expected viper.Unmarshal to return error due to unset field 'FLAG'")
}) })
t.Run("Exact", func(t *testing.T) {
var config Configuration
v.Set("port", 1234)
if err := v.UnmarshalExact(&config); err != nil {
t.Fatalf("unable to decode into struct, %v", err)
}
assert.Equal(
t,
Configuration{
Name: "Steve",
Port: 1234,
Duration: time.Second + time.Millisecond,
Modes: []int{1, 2, 3},
Authentication: AuthConfig{
Secret: "42",
},
Storage: StorageConfig{
Size: 4096,
},
},
config,
)
})
} }
func TestBindPFlags(t *testing.T) { func TestBindPFlags(t *testing.T) {