Merge branch 'master' into bugfix/map-interface-cast

This commit is contained in:
linuxsong 2023-10-07 11:38:38 +08:00 committed by GitHub
commit d5282b8564
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
49 changed files with 642 additions and 914 deletions

View file

@ -11,7 +11,7 @@ jobs:
steps:
- name: Check minimum labels
uses: mheap/github-action-required-labels@v5
uses: mheap/github-action-required-labels@4e9ef4ce8c697cf55716ecbf7f13a3d9e0b6ac6a # v5.1.0
with:
mode: minimum
count: 1

View file

@ -21,12 +21,12 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- name: Set up Go
uses: actions/setup-go@v4
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
with:
go-version: '1.20'
go-version: '1.21'
- name: Build
run: go build .
@ -44,23 +44,24 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
go: ['1.18', '1.19', '1.20']
go: ['1.19', '1.20', '1.21']
tags: ['', 'finder']
steps:
- name: Checkout repository
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- name: Set up Go
uses: actions/setup-go@v4
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
with:
go-version: ${{ matrix.go }}
- name: Test
run: go test -race -v ./...
run: go test -race -v -tags '${{ matrix.tags }}' ./...
if: runner.os != 'Windows'
- name: Test (without race detector)
run: go test -v ./...
run: go test -v -tags '${{ matrix.tags }}' ./...
if: runner.os == 'Windows'
lint:
@ -69,17 +70,17 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- name: Set up Go
uses: actions/setup-go@v4
uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe # v4.1.0
with:
go-version: '1.20'
go-version: '1.21'
- name: Lint
uses: golangci/golangci-lint-action@v3
uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0
with:
version: v1.53.3
version: v1.54.2
dev:
name: Developer environment
@ -87,10 +88,10 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- name: Set up Nix
uses: cachix/install-nix-action@6ed004b9ccb68dbc28e7c85bee15fa93dbd214ac # v22
uses: cachix/install-nix-action@6a9a9e84a173d90b3ffb42c5ddaf9ea033fad011 # v23
with:
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
@ -108,7 +109,7 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
- name: Dependency Review
uses: actions/dependency-review-action@1360a344ccb0ab6e9475edef90ad2f46bf8003b1 # v3.0.6
uses: actions/dependency-review-action@6c5ccdad469c9f8a2996bfecaec55a631a347034 # v3.1.0

View file

@ -39,11 +39,11 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9
with:
languages: ${{ matrix.language }}
# 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).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
uses: github/codeql-action/autobuild@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
@ -68,5 +68,5 @@ jobs:
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@ddccb873888234080b77e9bc2d4764d5ccaaccf9 # v2.21.9

View file

@ -6,7 +6,7 @@ jobs:
comment:
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v6
- uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |

View file

@ -6,7 +6,7 @@ jobs:
comment:
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@v6
- uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1
with:
github-token: ${{secrets.GITHUB_TOKEN}}
script: |

View file

@ -66,9 +66,9 @@ bin/golangci-lint:
@mkdir -p bin
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | bash -s -- v${GOLANGCI_VERSION}
.PHONY: fmt
.PHONY: yamllint
yamllint:
pip install --user yamllint
pip3 install --user yamllint
# Add custom targets here
-include custom.mk

View file

@ -11,7 +11,7 @@
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/spf13/viper/ci.yaml?branch=master&style=flat-square)](https://github.com/spf13/viper/actions?query=workflow%3ACI)
[![Join the chat at https://gitter.im/spf13/viper](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/spf13/viper?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Go Report Card](https://goreportcard.com/badge/github.com/spf13/viper?style=flat-square)](https://goreportcard.com/report/github.com/spf13/viper)
![Go Version](https://img.shields.io/badge/go%20version-%3E=1.18-61CFDD.svg?style=flat-square)
![Go Version](https://img.shields.io/badge/go%20version-%3E=1.19-61CFDD.svg?style=flat-square)
[![PkgGoDev](https://pkg.go.dev/badge/mod/github.com/spf13/viper)](https://pkg.go.dev/mod/github.com/spf13/viper)
**Go configuration with fangs!**
@ -30,6 +30,7 @@ Many Go projects are built using Viper including:
* [Meshery](https://github.com/meshery/meshery)
* [Bearer](https://github.com/bearer/bearer)
* [Coder](https://github.com/coder/coder)
* [Vitess](https://vitess.io/)
## Install
@ -140,7 +141,7 @@ if err := viper.ReadInConfig(); err != nil {
// Config file found and successfully parsed
```
*NOTE [since 1.6]:* You can also have a file without an extension and specify the format programmaticaly. For those configuration files that lie in the home of the user without any extension like `.bashrc`
*NOTE [since 1.6]:* You can also have a file without an extension and specify the format programmatically. For those configuration files that lie in the home of the user without any extension like `.bashrc`
### Writing Config Files
@ -221,6 +222,7 @@ These could be from a command line flag, or from your own application logic.
```go
viper.Set("Verbose", true)
viper.Set("LogFile", LogFile)
viper.Set("host.port", 5899) // set subset
```
### Registering and Using Aliases
@ -487,6 +489,15 @@ err := viper.ReadRemoteConfig()
Of course, you're allowed to use `SecureRemoteProvider` also
#### NATS
```go
viper.AddRemoteProvider("nats", "nats://127.0.0.1:4222", "myapp.config")
viper.SetConfigType("json")
err := viper.ReadRemoteConfig()
```
### Remote Key/Value Store Example - Encrypted
```go
@ -534,19 +545,19 @@ go func(){
In Viper, there are a few ways to get a value depending on the values type.
The following functions and methods exist:
* `Get(key string) : interface{}`
* `Get(key string) : any`
* `GetBool(key string) : bool`
* `GetFloat64(key string) : float64`
* `GetInt(key string) : int`
* `GetIntSlice(key string) : []int`
* `GetString(key string) : string`
* `GetStringMap(key string) : map[string]interface{}`
* `GetStringMap(key string) : map[string]any`
* `GetStringMapString(key string) : map[string]string`
* `GetStringSlice(key string) : []string`
* `GetTime(key string) : time.Time`
* `GetDuration(key string) : time.Duration`
* `IsSet(key string) : bool`
* `AllSettings() : map[string]interface{}`
* `AllSettings() : map[string]any`
One important thing to recognize is that each Get function will return a zero
value if its not found. To check if a given key exists, the `IsSet()` method
@ -709,8 +720,8 @@ etc.
There are two methods to do this:
* `Unmarshal(rawVal interface{}) : error`
* `UnmarshalKey(key string, rawVal interface{}) : error`
* `Unmarshal(rawVal any) : error`
* `UnmarshalKey(key string, rawVal any) : error`
Example:
@ -735,9 +746,9 @@ you have to change the delimiter:
```go
v := viper.NewWithOptions(viper.KeyDelimiter("::"))
v.SetDefault("chart::values", map[string]interface{}{
"ingress": map[string]interface{}{
"annotations": map[string]interface{}{
v.SetDefault("chart::values", map[string]any{
"ingress": map[string]any{
"annotations": map[string]any{
"traefik.frontend.rule.type": "PathPrefix",
"traefik.ingress.kubernetes.io/ssl-redirect": "true",
},
@ -746,7 +757,7 @@ v.SetDefault("chart::values", map[string]interface{}{
type config struct {
Chart struct{
Values map[string]interface{}
Values map[string]any
}
}

View file

@ -1,11 +0,0 @@
//go:build viper_logger
// +build viper_logger
package viper
// WithLogger sets a custom logger.
func WithLogger(l Logger) Option {
return optionFunc(func(v *Viper) {
v.logger = l
})
}

View file

@ -1,5 +1,4 @@
//go:build !go1.16 || !finder
// +build !go1.16 !finder
//go:build !finder
package viper

38
file_finder.go Normal file
View file

@ -0,0 +1,38 @@
//go:build finder
package viper
import (
"fmt"
"github.com/sagikazarmark/locafero"
)
// Search all configPaths for any config file.
// Returns the first path that exists (and is a config file).
func (v *Viper) findConfigFile() (string, error) {
var names []string
if v.configType != "" {
names = locafero.NameWithOptionalExtensions(v.configName, SupportedExts...)
} else {
names = locafero.NameWithExtensions(v.configName, SupportedExts...)
}
finder := locafero.Finder{
Paths: v.configPaths,
Names: names,
Type: locafero.FileTypeFile,
}
results, err := finder.Find(v.fs)
if err != nil {
return "", err
}
if len(results) == 0 {
return "", ConfigFileNotFoundError{v.configName, fmt.Sprintf("%s", v.configPaths)}
}
return results[0], nil
}

View file

@ -30,7 +30,7 @@ func (p pflagValueSet) VisitAll(fn func(flag FlagValue)) {
})
}
// pflagValue is a wrapper aroung *pflag.flag
// pflagValue is a wrapper around *pflag.flag
// that implements FlagValue
type pflagValue struct {
flag *pflag.Flag

View file

@ -39,7 +39,7 @@ func TestBindFlagValueSet(t *testing.T) {
})
for name, expected := range mutatedTestValues {
assert.Equal(t, Get(name), expected)
assert.Equal(t, expected, Get(name))
}
}

65
fs.go
View file

@ -1,65 +0,0 @@
//go:build go1.16 && finder
// +build go1.16,finder
package viper
import (
"errors"
"io/fs"
"path"
)
type finder struct {
paths []string
fileNames []string
extensions []string
withoutExtension bool
}
func (f finder) Find(fsys fs.FS) (string, error) {
for _, searchPath := range f.paths {
for _, fileName := range f.fileNames {
for _, extension := range f.extensions {
filePath := path.Join(searchPath, fileName+"."+extension)
ok, err := fileExists(fsys, filePath)
if err != nil {
return "", err
}
if ok {
return filePath, nil
}
}
if f.withoutExtension {
filePath := path.Join(searchPath, fileName)
ok, err := fileExists(fsys, filePath)
if err != nil {
return "", err
}
if ok {
return filePath, nil
}
}
}
}
return "", nil
}
func fileExists(fsys fs.FS, filePath string) (bool, error) {
fileInfo, err := fs.Stat(fsys, filePath)
if err == nil {
return !fileInfo.IsDir(), nil
}
if errors.Is(err, fs.ErrNotExist) {
return false, nil
}
return false, err
}

View file

@ -1,100 +0,0 @@
//go:build go1.16 && finder
// +build go1.16,finder
package viper
import (
"io/fs"
"testing"
"testing/fstest"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestFinder(t *testing.T) {
t.Parallel()
fsys := fstest.MapFS{
"home/user/.config": &fstest.MapFile{},
"home/user/config.json": &fstest.MapFile{},
"home/user/config.yaml": &fstest.MapFile{},
"home/user/data.json": &fstest.MapFile{},
"etc/config/.config": &fstest.MapFile{},
"etc/config/a_random_file.txt": &fstest.MapFile{},
"etc/config/config.json": &fstest.MapFile{},
"etc/config/config.yaml": &fstest.MapFile{},
"etc/config/config.xml": &fstest.MapFile{},
}
testCases := []struct {
name string
fsys func() fs.FS
finder finder
result string
}{
{
name: "find file",
fsys: func() fs.FS { return fsys },
finder: finder{
paths: []string{"etc/config"},
fileNames: []string{"config"},
extensions: []string{"json"},
},
result: "etc/config/config.json",
},
{
name: "file not found",
fsys: func() fs.FS { return fsys },
finder: finder{
paths: []string{"var/config"},
fileNames: []string{"config"},
extensions: []string{"json"},
},
result: "",
},
{
name: "empty search params",
fsys: func() fs.FS { return fsys },
finder: finder{},
result: "",
},
{
name: "precedence",
fsys: func() fs.FS { return fsys },
finder: finder{
paths: []string{"var/config", "home/user", "etc/config"},
fileNames: []string{"aconfig", "config"},
extensions: []string{"zml", "xml", "json"},
},
result: "home/user/config.json",
},
{
name: "without extension",
fsys: func() fs.FS { return fsys },
finder: finder{
paths: []string{"var/config", "home/user", "etc/config"},
fileNames: []string{".config"},
extensions: []string{"zml", "xml", "json"},
withoutExtension: true,
},
result: "home/user/.config",
},
}
for _, testCase := range testCases {
testCase := testCase
t.Run(testCase.name, func(t *testing.T) {
t.Parallel()
fsys := testCase.fsys()
result, err := testCase.finder.Find(fsys)
require.NoError(t, err)
assert.Equal(t, testCase.result, result)
})
}
}

58
go.mod
View file

@ -7,24 +7,25 @@ require (
github.com/hashicorp/hcl v1.0.0
github.com/magiconair/properties v1.8.7
github.com/mitchellh/mapstructure v1.5.0
github.com/pelletier/go-toml/v2 v2.0.8
github.com/sagikazarmark/crypt v0.11.0
github.com/spf13/afero v1.9.5
github.com/pelletier/go-toml/v2 v2.1.0
github.com/sagikazarmark/crypt v0.15.0
github.com/sagikazarmark/locafero v0.3.0
github.com/sagikazarmark/slog-shim v0.1.0
github.com/spf13/afero v1.10.0
github.com/spf13/cast v1.5.1
github.com/spf13/jwalterweatherman v1.1.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.4
github.com/subosito/gotenv v1.4.2
github.com/subosito/gotenv v1.6.0
gopkg.in/ini.v1 v1.67.0
gopkg.in/yaml.v3 v3.0.1
)
require (
cloud.google.com/go v0.110.2 // indirect
cloud.google.com/go/compute v1.19.3 // indirect
cloud.google.com/go v0.110.7 // indirect
cloud.google.com/go/compute v1.23.0 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/firestore v1.11.0 // indirect
cloud.google.com/go/longrunning v0.5.0 // indirect
cloud.google.com/go/firestore v1.13.0 // indirect
cloud.google.com/go/longrunning v0.5.1 // indirect
github.com/armon/go-metrics v0.4.1 // indirect
github.com/coreos/go-semver v0.3.0 // indirect
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
@ -34,10 +35,10 @@ require (
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/s2a-go v0.1.4 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.2.5 // indirect
github.com/googleapis/gax-go/v2 v2.11.0 // indirect
github.com/hashicorp/consul/api v1.22.0 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.1 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/hashicorp/consul/api v1.25.1 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-hclog v1.5.0 // indirect
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
@ -45,35 +46,42 @@ require (
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/hashicorp/serf v0.10.1 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect
github.com/minio/highwayhash v1.0.2 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/nats-io/jwt/v2 v2.4.1 // indirect
github.com/nats-io/nats.go v1.30.2 // indirect
github.com/nats-io/nkeys v0.4.5 // indirect
github.com/nats-io/nuid v1.0.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
go.etcd.io/etcd/api/v3 v3.5.9 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.9 // indirect
go.etcd.io/etcd/client/v2 v2.305.9 // indirect
go.etcd.io/etcd/client/v3 v3.5.9 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/multierr v1.9.0 // indirect
go.uber.org/zap v1.21.0 // indirect
golang.org/x/crypto v0.10.0 // indirect
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect
golang.org/x/net v0.11.0 // indirect
golang.org/x/oauth2 v0.9.0 // indirect
golang.org/x/crypto v0.13.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/net v0.15.0 // indirect
golang.org/x/oauth2 v0.12.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.9.0 // indirect
golang.org/x/text v0.10.0 // indirect
golang.org/x/sys v0.12.0 // indirect
golang.org/x/text v0.13.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/api v0.129.0 // indirect
google.golang.org/api v0.143.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc // indirect
google.golang.org/grpc v1.56.1 // indirect
google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 // indirect
google.golang.org/grpc v1.58.2 // indirect
google.golang.org/protobuf v1.31.0 // indirect
)

148
go.sum
View file

@ -17,24 +17,24 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go v0.110.2 h1:sdFPBr6xG9/wkBbfhmUz/JmZC7X6LavQgcrVINrKiVA=
cloud.google.com/go v0.110.2/go.mod h1:k04UEeEtb6ZBRTv3dZz4CeJC3jKGxyhl0sAiVVquxiw=
cloud.google.com/go v0.110.7 h1:rJyC7nWRg2jWGZ4wSJ5nY65GTdYJkg0cd/uXb+ACI6o=
cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/compute v1.19.3 h1:DcTwsFgGev/wV5+q8o2fzgcHOaac+DKGC91ZlvpsQds=
cloud.google.com/go/compute v1.19.3/go.mod h1:qxvISKp/gYnXkSAD1ppcSOveRAmzxicEv/JlizULFrI=
cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY=
cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/firestore v1.11.0 h1:PPgtwcYUOXV2jFe1bV3nda3RCrOa8cvBjTOn2MQVfW8=
cloud.google.com/go/firestore v1.11.0/go.mod h1:b38dKhgzlmNNGTNZZwe7ZRFEuRab1Hay3/DBsIGKKy4=
cloud.google.com/go/longrunning v0.5.0 h1:DK8BH0+hS+DIvc9a2TPnteUievsTCH4ORMAASSb7JcQ=
cloud.google.com/go/longrunning v0.5.0/go.mod h1:0JNuqRShmscVAhIACGtskSAWtqtOoPkwP0YF1oVEchc=
cloud.google.com/go/firestore v1.13.0 h1:/3S4RssUV4GO/kvgJZB+tayjhOfyAHs+KcpJgRVu/Qk=
cloud.google.com/go/firestore v1.13.0/go.mod h1:QojqqOh8IntInDUSTAh0c8ZsPYAr68Ma8c5DWOy8xb8=
cloud.google.com/go/longrunning v0.5.1 h1:Fr7TXftcqTudoyRJa113hyaqlGdiBQkp0Gq7tErFDWI=
cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
@ -53,7 +53,6 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-metrics v0.4.1 h1:hR91U9KYmb6bLBYLQjyM+3j+rcd/UhE+G78SFnF8gJA=
@ -77,10 +76,6 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
@ -94,7 +89,6 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
@ -104,7 +98,6 @@ github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8Wlg
github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@ -145,7 +138,6 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
@ -179,20 +171,19 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/s2a-go v0.1.4 h1:1kZ/sQM3srePvKs3tXAvQzo66XfcReoqFpIpIccE7Oc=
github.com/google/s2a-go v0.1.4/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A=
github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/enterprise-certificate-proxy v0.2.5 h1:UR4rDjcgpgEnqpIEvkiqTYKBCKLNmlge2eVjoZfySzM=
github.com/googleapis/enterprise-certificate-proxy v0.2.5/go.mod h1:RxW0N9901Cko1VOCW3SXCpWP+mlIEkk2tP7jnHy9a3w=
github.com/googleapis/enterprise-certificate-proxy v0.3.1 h1:SBWmZhjUDRorQxrN0nwzf+AHBxnbFjViHQS4P0yVpmQ=
github.com/googleapis/enterprise-certificate-proxy v0.3.1/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.11.0 h1:9V9PWXEsWnPpQhu/PeQIkS4eGzMlTLGgt80cUUI8Ki4=
github.com/googleapis/gax-go/v2 v2.11.0/go.mod h1:DxmR61SGKkGLa2xigwuZIQpkCI2S5iydzRfb3peWZJI=
github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas=
github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/consul/api v1.22.0 h1:ydEvDooB/A0c/xpsBd8GSt7P2/zYPBui4KrNip0xGjE=
github.com/hashicorp/consul/api v1.22.0/go.mod h1:zHpYgZ7TeYqS6zaszjwSt128OwESRpnhU9aGa6ue3Eg=
github.com/hashicorp/consul/sdk v0.14.0 h1:Hly+BMNMssVzoWddbBnBFi3W+Fzytvm0haSkihhj3GU=
github.com/hashicorp/consul/api v1.25.1 h1:CqrdhYzc8XZuPnhIYZWH45toM0LB9ZeYr/gvpLVI3PE=
github.com/hashicorp/consul/api v1.25.1/go.mod h1:iiLVwR/htV7mas/sy0O+XSuEnrdBUUydemjxcUrAt4g=
github.com/hashicorp/consul/sdk v0.14.1 h1:ZiwE2bKb+zro68sWzZ1SgHF3kRMBZ94TwOCFRF4ylPs=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
@ -241,6 +232,8 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
@ -270,6 +263,8 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.41 h1:WMszZWJG0XmzbK9FEmzH2TVcqYzFesusSIB41b8KHxY=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
@ -284,11 +279,20 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nats-io/jwt/v2 v2.4.1 h1:Y35W1dgbbz2SQUYDPCaclXcuqleVmpbRa7646Jf2EX4=
github.com/nats-io/jwt/v2 v2.4.1/go.mod h1:24BeQtRwxRV8ruvC4CojXlx/WQ/VjuwlYiH+vu/+ibI=
github.com/nats-io/nats-server/v2 v2.9.20 h1:bt1dW6xsL1hWWwv7Hovm+EJt5L6iplyqlgEFkoEUk0k=
github.com/nats-io/nats.go v1.30.2 h1:aloM0TGpPorZKQhbAkdCzYDj+ZmsJDyeo3Gkbr72NuY=
github.com/nats-io/nats.go v1.30.2/go.mod h1:dcfhUgmQNN4GJEfIb2f9R7Fow+gzBF4emzDHrVBd5qM=
github.com/nats-io/nkeys v0.4.5 h1:Zdz2BUlFm4fJlierwvGK+yl20IAKUm7eV6AAZXEhkPk=
github.com/nats-io/nkeys v0.4.5/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64=
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
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/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
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.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@ -311,22 +315,25 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sagikazarmark/crypt v0.11.0 h1:pEFoux+lQBXsS9lGkGKMcQ0fp5W+6HsNfu28yK7bKVE=
github.com/sagikazarmark/crypt v0.11.0/go.mod h1:04Tna7sDiOkvj4Qs78hSG+5MArl9wwrhEL1NZmblMb0=
github.com/sagikazarmark/crypt v0.15.0 h1:TQJg76CemcIdJyC9/dmNjU9OUyIFHyvE50Tpq1t1nqY=
github.com/sagikazarmark/crypt v0.15.0/go.mod h1:5rwNNax6Mlk9sZ40AcyVtiEw24Z4J04cfSioF2COKmc=
github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ=
github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM=
github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY=
github.com/spf13/afero v1.10.0/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ=
github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA=
github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN48=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@ -343,18 +350,16 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.etcd.io/etcd/api/v3 v3.5.9 h1:4wSsluwyTbGGmyjJktOf3wFQoTBIURXHnq9n/G/JQHs=
go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k=
go.etcd.io/etcd/client/pkg/v3 v3.5.9 h1:oidDC4+YEuSIQbsR94rY9gur91UPL6DnxDCIYd2IGsE=
@ -371,15 +376,14 @@ go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8=
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@ -390,11 +394,9 @@ golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@ -405,8 +407,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@ -431,7 +433,6 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -470,9 +471,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-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@ -482,8 +482,8 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.9.0 h1:BPpt2kU7oMRq3kCHAA1tbSEshXRw1LpG2ztgDwrzuAs=
golang.org/x/oauth2 v0.9.0/go.mod h1:qYgFZaFiu6Wg24azG8bdV52QJXJGbZzIIsRCdVKzbLw=
golang.org/x/oauth2 v0.12.0 h1:smVPGxink+n1ZI5pkQa8y6fZT0RW0MgCO5bFpepy4B4=
golang.org/x/oauth2 v0.12.0/go.mod h1:A74bZ3aGXgCY0qaIC9Ahg6Lglin4AMAco8cIv9baba4=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -495,13 +495,13 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190130150945-aca44879d564/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -548,15 +548,12 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -565,9 +562,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -624,7 +620,6 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -650,8 +645,8 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
google.golang.org/api v0.129.0 h1:2XbdjjNfFPXQyufzQVwPf1RRnHH8Den2pfNE2jw7L8w=
google.golang.org/api v0.129.0/go.mod h1:dFjiXlanKwWE3612X97llhsoI36FAoIiRj3aTl5b/zE=
google.golang.org/api v0.143.0 h1:o8cekTkqhywkbZT6p1UHJPZ9+9uuCAJs/KYomxZB8fA=
google.golang.org/api v0.143.0/go.mod h1:FoX9DO9hT7DLNn97OuoZAGSDuNAXdJRuGK98rSUgurk=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@ -683,7 +678,6 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
@ -697,12 +691,12 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc h1:8DyZCyvI8mE1IdLy/60bS+52xfymkE72wv1asokgtao=
google.golang.org/genproto v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:xZnkP7mREFX5MORlOPEzLMr+90PPZQ2QWzrVTWfAq64=
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc h1:kVKPf/IiYSBWEWtkIn6wZXwWGCnLKcC8oWfZvXjsGnM=
google.golang.org/genproto/googleapis/api v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:vHYtlOoi6TsQ3Uk2yxR7NI5z8uoV+3pZtR4jmHIkRig=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc h1:XSJ8Vk1SWuNr8S18z1NZSziL0CPIXLCCMDOEFtHBOFc=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230530153820-e85fd2cbaebc/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb h1:XFBgcDwm7irdHTbz4Zk2h7Mh+eis4nfJEFQFYzJzuIA=
google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4=
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb h1:lK0oleSc7IQsUxO3U5TjL9DWlsxpEBemh+zpB7IqhWI=
google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 h1:N3bU/SQDCDyD6R528GJ/PwW9KjYcJA3dgyH+MovAkIM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@ -716,14 +710,11 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc v1.56.1 h1:z0dNfjIl0VpaZ9iSVjA6daGatAYwPGstTjt5vkRMFkQ=
google.golang.org/grpc v1.56.1/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I=
google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@ -748,7 +739,6 @@ gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View file

@ -5,9 +5,9 @@ import (
)
// Decoder decodes the contents of b into v.
// It's primarily used for decoding contents of a file into a map[string]interface{}.
// It's primarily used for decoding contents of a file into a map[string]any.
type Decoder interface {
Decode(b []byte, v map[string]interface{}) error
Decode(b []byte, v map[string]any) error
}
const (
@ -48,7 +48,7 @@ func (e *DecoderRegistry) RegisterDecoder(format string, enc Decoder) error {
}
// Decode calls the underlying Decoder based on the format.
func (e *DecoderRegistry) Decode(format string, b []byte, v map[string]interface{}) error {
func (e *DecoderRegistry) Decode(format string, b []byte, v map[string]any) error {
e.mu.RLock()
decoder, ok := e.decoders[format]
e.mu.RUnlock()

View file

@ -6,10 +6,10 @@ import (
)
type decoder struct {
v map[string]interface{}
v map[string]any
}
func (d decoder) Decode(_ []byte, v map[string]interface{}) error {
func (d decoder) Decode(_ []byte, v map[string]any) error {
for key, value := range d.v {
v[key] = value
}
@ -46,7 +46,7 @@ func TestDecoderRegistry_Decode(t *testing.T) {
t.Run("OK", func(t *testing.T) {
registry := NewDecoderRegistry()
decoder := decoder{
v: map[string]interface{}{
v: map[string]any{
"key": "value",
},
}
@ -56,7 +56,7 @@ func TestDecoderRegistry_Decode(t *testing.T) {
t.Fatal(err)
}
v := map[string]interface{}{}
v := map[string]any{}
err = registry.Decode("myformat", []byte("key: value"), v)
if err != nil {
@ -71,7 +71,7 @@ func TestDecoderRegistry_Decode(t *testing.T) {
t.Run("DecoderNotFound", func(t *testing.T) {
registry := NewDecoderRegistry()
v := map[string]interface{}{}
v := map[string]any{}
err := registry.Decode("myformat", nil, v)
if err != ErrDecoderNotFound {

View file

@ -15,8 +15,8 @@ const keyDelimiter = "_"
// (commonly called as dotenv format).
type Codec struct{}
func (Codec) Encode(v map[string]interface{}) ([]byte, error) {
flattened := map[string]interface{}{}
func (Codec) Encode(v map[string]any) ([]byte, error) {
flattened := map[string]any{}
flattened = flattenAndMergeMap(flattened, v, "", keyDelimiter)
@ -40,7 +40,7 @@ func (Codec) Encode(v map[string]interface{}) ([]byte, error) {
return buf.Bytes(), nil
}
func (Codec) Decode(b []byte, v map[string]interface{}) error {
func (Codec) Decode(b []byte, v map[string]any) error {
var buf bytes.Buffer
_, err := buf.Write(b)

View file

@ -15,7 +15,7 @@ const encoded = `KEY=value
`
// Viper's internal representation
var data = map[string]interface{}{
var data = map[string]any{
"KEY": "value",
}
@ -36,7 +36,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("OK", func(t *testing.T) {
codec := Codec{}
v := map[string]interface{}{}
v := map[string]any{}
err := codec.Decode([]byte(original), v)
if err != nil {
@ -51,7 +51,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("InvalidData", func(t *testing.T) {
codec := Codec{}
v := map[string]interface{}{}
v := map[string]any{}
err := codec.Decode([]byte(`invalid data`), v)
if err == nil {

View file

@ -7,27 +7,27 @@ import (
)
// flattenAndMergeMap recursively flattens the given map into a new map
// Code is based on the function with the same name in tha main package.
// Code is based on the function with the same name in the main package.
// TODO: move it to a common place
func flattenAndMergeMap(shadow map[string]interface{}, m map[string]interface{}, prefix string, delimiter string) map[string]interface{} {
func flattenAndMergeMap(shadow map[string]any, m map[string]any, prefix string, delimiter string) map[string]any {
if shadow != nil && prefix != "" && shadow[prefix] != nil {
// prefix is shadowed => nothing more to flatten
return shadow
}
if shadow == nil {
shadow = make(map[string]interface{})
shadow = make(map[string]any)
}
var m2 map[string]interface{}
var m2 map[string]any
if prefix != "" {
prefix += delimiter
}
for k, val := range m {
fullKey := prefix + k
switch val.(type) {
case map[string]interface{}:
m2 = val.(map[string]interface{})
case map[interface{}]interface{}:
switch val := val.(type) {
case map[string]any:
m2 = val
case map[any]any:
m2 = cast.ToStringMap(val)
default:
// immediate value

View file

@ -5,9 +5,9 @@ import (
)
// Encoder encodes the contents of v into a byte representation.
// It's primarily used for encoding a map[string]interface{} into a file format.
// It's primarily used for encoding a map[string]any into a file format.
type Encoder interface {
Encode(v map[string]interface{}) ([]byte, error)
Encode(v map[string]any) ([]byte, error)
}
const (
@ -47,7 +47,7 @@ func (e *EncoderRegistry) RegisterEncoder(format string, enc Encoder) error {
return nil
}
func (e *EncoderRegistry) Encode(format string, v map[string]interface{}) ([]byte, error) {
func (e *EncoderRegistry) Encode(format string, v map[string]any) ([]byte, error) {
e.mu.RLock()
encoder, ok := e.encoders[format]
e.mu.RUnlock()

View file

@ -8,7 +8,7 @@ type encoder struct {
b []byte
}
func (e encoder) Encode(_ map[string]interface{}) ([]byte, error) {
func (e encoder) Encode(_ map[string]any) ([]byte, error) {
return e.b, nil
}
@ -49,7 +49,7 @@ func TestEncoderRegistry_Decode(t *testing.T) {
t.Fatal(err)
}
b, err := registry.Encode("myformat", map[string]interface{}{"key": "value"})
b, err := registry.Encode("myformat", map[string]any{"key": "value"})
if err != nil {
t.Fatal(err)
}
@ -62,7 +62,7 @@ func TestEncoderRegistry_Decode(t *testing.T) {
t.Run("EncoderNotFound", func(t *testing.T) {
registry := NewEncoderRegistry()
_, err := registry.Encode("myformat", map[string]interface{}{"key": "value"})
_, err := registry.Encode("myformat", map[string]any{"key": "value"})
if err != ErrEncoderNotFound {
t.Fatalf("expected ErrEncoderNotFound, got: %v", err)
}

View file

@ -12,7 +12,7 @@ import (
// TODO: add printer config to the codec?
type Codec struct{}
func (Codec) Encode(v map[string]interface{}) ([]byte, error) {
func (Codec) Encode(v map[string]any) ([]byte, error) {
b, err := json.Marshal(v)
if err != nil {
return nil, err
@ -35,6 +35,6 @@ func (Codec) Encode(v map[string]interface{}) ([]byte, error) {
return buf.Bytes(), nil
}
func (Codec) Decode(b []byte, v map[string]interface{}) error {
func (Codec) Decode(b []byte, v map[string]any) error {
return hcl.Unmarshal(b, &v)
}

View file

@ -45,24 +45,24 @@ const encoded = `"key" = "value"
//
// in case of HCL it's slightly different from Viper's internal representation
// (eg. map is decoded into a list of maps)
var decoded = map[string]interface{}{
var decoded = map[string]any{
"key": "value",
"list": []interface{}{
"list": []any{
"item1",
"item2",
"item3",
},
"map": []map[string]interface{}{
"map": []map[string]any{
{
"key": "value",
},
},
"nested_map": []map[string]interface{}{
"nested_map": []map[string]any{
{
"map": []map[string]interface{}{
"map": []map[string]any{
{
"key": "value",
"list": []interface{}{
"list": []any{
"item1",
"item2",
"item3",
@ -74,20 +74,20 @@ var decoded = map[string]interface{}{
}
// Viper's internal representation
var data = map[string]interface{}{
var data = map[string]any{
"key": "value",
"list": []interface{}{
"list": []any{
"item1",
"item2",
"item3",
},
"map": map[string]interface{}{
"map": map[string]any{
"key": "value",
},
"nested_map": map[string]interface{}{
"map": map[string]interface{}{
"nested_map": map[string]any{
"map": map[string]any{
"key": "value",
"list": []interface{}{
"list": []any{
"item1",
"item2",
"item3",
@ -113,7 +113,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("OK", func(t *testing.T) {
codec := Codec{}
v := map[string]interface{}{}
v := map[string]any{}
err := codec.Decode([]byte(original), v)
if err != nil {
@ -128,7 +128,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("InvalidData", func(t *testing.T) {
codec := Codec{}
v := map[string]interface{}{}
v := map[string]any{}
err := codec.Decode([]byte(`invalid data`), v)
if err == nil {

View file

@ -19,11 +19,11 @@ type Codec struct {
LoadOptions LoadOptions
}
func (c Codec) Encode(v map[string]interface{}) ([]byte, error) {
func (c Codec) Encode(v map[string]any) ([]byte, error) {
cfg := ini.Empty()
ini.PrettyFormat = false
flattened := map[string]interface{}{}
flattened := map[string]any{}
flattened = flattenAndMergeMap(flattened, v, "", c.keyDelimiter())
@ -62,7 +62,7 @@ func (c Codec) Encode(v map[string]interface{}) ([]byte, error) {
return buf.Bytes(), nil
}
func (c Codec) Decode(b []byte, v map[string]interface{}) error {
func (c Codec) Decode(b []byte, v map[string]any) error {
cfg := ini.Empty(c.LoadOptions)
err := cfg.Append(b)

View file

@ -26,19 +26,19 @@ key=value
//
// in case of INI it's slightly different from Viper's internal representation
// (eg. top level keys land in a section called default)
var decoded = map[string]interface{}{
"DEFAULT": map[string]interface{}{
var decoded = map[string]any{
"DEFAULT": map[string]any{
"key": "value",
},
"map": map[string]interface{}{
"map": map[string]any{
"key": "value",
},
}
// Viper's internal representation
var data = map[string]interface{}{
var data = map[string]any{
"key": "value",
"map": map[string]interface{}{
"map": map[string]any{
"key": "value",
},
}
@ -60,11 +60,11 @@ func TestCodec_Encode(t *testing.T) {
t.Run("Default", func(t *testing.T) {
codec := Codec{}
data := map[string]interface{}{
"default": map[string]interface{}{
data := map[string]any{
"default": map[string]any{
"key": "value",
},
"map": map[string]interface{}{
"map": map[string]any{
"key": "value",
},
}
@ -84,7 +84,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("OK", func(t *testing.T) {
codec := Codec{}
v := map[string]interface{}{}
v := map[string]any{}
err := codec.Decode([]byte(original), v)
if err != nil {
@ -99,7 +99,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("InvalidData", func(t *testing.T) {
codec := Codec{}
v := map[string]interface{}{}
v := map[string]any{}
err := codec.Decode([]byte(`invalid data`), v)
if err == nil {

View file

@ -15,22 +15,22 @@ import (
// In case intermediate keys do not exist, or map to a non-map value,
// a new map is created and inserted, and the search continues from there:
// the initial map "m" may be modified!
func deepSearch(m map[string]interface{}, path []string) map[string]interface{} {
func deepSearch(m map[string]any, path []string) map[string]any {
for _, k := range path {
m2, ok := m[k]
if !ok {
// intermediate key does not exist
// => create it and continue from there
m3 := make(map[string]interface{})
m3 := make(map[string]any)
m[k] = m3
m = m3
continue
}
m3, ok := m2.(map[string]interface{})
m3, ok := m2.(map[string]any)
if !ok {
// intermediate key is a value
// => replace with a new map
m3 = make(map[string]interface{})
m3 = make(map[string]any)
m[k] = m3
}
// continue search from here
@ -40,27 +40,27 @@ func deepSearch(m map[string]interface{}, path []string) map[string]interface{}
}
// flattenAndMergeMap recursively flattens the given map into a new map
// Code is based on the function with the same name in tha main package.
// Code is based on the function with the same name in the main package.
// TODO: move it to a common place
func flattenAndMergeMap(shadow map[string]interface{}, m map[string]interface{}, prefix string, delimiter string) map[string]interface{} {
func flattenAndMergeMap(shadow map[string]any, m map[string]any, prefix string, delimiter string) map[string]any {
if shadow != nil && prefix != "" && shadow[prefix] != nil {
// prefix is shadowed => nothing more to flatten
return shadow
}
if shadow == nil {
shadow = make(map[string]interface{})
shadow = make(map[string]any)
}
var m2 map[string]interface{}
var m2 map[string]any
if prefix != "" {
prefix += delimiter
}
for k, val := range m {
fullKey := prefix + k
switch val.(type) {
case map[string]interface{}:
m2 = val.(map[string]interface{})
case map[interface{}]interface{}:
switch val := val.(type) {
case map[string]any:
m2 = val
case map[any]any:
m2 = cast.ToStringMap(val)
default:
// immediate value

View file

@ -20,12 +20,12 @@ type Codec struct {
Properties *properties.Properties
}
func (c *Codec) Encode(v map[string]interface{}) ([]byte, error) {
func (c *Codec) Encode(v map[string]any) ([]byte, error) {
if c.Properties == nil {
c.Properties = properties.NewProperties()
}
flattened := map[string]interface{}{}
flattened := map[string]any{}
flattened = flattenAndMergeMap(flattened, v, "", c.keyDelimiter())
@ -54,7 +54,7 @@ func (c *Codec) Encode(v map[string]interface{}) ([]byte, error) {
return buf.Bytes(), nil
}
func (c *Codec) Decode(b []byte, v map[string]interface{}) error {
func (c *Codec) Decode(b []byte, v map[string]any) error {
var err error
c.Properties, err = properties.Load(b, properties.UTF8)
if err != nil {

View file

@ -17,9 +17,9 @@ map.key = value
`
// Viper's internal representation
var data = map[string]interface{}{
var data = map[string]any{
"key": "value",
"map": map[string]interface{}{
"map": map[string]any{
"key": "value",
},
}
@ -41,7 +41,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("OK", func(t *testing.T) {
codec := Codec{}
v := map[string]interface{}{}
v := map[string]any{}
err := codec.Decode([]byte(original), v)
if err != nil {
@ -58,7 +58,7 @@ func TestCodec_Decode(t *testing.T) {
codec := Codec{}
v := map[string]interface{}{}
v := map[string]any{}
codec.Decode([]byte(``), v)
@ -71,7 +71,7 @@ func TestCodec_Decode(t *testing.T) {
func TestCodec_DecodeEncode(t *testing.T) {
codec := Codec{}
v := map[string]interface{}{}
v := map[string]any{}
err := codec.Decode([]byte(original), v)
if err != nil {

View file

@ -15,22 +15,22 @@ import (
// In case intermediate keys do not exist, or map to a non-map value,
// a new map is created and inserted, and the search continues from there:
// the initial map "m" may be modified!
func deepSearch(m map[string]interface{}, path []string) map[string]interface{} {
func deepSearch(m map[string]any, path []string) map[string]any {
for _, k := range path {
m2, ok := m[k]
if !ok {
// intermediate key does not exist
// => create it and continue from there
m3 := make(map[string]interface{})
m3 := make(map[string]any)
m[k] = m3
m = m3
continue
}
m3, ok := m2.(map[string]interface{})
m3, ok := m2.(map[string]any)
if !ok {
// intermediate key is a value
// => replace with a new map
m3 = make(map[string]interface{})
m3 = make(map[string]any)
m[k] = m3
}
// continue search from here
@ -40,27 +40,27 @@ func deepSearch(m map[string]interface{}, path []string) map[string]interface{}
}
// flattenAndMergeMap recursively flattens the given map into a new map
// Code is based on the function with the same name in tha main package.
// Code is based on the function with the same name in the main package.
// TODO: move it to a common place
func flattenAndMergeMap(shadow map[string]interface{}, m map[string]interface{}, prefix string, delimiter string) map[string]interface{} {
func flattenAndMergeMap(shadow map[string]any, m map[string]any, prefix string, delimiter string) map[string]any {
if shadow != nil && prefix != "" && shadow[prefix] != nil {
// prefix is shadowed => nothing more to flatten
return shadow
}
if shadow == nil {
shadow = make(map[string]interface{})
shadow = make(map[string]any)
}
var m2 map[string]interface{}
var m2 map[string]any
if prefix != "" {
prefix += delimiter
}
for k, val := range m {
fullKey := prefix + k
switch val.(type) {
case map[string]interface{}:
m2 = val.(map[string]interface{})
case map[interface{}]interface{}:
switch val := val.(type) {
case map[string]any:
m2 = val
case map[any]any:
m2 = cast.ToStringMap(val)
default:
// immediate value

View file

@ -7,11 +7,11 @@ import (
// Codec implements the encoding.Encoder and encoding.Decoder interfaces for JSON encoding.
type Codec struct{}
func (Codec) Encode(v map[string]interface{}) ([]byte, error) {
func (Codec) Encode(v map[string]any) ([]byte, error) {
// TODO: expose prefix and indent in the Codec as setting?
return json.MarshalIndent(v, "", " ")
}
func (Codec) Decode(b []byte, v map[string]interface{}) error {
func (Codec) Decode(b []byte, v map[string]any) error {
return json.Unmarshal(b, &v)
}

View file

@ -29,20 +29,20 @@ const encoded = `{
}`
// Viper's internal representation
var data = map[string]interface{}{
var data = map[string]any{
"key": "value",
"list": []interface{}{
"list": []any{
"item1",
"item2",
"item3",
},
"map": map[string]interface{}{
"map": map[string]any{
"key": "value",
},
"nested_map": map[string]interface{}{
"map": map[string]interface{}{
"nested_map": map[string]any{
"map": map[string]any{
"key": "value",
"list": []interface{}{
"list": []any{
"item1",
"item2",
"item3",
@ -68,7 +68,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("OK", func(t *testing.T) {
codec := Codec{}
v := map[string]interface{}{}
v := map[string]any{}
err := codec.Decode([]byte(encoded), v)
if err != nil {
@ -83,7 +83,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("InvalidData", func(t *testing.T) {
codec := Codec{}
v := map[string]interface{}{}
v := map[string]any{}
err := codec.Decode([]byte(`invalid data`), v)
if err == nil {

View file

@ -7,10 +7,10 @@ import (
// Codec implements the encoding.Encoder and encoding.Decoder interfaces for TOML encoding.
type Codec struct{}
func (Codec) Encode(v map[string]interface{}) ([]byte, error) {
func (Codec) Encode(v map[string]any) ([]byte, error) {
return toml.Marshal(v)
}
func (Codec) Decode(b []byte, v map[string]interface{}) error {
func (Codec) Decode(b []byte, v map[string]any) error {
return toml.Unmarshal(b, &v)
}

View file

@ -39,20 +39,20 @@ list = ['item1', 'item2', 'item3']
`
// Viper's internal representation
var data = map[string]interface{}{
var data = map[string]any{
"key": "value",
"list": []interface{}{
"list": []any{
"item1",
"item2",
"item3",
},
"map": map[string]interface{}{
"map": map[string]any{
"key": "value",
},
"nested_map": map[string]interface{}{
"map": map[string]interface{}{
"nested_map": map[string]any{
"map": map[string]any{
"key": "value",
"list": []interface{}{
"list": []any{
"item1",
"item2",
"item3",
@ -78,7 +78,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("OK", func(t *testing.T) {
codec := Codec{}
v := map[string]interface{}{}
v := map[string]any{}
err := codec.Decode([]byte(original), v)
if err != nil {
@ -93,7 +93,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("InvalidData", func(t *testing.T) {
codec := Codec{}
v := map[string]interface{}{}
v := map[string]any{}
err := codec.Decode([]byte(`invalid data`), v)
if err == nil {

View file

@ -5,10 +5,10 @@ import "gopkg.in/yaml.v3"
// Codec implements the encoding.Encoder and encoding.Decoder interfaces for YAML encoding.
type Codec struct{}
func (Codec) Encode(v map[string]interface{}) ([]byte, error) {
func (Codec) Encode(v map[string]any) ([]byte, error) {
return yaml.Marshal(v)
}
func (Codec) Decode(b []byte, v map[string]interface{}) error {
func (Codec) Decode(b []byte, v map[string]any) error {
return yaml.Unmarshal(b, &v)
}

View file

@ -47,20 +47,20 @@ nested_map:
//
// in case of YAML it's slightly different from Viper's internal representation
// (eg. map is decoded into a map with interface key)
var decoded = map[string]interface{}{
var decoded = map[string]any{
"key": "value",
"list": []interface{}{
"list": []any{
"item1",
"item2",
"item3",
},
"map": map[string]interface{}{
"map": map[string]any{
"key": "value",
},
"nested_map": map[string]interface{}{
"map": map[string]interface{}{
"nested_map": map[string]any{
"map": map[string]any{
"key": "value",
"list": []interface{}{
"list": []any{
"item1",
"item2",
"item3",
@ -70,20 +70,20 @@ var decoded = map[string]interface{}{
}
// Viper's internal representation
var data = map[string]interface{}{
var data = map[string]any{
"key": "value",
"list": []interface{}{
"list": []any{
"item1",
"item2",
"item3",
},
"map": map[string]interface{}{
"map": map[string]any{
"key": "value",
},
"nested_map": map[string]interface{}{
"map": map[string]interface{}{
"nested_map": map[string]any{
"map": map[string]any{
"key": "value",
"list": []interface{}{
"list": []any{
"item1",
"item2",
"item3",
@ -109,7 +109,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("OK", func(t *testing.T) {
codec := Codec{}
v := map[string]interface{}{}
v := map[string]any{}
err := codec.Decode([]byte(original), v)
if err != nil {
@ -124,7 +124,7 @@ func TestCodec_Decode(t *testing.T) {
t.Run("InvalidData", func(t *testing.T) {
codec := Codec{}
v := map[string]interface{}{}
v := map[string]any{}
err := codec.Decode([]byte(`invalid data`), v)
if err == nil {

View file

@ -1,40 +0,0 @@
//go:build !go1.17
// +build !go1.17
package testutil
import (
"os"
"testing"
)
// Based on https://github.com/frankban/quicktest/blob/577841610793d24f99e31cc2c0ef3a541fefd7c7/patch.go#L34-L64
// Licensed under the MIT license
// Copyright (c) 2017 Canonical Ltd.
// Setenv sets an environment variable to a temporary value for the
// duration of the test.
//
// At the end of the test (see "Deferred execution" in the package docs), the
// environment variable is returned to its original value.
func Setenv(t *testing.T, name, val string) {
setenv(t, name, val, true)
}
// setenv sets or unsets an environment variable to a temporary value for the
// duration of the test
func setenv(t *testing.T, name, val string, valOK bool) {
oldVal, oldOK := os.LookupEnv(name)
if valOK {
os.Setenv(name, val)
} else {
os.Unsetenv(name)
}
t.Cleanup(func() {
if oldOK {
os.Setenv(name, oldVal)
} else {
os.Unsetenv(name)
}
})
}

View file

@ -1,18 +0,0 @@
//go:build go1.17
// +build go1.17
package testutil
import (
"testing"
)
// Setenv sets an environment variable to a temporary value for the
// duration of the test.
//
// This shim can be removed once support for Go <1.17 is dropped.
func Setenv(t *testing.T, name, val string) {
t.Helper()
t.Setenv(name, val)
}

View file

@ -1,77 +1,68 @@
package viper
import (
"fmt"
"context"
jww "github.com/spf13/jwalterweatherman"
slog "github.com/sagikazarmark/slog-shim"
)
// Logger is a unified interface for various logging use cases and practices, including:
// - leveled logging
// - structured logging
//
// Deprecated: use `log/slog` instead.
type Logger interface {
// Trace logs a Trace event.
//
// Even more fine-grained information than Debug events.
// Loggers not supporting this level should fall back to Debug.
Trace(msg string, keyvals ...interface{})
Trace(msg string, keyvals ...any)
// Debug logs a Debug event.
//
// A verbose series of information events.
// They are useful when debugging the system.
Debug(msg string, keyvals ...interface{})
Debug(msg string, keyvals ...any)
// Info logs an Info event.
//
// General information about what's happening inside the system.
Info(msg string, keyvals ...interface{})
Info(msg string, keyvals ...any)
// Warn logs a Warn(ing) event.
//
// Non-critical events that should be looked at.
Warn(msg string, keyvals ...interface{})
Warn(msg string, keyvals ...any)
// Error logs an Error event.
//
// Critical events that require immediate attention.
// Loggers commonly provide Fatal and Panic levels above Error level,
// but exiting and panicing is out of scope for a logging library.
Error(msg string, keyvals ...interface{})
// but exiting and panicking is out of scope for a logging library.
Error(msg string, keyvals ...any)
}
type jwwLogger struct{}
func (jwwLogger) Trace(msg string, keyvals ...interface{}) {
jww.TRACE.Printf(jwwLogMessage(msg, keyvals...))
// WithLogger sets a custom logger.
func WithLogger(l *slog.Logger) Option {
return optionFunc(func(v *Viper) {
v.logger = l
})
}
func (jwwLogger) Debug(msg string, keyvals ...interface{}) {
jww.DEBUG.Printf(jwwLogMessage(msg, keyvals...))
type discardHandler struct{}
func (n *discardHandler) Enabled(_ context.Context, _ slog.Level) bool {
return false
}
func (jwwLogger) Info(msg string, keyvals ...interface{}) {
jww.INFO.Printf(jwwLogMessage(msg, keyvals...))
func (n *discardHandler) Handle(_ context.Context, _ slog.Record) error {
return nil
}
func (jwwLogger) Warn(msg string, keyvals ...interface{}) {
jww.WARN.Printf(jwwLogMessage(msg, keyvals...))
func (n *discardHandler) WithAttrs(_ []slog.Attr) slog.Handler {
return n
}
func (jwwLogger) Error(msg string, keyvals ...interface{}) {
jww.ERROR.Printf(jwwLogMessage(msg, keyvals...))
}
func jwwLogMessage(msg string, keyvals ...interface{}) string {
out := msg
if len(keyvals) > 0 && len(keyvals)%2 == 1 {
keyvals = append(keyvals, nil)
}
for i := 0; i <= len(keyvals)-2; i += 2 {
out = fmt.Sprintf("%s %v=%v", out, keyvals[i], keyvals[i+1])
}
return out
func (n *discardHandler) WithGroup(_ string) slog.Handler {
return n
}

View file

@ -1,7 +1,6 @@
package viper
import (
"fmt"
"strings"
"testing"
@ -46,11 +45,11 @@ func TestNestedOverrides(t *testing.T) {
deepCheckValue(assert, v, overrideLayer, []string{"tom", "size"}, 4)
// Case 4: key:value overridden by a map
v = overrideDefault(assert, "tom.size", 4, "tom", map[string]interface{}{"age": 10}) // "tom.size" is first given "4" as default value, then "tom" is overridden by map{"age":10}
assert.Equal(4, v.Get("tom.size")) // "tom.size" should still be reachable
assert.Equal(10, v.Get("tom.age")) // new value should be there
deepCheckValue(assert, v, overrideLayer, []string{"tom", "age"}, 10) // new value should be there
v = override(assert, "tom.size", 4, "tom", map[string]interface{}{"age": 10})
v = overrideDefault(assert, "tom.size", 4, "tom", map[string]any{"age": 10}) // "tom.size" is first given "4" as default value, then "tom" is overridden by map{"age":10}
assert.Equal(4, v.Get("tom.size")) // "tom.size" should still be reachable
assert.Equal(10, v.Get("tom.age")) // new value should be there
deepCheckValue(assert, v, overrideLayer, []string{"tom", "age"}, 10) // new value should be there
v = override(assert, "tom.size", 4, "tom", map[string]any{"age": 10})
assert.Nil(v.Get("tom.size"))
assert.Equal(10, v.Get("tom.age"))
deepCheckValue(assert, v, overrideLayer, []string{"tom", "age"}, 10)
@ -75,11 +74,11 @@ 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 any, secondPath string, secondValue any) *Viper {
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 any, secondPath string, secondValue any) *Viper {
return overrideFromLayer(overrideLayer, assert, firstPath, firstValue, secondPath, secondValue)
}
@ -94,7 +93,7 @@ func override(assert *assert.Assertions, firstPath string, firstValue interface{
//
// After each assignment, the value is checked, retrieved both by its full path
// and by its key sequence (successive maps).
func overrideFromLayer(l layer, assert *assert.Assertions, firstPath string, firstValue interface{}, secondPath string, secondValue interface{}) *Viper {
func overrideFromLayer(l layer, assert *assert.Assertions, firstPath string, firstValue any, secondPath string, secondValue any) *Viper {
v := New()
firstKeys := strings.Split(firstPath, v.keyDelim)
if assert == nil ||
@ -128,14 +127,14 @@ func overrideFromLayer(l layer, assert *assert.Assertions, firstPath string, fir
// deepCheckValue checks that all given keys correspond to a valid path in the
// configuration map of the given layer, and that the final value equals the one given
func deepCheckValue(assert *assert.Assertions, v *Viper, l layer, keys []string, value interface{}) {
func deepCheckValue(assert *assert.Assertions, v *Viper, l layer, keys []string, value any) {
if assert == nil || v == nil ||
len(keys) == 0 || len(keys[0]) == 0 {
return
}
// init
var val interface{}
var val any
var ms string
switch l {
case defaultLayer:
@ -147,28 +146,25 @@ func deepCheckValue(assert *assert.Assertions, v *Viper, l layer, keys []string,
}
// loop through map
var m map[string]interface{}
err := false
var m map[string]any
for _, k := range keys {
if val == nil {
assert.Fail(fmt.Sprintf("%s is not a map[string]interface{}", ms))
assert.Failf("%s is not a map[string]any", ms)
return
}
// deep scan of the map to get the final value
switch val.(type) {
case map[interface{}]interface{}:
switch val := val.(type) {
case map[any]any:
m = cast.ToStringMap(val)
case map[string]interface{}:
m = val.(map[string]interface{})
case map[string]any:
m = val
default:
assert.Fail(fmt.Sprintf("%s is not a map[string]interface{}", ms))
assert.Failf("%s is not a map[string]any", ms)
return
}
ms = ms + "[\"" + k + "\"]"
val = m[k]
}
if !err {
assert.Equal(value, val)
}
assert.Equal(value, val)
}

View file

@ -91,6 +91,8 @@ func getConfigManager(rp viper.RemoteProvider) (crypt.ConfigManager, error) {
cm, err = crypt.NewEtcdV3ConfigManager(endpoints, kr)
case "firestore":
cm, err = crypt.NewFirestoreConfigManager(endpoints, kr)
case "nats":
cm, err = crypt.NewNatsConfigManager(endpoints, kr)
default:
cm, err = crypt.NewConsulConfigManager(endpoints, kr)
}
@ -102,6 +104,8 @@ func getConfigManager(rp viper.RemoteProvider) (crypt.ConfigManager, error) {
cm, err = crypt.NewStandardEtcdV3ConfigManager(endpoints)
case "firestore":
cm, err = crypt.NewStandardFirestoreConfigManager(endpoints)
case "nats":
cm, err = crypt.NewStandardNatsConfigManager(endpoints)
default:
cm, err = crypt.NewStandardConsulConfigManager(endpoints)
}

45
util.go
View file

@ -18,6 +18,7 @@ import (
"strings"
"unicode"
slog "github.com/sagikazarmark/slog-shim"
"github.com/spf13/cast"
)
@ -38,11 +39,11 @@ func (pe ConfigParseError) Unwrap() error {
// toCaseInsensitiveValue checks if the value is a map;
// if so, create a copy and lower-case the keys recursively.
func toCaseInsensitiveValue(value interface{}) interface{} {
func toCaseInsensitiveValue(value any) any {
switch v := value.(type) {
case map[interface{}]interface{}:
case map[any]any:
value = copyAndInsensitiviseMap(cast.ToStringMap(v))
case map[string]interface{}:
case map[string]any:
value = copyAndInsensitiviseMap(v)
}
@ -51,15 +52,15 @@ func toCaseInsensitiveValue(value interface{}) interface{} {
// copyAndInsensitiviseMap behaves like insensitiviseMap, but creates a copy of
// any map it makes case insensitive.
func copyAndInsensitiviseMap(m map[string]interface{}) map[string]interface{} {
nm := make(map[string]interface{})
func copyAndInsensitiviseMap(m map[string]any) map[string]any {
nm := make(map[string]any)
for key, val := range m {
lkey := strings.ToLower(key)
switch v := val.(type) {
case map[interface{}]interface{}:
case map[any]any:
nm[lkey] = copyAndInsensitiviseMap(cast.ToStringMap(v))
case map[string]interface{}:
case map[string]any:
nm[lkey] = copyAndInsensitiviseMap(v)
default:
nm[lkey] = v
@ -69,23 +70,23 @@ func copyAndInsensitiviseMap(m map[string]interface{}) map[string]interface{} {
return nm
}
func insensitiviseVal(val interface{}) interface{} {
switch val.(type) {
case map[interface{}]interface{}:
func insensitiviseVal(val any) any {
switch v := val.(type) {
case map[any]any:
// nested map: cast and recursively insensitivise
val = cast.ToStringMap(val)
insensitiviseMap(val.(map[string]interface{}))
case map[string]interface{}:
insensitiviseMap(val.(map[string]any))
case map[string]any:
// nested map: recursively insensitivise
insensitiviseMap(val.(map[string]interface{}))
case []interface{}:
insensitiviseMap(v)
case []any:
// nested array: recursively insensitivise
insensitiveArray(val.([]interface{}))
insensitiveArray(v)
}
return val
}
func insensitiviseMap(m map[string]interface{}) {
func insensitiviseMap(m map[string]any) {
for key, val := range m {
val = insensitiviseVal(val)
lower := strings.ToLower(key)
@ -98,13 +99,13 @@ func insensitiviseMap(m map[string]interface{}) {
}
}
func insensitiveArray(a []interface{}) {
func insensitiveArray(a []any) {
for i, val := range a {
a[i] = insensitiviseVal(val)
}
}
func absPathify(logger Logger, inPath string) string {
func absPathify(logger *slog.Logger, inPath string) string {
logger.Info("trying to resolve absolute path", "path", inPath)
if inPath == "$HOME" || strings.HasPrefix(inPath, "$HOME"+string(os.PathSeparator)) {
@ -197,22 +198,22 @@ func parseSizeInBytes(sizeStr string) uint {
// In case intermediate keys do not exist, or map to a non-map value,
// a new map is created and inserted, and the search continues from there:
// the initial map "m" may be modified!
func deepSearch(m map[string]interface{}, path []string) map[string]interface{} {
func deepSearch(m map[string]any, path []string) map[string]any {
for _, k := range path {
m2, ok := m[k]
if !ok {
// intermediate key does not exist
// => create it and continue from there
m3 := make(map[string]interface{})
m3 := make(map[string]any)
m[k] = m3
m = m3
continue
}
m3, ok := m2.(map[string]interface{})
m3, ok := m2.(map[string]any)
if !ok {
// intermediate key is a value
// => replace with a new map
m3 = make(map[string]interface{})
m3 = make(map[string]any)
m[k] = m3
}
// continue search from here

View file

@ -16,21 +16,21 @@ import (
"reflect"
"testing"
"github.com/spf13/viper/internal/testutil"
slog "github.com/sagikazarmark/slog-shim"
)
func TestCopyAndInsensitiviseMap(t *testing.T) {
var (
given = map[string]interface{}{
given = map[string]any{
"Foo": 32,
"Bar": map[interface{}]interface{}{
"Bar": map[any]any{
"ABc": "A",
"cDE": "B",
},
}
expected = map[string]interface{}{
expected = map[string]any{
"foo": 32,
"bar": map[string]interface{}{
"bar": map[string]any{
"abc": "A",
"cde": "B",
},
@ -51,7 +51,7 @@ func TestCopyAndInsensitiviseMap(t *testing.T) {
t.Fatal("Input map changed")
}
m := given["Bar"].(map[interface{}]interface{})
m := given["Bar"].(map[any]any)
if _, ok := m["ABc"]; !ok {
t.Fatal("Input map changed")
}
@ -64,8 +64,8 @@ func TestAbsPathify(t *testing.T) {
homer := filepath.Join(home, "homer")
wd, _ := os.Getwd()
testutil.Setenv(t, "HOMER_ABSOLUTE_PATH", homer)
testutil.Setenv(t, "VAR_WITH_RELATIVE_PATH", "relative")
t.Setenv("HOMER_ABSOLUTE_PATH", homer)
t.Setenv("VAR_WITH_RELATIVE_PATH", "relative")
tests := []struct {
input string
@ -87,7 +87,7 @@ func TestAbsPathify(t *testing.T) {
}
for _, test := range tests {
got := absPathify(jwwLogger{}, test.input)
got := absPathify(slog.Default(), test.input)
if got != test.output {
t.Errorf("Got %v\nexpected\n%q", got, test.output)
}

235
viper.go
View file

@ -35,6 +35,7 @@ import (
"github.com/fsnotify/fsnotify"
"github.com/mitchellh/mapstructure"
slog "github.com/sagikazarmark/slog-shim"
"github.com/spf13/afero"
"github.com/spf13/cast"
"github.com/spf13/pflag"
@ -206,10 +207,10 @@ type Viper struct {
allowEmptyEnv bool
parents []string
config map[string]interface{}
override map[string]interface{}
defaults map[string]interface{}
kvstore map[string]interface{}
config map[string]any
override map[string]any
defaults map[string]any
kvstore map[string]any
pflags map[string]FlagValue
env map[string][]string
aliases map[string]string
@ -217,7 +218,7 @@ type Viper struct {
onConfigChange func(fsnotify.Event)
logger Logger
logger *slog.Logger
// TODO: should probably be protected with a mutex
encoderRegistry *encoding.EncoderRegistry
@ -231,16 +232,16 @@ func New() *Viper {
v.configName = "config"
v.configPermissions = os.FileMode(0o644)
v.fs = afero.NewOsFs()
v.config = make(map[string]interface{})
v.config = make(map[string]any)
v.parents = []string{}
v.override = make(map[string]interface{})
v.defaults = make(map[string]interface{})
v.kvstore = make(map[string]interface{})
v.override = make(map[string]any)
v.defaults = make(map[string]any)
v.kvstore = make(map[string]any)
v.pflags = make(map[string]FlagValue)
v.env = make(map[string][]string)
v.aliases = make(map[string]string)
v.typeByDefValue = false
v.logger = jwwLogger{}
v.logger = slog.New(&discardHandler{})
v.resetEncoding()
@ -301,7 +302,7 @@ func NewWithOptions(opts ...Option) *Viper {
func Reset() {
v = New()
SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}
SupportedRemoteProviders = []string{"etcd", "etcd3", "consul", "firestore"}
SupportedRemoteProviders = []string{"etcd", "etcd3", "consul", "firestore", "nats"}
}
// TODO: make this lazy initialization instead
@ -420,7 +421,7 @@ type RemoteProvider interface {
var SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}
// SupportedRemoteProviders are universally supported remote providers.
var SupportedRemoteProviders = []string{"etcd", "etcd3", "consul", "firestore"}
var SupportedRemoteProviders = []string{"etcd", "etcd3", "consul", "firestore", "nats"}
// OnConfigChange sets the event handler that is called when a config file changes.
func OnConfigChange(run func(in fsnotify.Event)) { v.OnConfigChange(run) }
@ -584,8 +585,8 @@ func (v *Viper) AddConfigPath(in string) {
// AddRemoteProvider adds a remote configuration source.
// Remote Providers are searched in the order they are added.
// provider is a string value: "etcd", "etcd3", "consul" or "firestore" are currently supported.
// endpoint is the url. etcd requires http://ip:port consul requires ip:port
// provider is a string value: "etcd", "etcd3", "consul", "firestore" or "nats" are currently supported.
// endpoint is the url. etcd requires http://ip:port, consul requires ip:port, nats requires nats://ip:port
// path is the path in the k/v store to retrieve configuration
// To retrieve a config file called myapp.json from /configs/myapp.json
// you should set path to /configs and set config name (SetConfigName()) to
@ -615,7 +616,7 @@ func (v *Viper) AddRemoteProvider(provider, endpoint, path string) error {
// AddSecureRemoteProvider adds a remote configuration source.
// Secure Remote Providers are searched in the order they are added.
// provider is a string value: "etcd", "etcd3", "consul" or "firestore" are currently supported.
// provider is a string value: "etcd", "etcd3", "consul", "firestore" or "nats" are currently supported.
// endpoint is the url. etcd requires http://ip:port consul requires ip:port
// secretkeyring is the filepath to your openpgp secret keyring. e.g. /etc/secrets/myring.gpg
// path is the path in the k/v store to retrieve configuration
@ -659,7 +660,7 @@ func (v *Viper) providerPathExists(p *defaultRemoteProvider) bool {
// searchMap recursively searches for a value for path in source map.
// Returns nil if not found.
// Note: This assumes that the path entries and map keys are lower cased.
func (v *Viper) searchMap(source map[string]interface{}, path []string) interface{} {
func (v *Viper) searchMap(source map[string]any, path []string) any {
if len(path) == 0 {
return source
}
@ -672,13 +673,13 @@ func (v *Viper) searchMap(source map[string]interface{}, path []string) interfac
}
// Nested case
switch next.(type) {
case map[interface{}]interface{}:
switch next := next.(type) {
case map[any]any:
return v.searchMap(cast.ToStringMap(next), path[1:])
case map[string]interface{}:
case map[string]any:
// 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:])
return v.searchMap(next, path[1:])
default:
// got a value but nested key expected, return "nil" for not found
return nil
@ -698,7 +699,7 @@ func (v *Viper) searchMap(source map[string]interface{}, path []string) interfac
// in their keys).
//
// Note: This assumes that the path entries and map keys are lower cased.
func (v *Viper) searchIndexableWithPathPrefixes(source interface{}, path []string) interface{} {
func (v *Viper) searchIndexableWithPathPrefixes(source any, path []string) any {
if len(path) == 0 {
return source
}
@ -707,11 +708,11 @@ func (v *Viper) searchIndexableWithPathPrefixes(source interface{}, path []strin
for i := len(path); i > 0; i-- {
prefixKey := strings.ToLower(strings.Join(path[0:i], v.keyDelim))
var val interface{}
var val any
switch sourceIndexable := source.(type) {
case []interface{}:
case []any:
val = v.searchSliceWithPathPrefixes(sourceIndexable, prefixKey, i, path)
case map[string]interface{}:
case map[string]any:
val = v.searchMapWithPathPrefixes(sourceIndexable, prefixKey, i, path)
}
if val != nil {
@ -728,11 +729,11 @@ func (v *Viper) searchIndexableWithPathPrefixes(source interface{}, path []strin
// This function is part of the searchIndexableWithPathPrefixes recurring search and
// should not be called directly from functions other than searchIndexableWithPathPrefixes.
func (v *Viper) searchSliceWithPathPrefixes(
sourceSlice []interface{},
sourceSlice []any,
prefixKey string,
pathIndex int,
path []string,
) interface{} {
) any {
// if the prefixKey is not a number or it is out of bounds of the slice
index, err := strconv.Atoi(prefixKey)
if err != nil || len(sourceSlice) <= index {
@ -747,9 +748,9 @@ func (v *Viper) searchSliceWithPathPrefixes(
}
switch n := next.(type) {
case map[interface{}]interface{}:
case map[any]any:
return v.searchIndexableWithPathPrefixes(cast.ToStringMap(n), path[pathIndex:])
case map[string]interface{}, []interface{}:
case map[string]any, []any:
return v.searchIndexableWithPathPrefixes(n, path[pathIndex:])
default:
// got a value but nested key expected, do nothing and look for next prefix
@ -764,11 +765,11 @@ func (v *Viper) searchSliceWithPathPrefixes(
// This function is part of the searchIndexableWithPathPrefixes recurring search and
// should not be called directly from functions other than searchIndexableWithPathPrefixes.
func (v *Viper) searchMapWithPathPrefixes(
sourceMap map[string]interface{},
sourceMap map[string]any,
prefixKey string,
pathIndex int,
path []string,
) interface{} {
) any {
next, ok := sourceMap[prefixKey]
if !ok {
return nil
@ -781,9 +782,9 @@ func (v *Viper) searchMapWithPathPrefixes(
// Nested case
switch n := next.(type) {
case map[interface{}]interface{}:
case map[any]any:
return v.searchIndexableWithPathPrefixes(cast.ToStringMap(n), path[pathIndex:])
case map[string]interface{}, []interface{}:
case map[string]any, []any:
return v.searchIndexableWithPathPrefixes(n, path[pathIndex:])
default:
// got a value but nested key expected, do nothing and look for next prefix
@ -798,8 +799,8 @@ func (v *Viper) searchMapWithPathPrefixes(
// e.g., if "foo.bar" has a value in the given map, it “shadows”
//
// "foo.bar.baz" in a lower-priority map
func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]interface{}) string {
var parentVal interface{}
func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]any) string {
var parentVal any
for i := 1; i < len(path); i++ {
parentVal = v.searchMap(m, path[0:i])
if parentVal == nil {
@ -807,9 +808,9 @@ func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]interface{})
return ""
}
switch parentVal.(type) {
case map[interface{}]interface{}:
case map[any]any:
continue
case map[string]interface{}:
case map[string]any:
continue
default:
// parentVal is a regular value which shadows "path"
@ -824,7 +825,7 @@ func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]interface{})
// e.g., if "foo.bar" has a value in the given map, it “shadows”
//
// "foo.bar.baz" in a lower-priority map
func (v *Viper) isPathShadowedInFlatMap(path []string, mi interface{}) string {
func (v *Viper) isPathShadowedInFlatMap(path []string, mi any) string {
// unify input map
var m map[string]interface{}
switch miv := mi.(type) {
@ -895,9 +896,9 @@ func GetViper() *Viper {
// override, flag, env, config file, key/value store, default
//
// 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) any { return v.Get(key) }
func (v *Viper) Get(key string) interface{} {
func (v *Viper) Get(key string) any {
lcaseKey := strings.ToLower(key)
val := v.find(lcaseKey, true)
if val == nil {
@ -1067,9 +1068,9 @@ func (v *Viper) GetStringSlice(key string) []string {
}
// 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]any { return v.GetStringMap(key) }
func (v *Viper) GetStringMap(key string) map[string]interface{} {
func (v *Viper) GetStringMap(key string) map[string]any {
return cast.ToStringMap(v.Get(key))
}
@ -1097,27 +1098,27 @@ func (v *Viper) GetSizeInBytes(key string) uint {
}
// UnmarshalKey takes a single key and unmarshals it into a Struct.
func UnmarshalKey(key string, rawVal interface{}, opts ...DecoderConfigOption) error {
func UnmarshalKey(key string, rawVal any, opts ...DecoderConfigOption) error {
return v.UnmarshalKey(key, rawVal, opts...)
}
func (v *Viper) UnmarshalKey(key string, rawVal interface{}, opts ...DecoderConfigOption) error {
func (v *Viper) UnmarshalKey(key string, rawVal any, opts ...DecoderConfigOption) error {
return decode(v.Get(key), defaultDecoderConfig(rawVal, opts...))
}
// Unmarshal unmarshals the config into a Struct. Make sure that the tags
// on the fields of the structure are properly set.
func Unmarshal(rawVal interface{}, opts ...DecoderConfigOption) error {
func Unmarshal(rawVal any, opts ...DecoderConfigOption) error {
return v.Unmarshal(rawVal, opts...)
}
func (v *Viper) Unmarshal(rawVal interface{}, opts ...DecoderConfigOption) error {
func (v *Viper) Unmarshal(rawVal any, opts ...DecoderConfigOption) error {
return decode(v.AllSettings(), defaultDecoderConfig(rawVal, opts...))
}
// defaultDecoderConfig returns default mapstructure.DecoderConfig with support
// of time.Duration values & string slices
func defaultDecoderConfig(output interface{}, opts ...DecoderConfigOption) *mapstructure.DecoderConfig {
func defaultDecoderConfig(output any, opts ...DecoderConfigOption) *mapstructure.DecoderConfig {
c := &mapstructure.DecoderConfig{
Metadata: nil,
Result: output,
@ -1134,7 +1135,7 @@ func defaultDecoderConfig(output interface{}, opts ...DecoderConfigOption) *maps
}
// A wrapper around mapstructure.Decode that mimics the WeakDecode functionality
func decode(input interface{}, config *mapstructure.DecoderConfig) error {
func decode(input any, config *mapstructure.DecoderConfig) error {
decoder, err := mapstructure.NewDecoder(config)
if err != nil {
return err
@ -1144,11 +1145,11 @@ func decode(input interface{}, config *mapstructure.DecoderConfig) error {
// UnmarshalExact unmarshals the config into a Struct, erroring if a field is nonexistent
// in the destination struct.
func UnmarshalExact(rawVal interface{}, opts ...DecoderConfigOption) error {
func UnmarshalExact(rawVal any, opts ...DecoderConfigOption) error {
return v.UnmarshalExact(rawVal, opts...)
}
func (v *Viper) UnmarshalExact(rawVal interface{}, opts ...DecoderConfigOption) error {
func (v *Viper) UnmarshalExact(rawVal any, opts ...DecoderConfigOption) error {
config := defaultDecoderConfig(rawVal, opts...)
config.ErrorUnused = true
@ -1245,9 +1246,9 @@ func (v *Viper) MustBindEnv(input ...string) {
// corresponds to a flag, the flag's default value is returned.
//
// Note: this assumes a lower-cased key given.
func (v *Viper) find(lcaseKey string, flagDefault bool) interface{} {
func (v *Viper) find(lcaseKey string, flagDefault bool) any {
var (
val interface{}
val any
exists bool
path = strings.Split(lcaseKey, v.keyDelim)
nested = len(path) > 1
@ -1406,46 +1407,46 @@ func readAsCSV(val string) ([]string, error) {
}
// mostly copied from pflag's implementation of this operation here https://github.com/spf13/pflag/blob/master/string_to_string.go#L79
// alterations are: errors are swallowed, map[string]interface{} is returned in order to enable cast.ToStringMap
func stringToStringConv(val string) interface{} {
// alterations are: errors are swallowed, map[string]any is returned in order to enable cast.ToStringMap
func stringToStringConv(val string) any {
val = strings.Trim(val, "[]")
// An empty string would cause an empty map
if len(val) == 0 {
return map[string]interface{}{}
return map[string]any{}
}
r := csv.NewReader(strings.NewReader(val))
ss, err := r.Read()
if err != nil {
return nil
}
out := make(map[string]interface{}, len(ss))
out := make(map[string]any, len(ss))
for _, pair := range ss {
kv := strings.SplitN(pair, "=", 2)
if len(kv) != 2 {
k, vv, found := strings.Cut(pair, "=")
if !found {
return nil
}
out[kv[0]] = kv[1]
out[k] = vv
}
return out
}
// mostly copied from pflag's implementation of this operation here https://github.com/spf13/pflag/blob/d5e0c0615acee7028e1e2740a11102313be88de1/string_to_int.go#L68
// alterations are: errors are swallowed, map[string]interface{} is returned in order to enable cast.ToStringMap
func stringToIntConv(val string) interface{} {
// alterations are: errors are swallowed, map[string]any is returned in order to enable cast.ToStringMap
func stringToIntConv(val string) any {
val = strings.Trim(val, "[]")
// An empty string would cause an empty map
if len(val) == 0 {
return map[string]interface{}{}
return map[string]any{}
}
ss := strings.Split(val, ",")
out := make(map[string]interface{}, len(ss))
out := make(map[string]any, len(ss))
for _, pair := range ss {
kv := strings.SplitN(pair, "=", 2)
if len(kv) != 2 {
k, vv, found := strings.Cut(pair, "=")
if !found {
return nil
}
var err error
out[kv[0]], err = strconv.Atoi(kv[1])
out[k], err = strconv.Atoi(vv)
if err != nil {
return nil
}
@ -1546,9 +1547,9 @@ func (v *Viper) InConfig(key string) bool {
// SetDefault sets the default value for this key.
// SetDefault is case-insensitive for a key.
// 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 any) { v.SetDefault(key, value) }
func (v *Viper) SetDefault(key string, value interface{}) {
func (v *Viper) SetDefault(key string, value any) {
// If alias passed in, then set the proper default
key = v.realKey(strings.ToLower(key))
value = toCaseInsensitiveValue(value)
@ -1565,9 +1566,9 @@ func (v *Viper) SetDefault(key string, value interface{}) {
// Set is case-insensitive for a key.
// Will be used instead of values obtained via
// flags, config file, ENV, default, or key/value store.
func Set(key string, value interface{}) { v.Set(key, value) }
func Set(key string, value any) { v.Set(key, value) }
func (v *Viper) Set(key string, value interface{}) {
func (v *Viper) Set(key string, value any) {
// If alias passed in, then set the proper override
key = v.realKey(strings.ToLower(key))
value = toCaseInsensitiveValue(value)
@ -1601,7 +1602,7 @@ func (v *Viper) ReadInConfig() error {
return err
}
config := make(map[string]interface{})
config := make(map[string]any)
err = v.unmarshalReader(bytes.NewReader(file), config)
if err != nil {
@ -1639,7 +1640,7 @@ func (v *Viper) MergeInConfig() error {
func ReadConfig(in io.Reader) error { return v.ReadConfig(in) }
func (v *Viper) ReadConfig(in io.Reader) error {
v.config = make(map[string]interface{})
v.config = make(map[string]any)
return v.unmarshalReader(in, v.config)
}
@ -1647,7 +1648,7 @@ func (v *Viper) ReadConfig(in io.Reader) error {
func MergeConfig(in io.Reader) error { return v.MergeConfig(in) }
func (v *Viper) MergeConfig(in io.Reader) error {
cfg := make(map[string]interface{})
cfg := make(map[string]any)
if err := v.unmarshalReader(in, cfg); err != nil {
return err
}
@ -1656,11 +1657,11 @@ func (v *Viper) MergeConfig(in io.Reader) error {
// MergeConfigMap merges the configuration from the map given with an existing config.
// Note that the map given may be modified.
func MergeConfigMap(cfg map[string]interface{}) error { return v.MergeConfigMap(cfg) }
func MergeConfigMap(cfg map[string]any) error { return v.MergeConfigMap(cfg) }
func (v *Viper) MergeConfigMap(cfg map[string]interface{}) error {
func (v *Viper) MergeConfigMap(cfg map[string]any) error {
if v.config == nil {
v.config = make(map[string]interface{})
v.config = make(map[string]any)
}
insensitiviseMap(cfg)
mergeMaps(cfg, v.config, nil)
@ -1725,7 +1726,7 @@ func (v *Viper) writeConfig(filename string, force bool) error {
return UnsupportedConfigError(configType)
}
if v.config == nil {
v.config = make(map[string]interface{})
v.config = make(map[string]any)
}
flags := os.O_CREATE | os.O_TRUNC | os.O_WRONLY
if !force {
@ -1746,11 +1747,11 @@ func (v *Viper) writeConfig(filename string, force bool) error {
// Unmarshal a Reader into a map.
// Should probably be an unexported function.
func unmarshalReader(in io.Reader, c map[string]interface{}) error {
func unmarshalReader(in io.Reader, c map[string]any) error {
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]any) error {
buf := new(bytes.Buffer)
buf.ReadFrom(in)
@ -1784,7 +1785,7 @@ func (v *Viper) marshalWriter(f afero.File, configType string) error {
return nil
}
func keyExists(k string, m map[string]interface{}) string {
func keyExists(k string, m map[string]any) string {
lk := strings.ToLower(k)
for mk := range m {
lmk := strings.ToLower(mk)
@ -1796,33 +1797,33 @@ func keyExists(k string, m map[string]interface{}) string {
}
func castToMapStringInterface(
src map[interface{}]interface{},
) map[string]interface{} {
tgt := map[string]interface{}{}
src map[any]any,
) map[string]any {
tgt := map[string]any{}
for k, v := range src {
tgt[fmt.Sprintf("%v", k)] = v
}
return tgt
}
func castMapStringSliceToMapInterface(src map[string][]string) map[string]interface{} {
tgt := map[string]interface{}{}
func castMapStringSliceToMapInterface(src map[string][]string) map[string]any {
tgt := map[string]any{}
for k, v := range src {
tgt[k] = v
}
return tgt
}
func castMapStringToMapInterface(src map[string]string) map[string]interface{} {
tgt := map[string]interface{}{}
func castMapStringToMapInterface(src map[string]string) map[string]any {
tgt := map[string]any{}
for k, v := range src {
tgt[k] = v
}
return tgt
}
func castMapFlagToMapInterface(src map[string]FlagValue) map[string]interface{} {
tgt := map[string]interface{}{}
func castMapFlagToMapInterface(src map[string]FlagValue) map[string]any {
tgt := map[string]any{}
for k, v := range src {
tgt[k] = v
}
@ -1830,17 +1831,15 @@ func castMapFlagToMapInterface(src map[string]FlagValue) map[string]interface{}
}
// mergeMaps merges two maps. The `itgt` parameter is for handling go-yaml's
// insistence on parsing nested structures as `map[interface{}]interface{}`
// insistence on parsing nested structures as `map[any]any`
// instead of using a `string` as the key for nest structures beyond one level
// deep. Both map types are supported as there is a go-yaml fork that uses
// `map[string]interface{}` instead.
func mergeMaps(
src, tgt map[string]interface{}, itgt map[interface{}]interface{},
) {
// `map[string]any` instead.
func mergeMaps(src, tgt map[string]any, itgt map[any]any) {
for sk, sv := range src {
tk := keyExists(sk, tgt)
if tk == "" {
v.logger.Trace("", "tk", "\"\"", fmt.Sprintf("tgt[%s]", sk), sv)
v.logger.Debug("", "tk", "\"\"", fmt.Sprintf("tgt[%s]", sk), sv)
tgt[sk] = sv
if itgt != nil {
itgt[sk] = sv
@ -1850,7 +1849,7 @@ func mergeMaps(
tv, ok := tgt[tk]
if !ok {
v.logger.Trace("", fmt.Sprintf("ok[%s]", tk), false, fmt.Sprintf("tgt[%s]", sk), sv)
v.logger.Debug("", fmt.Sprintf("ok[%s]", tk), false, fmt.Sprintf("tgt[%s]", sk), sv)
tgt[sk] = sv
if itgt != nil {
itgt[sk] = sv
@ -1861,7 +1860,7 @@ func mergeMaps(
svType := reflect.TypeOf(sv)
tvType := reflect.TypeOf(tv)
v.logger.Trace(
v.logger.Debug(
"processing",
"key", sk,
"st", svType,
@ -1871,12 +1870,12 @@ func mergeMaps(
)
switch ttv := tv.(type) {
case map[interface{}]interface{}:
v.logger.Trace("merging maps (must convert)")
tsv, ok := sv.(map[interface{}]interface{})
case map[any]any:
v.logger.Debug("merging maps (must convert)")
tsv, ok := sv.(map[any]any)
if !ok {
v.logger.Error(
"Could not cast sv to map[interface{}]interface{}",
"Could not cast sv to map[any]any",
"key", sk,
"st", svType,
"tt", tvType,
@ -1889,12 +1888,12 @@ func mergeMaps(
ssv := castToMapStringInterface(tsv)
stv := castToMapStringInterface(ttv)
mergeMaps(ssv, stv, ttv)
case map[string]interface{}:
v.logger.Trace("merging maps")
tsv, ok := sv.(map[string]interface{})
case map[string]any:
v.logger.Debug("merging maps")
tsv, ok := sv.(map[string]any)
if !ok {
v.logger.Error(
"Could not cast sv to map[string]interface{}",
"Could not cast sv to map[string]any",
"key", sk,
"st", svType,
"tt", tvType,
@ -1905,7 +1904,7 @@ func mergeMaps(
}
mergeMaps(tsv, ttv, nil)
default:
v.logger.Trace("setting value")
v.logger.Debug("setting value")
tgt[tk] = sv
if itgt != nil {
itgt[tk] = sv
@ -1956,7 +1955,7 @@ func (v *Viper) getKeyValueConfig() error {
return RemoteConfigError("No Files Found")
}
func (v *Viper) getRemoteConfig(provider RemoteProvider) (map[string]interface{}, error) {
func (v *Viper) getRemoteConfig(provider RemoteProvider) (map[string]any, error) {
reader, err := RemoteConfig.Get(provider)
if err != nil {
return nil, err
@ -2005,7 +2004,7 @@ func (v *Viper) watchKeyValueConfig() error {
return RemoteConfigError("No Files Found")
}
func (v *Viper) watchRemoteConfig(provider RemoteProvider) (map[string]interface{}, error) {
func (v *Viper) watchRemoteConfig(provider RemoteProvider) (map[string]any, error) {
reader, err := RemoteConfig.Watch(provider)
if err != nil {
return nil, err
@ -2044,7 +2043,7 @@ func (v *Viper) AllKeys() []string {
// it is skipped.
//
// The resulting set of paths is merged to the given shadow set at the same time.
func (v *Viper) flattenAndMergeMap(shadow map[string]bool, m map[string]interface{}, prefix string) map[string]bool {
func (v *Viper) flattenAndMergeMap(shadow map[string]bool, m map[string]any, prefix string) map[string]bool {
if shadow != nil && prefix != "" && shadow[prefix] {
// prefix is shadowed => nothing more to flatten
return shadow
@ -2053,16 +2052,16 @@ func (v *Viper) flattenAndMergeMap(shadow map[string]bool, m map[string]interfac
shadow = make(map[string]bool)
}
var m2 map[string]interface{}
var m2 map[string]any
if prefix != "" {
prefix += v.keyDelim
}
for k, val := range m {
fullKey := prefix + k
switch val.(type) {
case map[string]interface{}:
m2 = val.(map[string]interface{})
case map[interface{}]interface{}:
switch val := val.(type) {
case map[string]any:
m2 = val
case map[any]any:
m2 = cast.ToStringMap(val)
default:
// immediate value
@ -2077,7 +2076,7 @@ func (v *Viper) flattenAndMergeMap(shadow map[string]bool, m map[string]interfac
// mergeFlatMap merges the given maps, excluding values of the second map
// shadowed by values from the first map.
func (v *Viper) mergeFlatMap(shadow map[string]bool, m map[string]interface{}) map[string]bool {
func (v *Viper) mergeFlatMap(shadow map[string]bool, m map[string]any) map[string]bool {
// scan keys
outer:
for k := range m {
@ -2097,11 +2096,11 @@ outer:
return shadow
}
// AllSettings merges all settings and returns them as a map[string]interface{}.
func AllSettings() map[string]interface{} { return v.AllSettings() }
// AllSettings merges all settings and returns them as a map[string]any.
func AllSettings() map[string]any { return v.AllSettings() }
func (v *Viper) AllSettings() map[string]interface{} {
m := map[string]interface{}{}
func (v *Viper) AllSettings() map[string]any {
m := map[string]any{}
// start from the list of keys, and construct the map one value at a time
for _, k := range v.AllKeys() {
value := v.Get(k)

View file

@ -1,32 +0,0 @@
//go:build go1.16 && finder
// +build go1.16,finder
package viper
import (
"fmt"
"github.com/spf13/afero"
)
// Search all configPaths for any config file.
// Returns the first path that exists (and is a config file).
func (v *Viper) findConfigFile() (string, error) {
finder := finder{
paths: v.configPaths,
fileNames: []string{v.configName},
extensions: SupportedExts,
withoutExtension: v.configType != "",
}
file, err := finder.Find(afero.NewIOFS(v.fs))
if err != nil {
return "", err
}
if file == "" {
return "", ConfigFileNotFoundError{v.configName, fmt.Sprintf("%s", v.configPaths)}
}
return file, nil
}

View file

@ -10,14 +10,12 @@ import (
"encoding/json"
"errors"
"io"
"io/ioutil"
"os"
"os/exec"
"path"
"path/filepath"
"reflect"
"runtime"
"sort"
"strings"
"sync"
"testing"
@ -237,7 +235,7 @@ func initIni() {
}
// make directories for testing
func initDirs(t *testing.T) (string, string, func()) {
func initDirs(t *testing.T) (string, string) {
var (
testDirs = []string{`a a`, `b`, `C_`}
config = `improbable`
@ -247,38 +245,21 @@ func initDirs(t *testing.T) (string, string, func()) {
testDirs = append(testDirs, `d\d`)
}
root, err := ioutil.TempDir("", "")
require.NoError(t, err, "Failed to create temporary directory")
cleanup := true
defer func() {
if cleanup {
os.Chdir("..")
os.RemoveAll(root)
}
}()
assert.Nil(t, err)
err = os.Chdir(root)
require.Nil(t, err)
root := t.TempDir()
for _, dir := range testDirs {
err = os.Mkdir(dir, 0o750)
assert.Nil(t, err)
innerDir := filepath.Join(root, dir)
err := os.Mkdir(innerDir, 0o750)
require.NoError(t, err)
err = ioutil.WriteFile(
path.Join(dir, config+".toml"),
[]byte("key = \"value is "+dir+"\"\n"),
err = os.WriteFile(
filepath.Join(innerDir, config+".toml"),
[]byte(`key = "value is `+dir+`"`+"\n"),
0o640)
assert.Nil(t, err)
require.NoError(t, err)
}
cleanup = false
return root, config, func() {
os.Chdir("..")
os.RemoveAll(root)
}
return root, config
}
// stubs for PFlag Values
@ -514,8 +495,8 @@ func TestUnmarshaling(t *testing.T) {
assert.False(t, InConfig("state"))
assert.False(t, InConfig("clothing.hat"))
assert.Equal(t, "steve", Get("name"))
assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, Get("hobbies"))
assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[string]interface{}{"size": "large"}}, Get("clothing"))
assert.Equal(t, []any{"skateboarding", "snowboarding", "go"}, Get("hobbies"))
assert.Equal(t, map[string]any{"jacket": "leather", "trousers": "denim", "pants": map[string]any{"size": "large"}}, Get("clothing"))
assert.Equal(t, 35, Get("age"))
}
@ -620,10 +601,10 @@ func TestEnv(t *testing.T) {
BindEnv("id")
BindEnv("f", "FOOD", "OLD_FOOD")
testutil.Setenv(t, "ID", "13")
testutil.Setenv(t, "FOOD", "apple")
testutil.Setenv(t, "OLD_FOOD", "banana")
testutil.Setenv(t, "NAME", "crunk")
t.Setenv("ID", "13")
t.Setenv("FOOD", "apple")
t.Setenv("OLD_FOOD", "banana")
t.Setenv("NAME", "crunk")
assert.Equal(t, "13", Get("id"))
assert.Equal(t, "apple", Get("f"))
@ -639,7 +620,7 @@ func TestMultipleEnv(t *testing.T) {
BindEnv("f", "FOOD", "OLD_FOOD")
testutil.Setenv(t, "OLD_FOOD", "banana")
t.Setenv("OLD_FOOD", "banana")
assert.Equal(t, "banana", Get("f"))
}
@ -650,7 +631,7 @@ func TestEmptyEnv(t *testing.T) {
BindEnv("type") // Empty environment variable
BindEnv("name") // Bound, but not set environment variable
testutil.Setenv(t, "TYPE", "")
t.Setenv("TYPE", "")
assert.Equal(t, "donut", Get("type"))
assert.Equal(t, "Cake", Get("name"))
@ -664,7 +645,7 @@ func TestEmptyEnv_Allowed(t *testing.T) {
BindEnv("type") // Empty environment variable
BindEnv("name") // Bound, but not set environment variable
testutil.Setenv(t, "TYPE", "")
t.Setenv("TYPE", "")
assert.Equal(t, "", Get("type"))
assert.Equal(t, "Cake", Get("name"))
@ -677,9 +658,9 @@ func TestEnvPrefix(t *testing.T) {
BindEnv("id")
BindEnv("f", "FOOD") // not using prefix
testutil.Setenv(t, "FOO_ID", "13")
testutil.Setenv(t, "FOOD", "apple")
testutil.Setenv(t, "FOO_NAME", "crunk")
t.Setenv("FOO_ID", "13")
t.Setenv("FOOD", "apple")
t.Setenv("FOO_NAME", "crunk")
assert.Equal(t, "13", Get("id"))
assert.Equal(t, "apple", Get("f"))
@ -695,7 +676,7 @@ func TestAutoEnv(t *testing.T) {
AutomaticEnv()
testutil.Setenv(t, "FOO_BAR", "13")
t.Setenv("FOO_BAR", "13")
assert.Equal(t, "13", Get("foo_bar"))
}
@ -706,7 +687,7 @@ func TestAutoEnvWithPrefix(t *testing.T) {
AutomaticEnv()
SetEnvPrefix("Baz")
testutil.Setenv(t, "BAZ_BAR", "13")
t.Setenv("BAZ_BAR", "13")
assert.Equal(t, "13", Get("bar"))
}
@ -716,7 +697,7 @@ func TestSetEnvKeyReplacer(t *testing.T) {
AutomaticEnv()
testutil.Setenv(t, "REFRESH_INTERVAL", "30s")
t.Setenv("REFRESH_INTERVAL", "30s")
replacer := strings.NewReplacer("-", "_")
SetEnvKeyReplacer(replacer)
@ -729,7 +710,7 @@ func TestEnvKeyReplacer(t *testing.T) {
v.AutomaticEnv()
testutil.Setenv(t, "REFRESH_INTERVAL", "30s")
t.Setenv("REFRESH_INTERVAL", "30s")
assert.Equal(t, "30s", v.Get("refresh-interval"))
}
@ -741,21 +722,21 @@ func TestEnvSubConfig(t *testing.T) {
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
testutil.Setenv(t, "CLOTHING_PANTS_SIZE", "small")
t.Setenv("CLOTHING_PANTS_SIZE", "small")
subv := v.Sub("clothing").Sub("pants")
assert.Equal(t, "small", subv.Get("size"))
// again with EnvPrefix
v.SetEnvPrefix("foo") // will be uppercased automatically
subWithPrefix := v.Sub("clothing").Sub("pants")
testutil.Setenv(t, "FOO_CLOTHING_PANTS_SIZE", "large")
t.Setenv("FOO_CLOTHING_PANTS_SIZE", "large")
assert.Equal(t, "large", subWithPrefix.Get("size"))
}
func TestAllKeys(t *testing.T) {
initConfigs()
ks := sort.StringSlice{
ks := []string{
"title",
"author.bio",
"author.e-mail",
@ -792,14 +773,14 @@ func TestAllKeys(t *testing.T) {
"name_dotenv",
}
dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
all := map[string]interface{}{
"owner": map[string]interface{}{
all := map[string]any{
"owner": map[string]any{
"organization": "MongoDB",
"bio": "MongoDB Chief Developer Advocate & Hacker at Large",
"dob": dob,
},
"title": "TOML Example",
"author": map[string]interface{}{
"author": map[string]any{
"e-mail": "fake@localhost",
"github": "https://github.com/Unknown",
"name": "Unknown",
@ -807,28 +788,28 @@ func TestAllKeys(t *testing.T) {
},
"ppu": 0.55,
"eyes": "brown",
"clothing": map[string]interface{}{
"clothing": map[string]any{
"trousers": "denim",
"jacket": "leather",
"pants": map[string]interface{}{"size": "large"},
"pants": map[string]any{"size": "large"},
},
"default": map[string]interface{}{
"default": map[string]any{
"import_path": "gopkg.in/ini.v1",
"name": "ini",
"version": "v1",
},
"id": "0001",
"batters": map[string]interface{}{
"batter": []interface{}{
map[string]interface{}{"type": "Regular"},
map[string]interface{}{"type": "Chocolate"},
map[string]interface{}{"type": "Blueberry"},
map[string]interface{}{"type": "Devil's Food"},
"batters": map[string]any{
"batter": []any{
map[string]any{"type": "Regular"},
map[string]any{"type": "Chocolate"},
map[string]any{"type": "Blueberry"},
map[string]any{"type": "Devil's Food"},
},
},
"hacker": true,
"beard": true,
"hobbies": []interface{}{
"hobbies": []any{
"skateboarding",
"snowboarding",
"go",
@ -840,13 +821,13 @@ func TestAllKeys(t *testing.T) {
"p_id": "0001",
"p_ppu": "0.55",
"p_name": "Cake",
"p_batters": map[string]interface{}{
"batter": map[string]interface{}{"type": "Regular"},
"p_batters": map[string]any{
"batter": map[string]any{"type": "Regular"},
},
"p_type": "donut",
"foos": []map[string]interface{}{
"foos": []map[string]any{
{
"foo": []map[string]interface{}{
"foo": []map[string]any{
{"key": 1},
{"key": 2},
{"key": 3},
@ -859,11 +840,7 @@ func TestAllKeys(t *testing.T) {
"name_dotenv": "Cake",
}
allkeys := sort.StringSlice(AllKeys())
allkeys.Sort()
ks.Sort()
assert.Equal(t, ks, allkeys)
assert.ElementsMatch(t, ks, AllKeys())
assert.Equal(t, all, AllSettings())
}
@ -875,14 +852,10 @@ func TestAllKeysWithEnv(t *testing.T) {
v.BindEnv("foo.bar")
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_"))
testutil.Setenv(t, "ID", "13")
testutil.Setenv(t, "FOO_BAR", "baz")
t.Setenv("ID", "13")
t.Setenv("FOO_BAR", "baz")
expectedKeys := sort.StringSlice{"id", "foo.bar"}
expectedKeys.Sort()
keys := sort.StringSlice(v.AllKeys())
keys.Sort()
assert.Equal(t, expectedKeys, keys)
assert.ElementsMatch(t, []string{"id", "foo.bar"}, v.AllKeys())
}
func TestAliasesOfAliases(t *testing.T) {
@ -955,7 +928,7 @@ func TestUnmarshalWithDecoderOptions(t *testing.T) {
mapstructure.StringToTimeDurationHookFunc(),
mapstructure.StringToSliceHookFunc(","),
// Custom Decode Hook Function
func(rf reflect.Kind, rt reflect.Kind, data interface{}) (interface{}, error) {
func(rf reflect.Kind, rt reflect.Kind, data any) (any, error) {
if rf != reflect.String || rt != reflect.Map {
return data, nil
}
@ -1308,7 +1281,7 @@ func TestBoundCaseSensitivity(t *testing.T) {
BindEnv("eYEs", "TURTLE_EYES")
testutil.Setenv(t, "TURTLE_EYES", "blue")
t.Setenv("TURTLE_EYES", "blue")
assert.Equal(t, "blue", Get("eyes"))
@ -1346,38 +1319,38 @@ func TestFindsNestedKeys(t *testing.T) {
initConfigs()
dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
Set("super", map[string]interface{}{
"deep": map[string]interface{}{
Set("super", map[string]any{
"deep": map[string]any{
"nested": "value",
},
})
expected := map[string]interface{}{
"super": map[string]interface{}{
"deep": map[string]interface{}{
expected := map[string]any{
"super": map[string]any{
"deep": map[string]any{
"nested": "value",
},
},
"super.deep": map[string]interface{}{
"super.deep": map[string]any{
"nested": "value",
},
"super.deep.nested": "value",
"owner.organization": "MongoDB",
"batters.batter": []interface{}{
map[string]interface{}{
"batters.batter": []any{
map[string]any{
"type": "Regular",
},
map[string]interface{}{
map[string]any{
"type": "Chocolate",
},
map[string]interface{}{
map[string]any{
"type": "Blueberry",
},
map[string]interface{}{
map[string]any{
"type": "Devil's Food",
},
},
"hobbies": []interface{}{
"hobbies": []any{
"skateboarding", "snowboarding", "go",
},
"TITLE_DOTENV": "DotEnv Example",
@ -1385,25 +1358,25 @@ func TestFindsNestedKeys(t *testing.T) {
"NAME_DOTENV": "Cake",
"title": "TOML Example",
"newkey": "remote",
"batters": map[string]interface{}{
"batter": []interface{}{
map[string]interface{}{
"batters": map[string]any{
"batter": []any{
map[string]any{
"type": "Regular",
},
map[string]interface{}{
map[string]any{
"type": "Chocolate",
},
map[string]interface{}{
map[string]any{
"type": "Blueberry",
},
map[string]interface{}{
map[string]any{
"type": "Devil's Food",
},
},
},
"eyes": "brown",
"age": 35,
"owner": map[string]interface{}{
"owner": map[string]any{
"organization": "MongoDB",
"bio": "MongoDB Chief Developer Advocate & Hacker at Large",
"dob": dob,
@ -1414,10 +1387,10 @@ func TestFindsNestedKeys(t *testing.T) {
"name": "Cake",
"hacker": true,
"ppu": 0.55,
"clothing": map[string]interface{}{
"clothing": map[string]any{
"jacket": "leather",
"trousers": "denim",
"pants": map[string]interface{}{
"pants": map[string]any{
"size": "large",
},
},
@ -1426,9 +1399,9 @@ func TestFindsNestedKeys(t *testing.T) {
"clothing.trousers": "denim",
"owner.dob": dob,
"beard": true,
"foos": []map[string]interface{}{
"foos": []map[string]any{
{
"foo": []map[string]interface{}{
"foo": []map[string]any{
{
"key": 1,
},
@ -1462,8 +1435,8 @@ func TestReadBufConfig(t *testing.T) {
assert.False(t, v.InConfig("state"))
assert.False(t, v.InConfig("clothing.hat"))
assert.Equal(t, "steve", v.Get("name"))
assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, v.Get("hobbies"))
assert.Equal(t, map[string]interface{}{"jacket": "leather", "trousers": "denim", "pants": map[string]interface{}{"size": "large"}}, v.Get("clothing"))
assert.Equal(t, []any{"skateboarding", "snowboarding", "go"}, v.Get("hobbies"))
assert.Equal(t, map[string]any{"jacket": "leather", "trousers": "denim", "pants": map[string]any{"size": "large"}}, v.Get("clothing"))
assert.Equal(t, 35, v.Get("age"))
}
@ -1492,8 +1465,8 @@ func TestIsSet(t *testing.T) {
v.BindEnv("clothing.hat")
v.BindEnv("clothing.hats")
testutil.Setenv(t, "FOO", "bar")
testutil.Setenv(t, "CLOTHING_HAT", "bowler")
t.Setenv("FOO", "bar")
t.Setenv("CLOTHING_HAT", "bowler")
assert.True(t, v.IsSet("eyes")) // in the config file
assert.True(t, v.IsSet("foo")) // in the environment
@ -1515,30 +1488,28 @@ func TestIsSet(t *testing.T) {
}
func TestDirsSearch(t *testing.T) {
root, config, cleanup := initDirs(t)
defer cleanup()
root, config := initDirs(t)
v := New()
v.SetConfigName(config)
v.SetDefault(`key`, `default`)
entries, err := ioutil.ReadDir(root)
assert.Nil(t, err)
entries, err := os.ReadDir(root)
require.NoError(t, err)
for _, e := range entries {
if e.IsDir() {
v.AddConfigPath(e.Name())
v.AddConfigPath(filepath.Join(root, e.Name()))
}
}
err = v.ReadInConfig()
assert.Nil(t, err)
require.NoError(t, err)
assert.Equal(t, `value is `+filepath.Base(v.configPaths[0]), v.GetString(`key`))
}
func TestWrongDirsSearchNotFound(t *testing.T) {
_, config, cleanup := initDirs(t)
defer cleanup()
_, config := initDirs(t)
v := New()
v.SetConfigName(config)
@ -1548,7 +1519,7 @@ func TestWrongDirsSearchNotFound(t *testing.T) {
v.AddConfigPath(`thispathaintthere`)
err := v.ReadInConfig()
assert.Equal(t, reflect.TypeOf(ConfigFileNotFoundError{"", ""}), reflect.TypeOf(err))
assert.IsType(t, err, ConfigFileNotFoundError{"", ""})
// Even though config did not load and the error might have
// been ignored by the client, the default still loads
@ -1556,8 +1527,7 @@ func TestWrongDirsSearchNotFound(t *testing.T) {
}
func TestWrongDirsSearchNotFoundForMerge(t *testing.T) {
_, config, cleanup := initDirs(t)
defer cleanup()
_, config := initDirs(t)
v := New()
v.SetConfigName(config)
@ -1604,12 +1574,10 @@ func TestSub(t *testing.T) {
assert.Equal(t, (*Viper)(nil), subv)
subv = v.Sub("clothing")
assert.Equal(t, subv.parents[0], "clothing")
assert.Equal(t, []string{"clothing"}, subv.parents)
subv = v.Sub("clothing").Sub("pants")
assert.Equal(t, len(subv.parents), 2)
assert.Equal(t, subv.parents[0], "clothing")
assert.Equal(t, subv.parents[1], "pants")
assert.Equal(t, []string{"clothing", "pants"}, subv.parents)
}
var hclWriteExpected = []byte(`"foos" = {
@ -2201,11 +2169,11 @@ func TestMergeConfigMap(t *testing.T) {
assert(37890)
update := map[string]interface{}{
"Hello": map[string]interface{}{
update := map[string]any{
"Hello": map[string]any{
"Pop": 1234,
},
"World": map[interface{}]interface{}{
"World": map[any]any{
"Rock": 345,
},
}
@ -2276,19 +2244,19 @@ clothing:
assert.Nil(t, Get("clothing.jacket.price"))
assert.Equal(t, polyester, GetString("clothing.shirt"))
clothingSettings := AllSettings()["clothing"].(map[string]interface{})
clothingSettings := AllSettings()["clothing"].(map[string]any)
assert.Equal(t, "leather", clothingSettings["jacket"])
assert.Equal(t, polyester, clothingSettings["shirt"])
}
func TestDotParameter(t *testing.T) {
initJSON()
// shoud take precedence over batters defined in jsonExample
// should take precedence over batters defined in jsonExample
r := bytes.NewReader([]byte(`{ "batters.batter": [ { "type": "Small" } ] }`))
unmarshalReader(r, v.config)
actual := Get("batters.batter")
expected := []interface{}{map[string]interface{}{"type": "Small"}}
expected := []any{map[string]any{"type": "Small"}}
assert.Equal(t, expected, actual)
}
@ -2339,17 +2307,17 @@ R = 6
func TestCaseInsensitiveSet(t *testing.T) {
Reset()
m1 := map[string]interface{}{
m1 := map[string]any{
"Foo": 32,
"Bar": map[interface{}]interface{}{
"Bar": map[any]any{
"ABc": "A",
"cDE": "B",
},
}
m2 := map[string]interface{}{
m2 := map[string]any{
"Foo": 52,
"Bar": map[interface{}]interface{}{
"Bar": map[any]any{
"bCd": "A",
"eFG": "B",
},
@ -2420,7 +2388,7 @@ func TestParseNested(t *testing.T) {
t.Fatalf("unable to decode into struct, %v", err)
}
assert.Equal(t, 1, len(items))
assert.Len(t, items, 1)
assert.Equal(t, 100*time.Millisecond, items[0].Delay)
assert.Equal(t, 200*time.Millisecond, items[0].Nested.Delay)
}
@ -2438,36 +2406,28 @@ func doTestCaseInsensitive(t *testing.T, typ, config string) {
assert.Equal(t, 5, cast.ToInt(Get("ef.lm.p.q")))
}
func newViperWithConfigFile(t *testing.T) (*Viper, string, func()) {
watchDir, err := ioutil.TempDir("", "")
require.Nil(t, err)
func newViperWithConfigFile(t *testing.T) (*Viper, string) {
watchDir := t.TempDir()
configFile := path.Join(watchDir, "config.yaml")
err = ioutil.WriteFile(configFile, []byte("foo: bar\n"), 0o640)
require.Nil(t, err)
cleanup := func() {
os.RemoveAll(watchDir)
}
err := os.WriteFile(configFile, []byte("foo: bar\n"), 0o640)
require.NoError(t, err)
v := New()
v.SetConfigFile(configFile)
err = v.ReadInConfig()
require.Nil(t, err)
require.NoError(t, err)
require.Equal(t, "bar", v.Get("foo"))
return v, configFile, cleanup
return v, configFile
}
func newViperWithSymlinkedConfigFile(t *testing.T) (*Viper, string, string, func()) {
watchDir, err := ioutil.TempDir("", "")
require.Nil(t, err)
func newViperWithSymlinkedConfigFile(t *testing.T) (*Viper, string, string) {
watchDir := t.TempDir()
dataDir1 := path.Join(watchDir, "data1")
err = os.Mkdir(dataDir1, 0o777)
require.Nil(t, err)
err := os.Mkdir(dataDir1, 0o777)
require.NoError(t, err)
realConfigFile := path.Join(dataDir1, "config.yaml")
t.Logf("Real config file location: %s\n", realConfigFile)
err = ioutil.WriteFile(realConfigFile, []byte("foo: bar\n"), 0o640)
require.Nil(t, err)
cleanup := func() {
os.RemoveAll(watchDir)
}
err = os.WriteFile(realConfigFile, []byte("foo: bar\n"), 0o640)
require.NoError(t, err)
// now, symlink the tm `data1` dir to `data` in the baseDir
os.Symlink(dataDir1, path.Join(watchDir, "data"))
// and link the `<watchdir>/datadir1/config.yaml` to `<watchdir>/config.yaml`
@ -2478,9 +2438,9 @@ func newViperWithSymlinkedConfigFile(t *testing.T) (*Viper, string, string, func
v := New()
v.SetConfigFile(configFile)
err = v.ReadInConfig()
require.Nil(t, err)
require.NoError(t, err)
require.Equal(t, "bar", v.Get("foo"))
return v, watchDir, configFile, cleanup
return v, watchDir, configFile
}
func TestWatchFile(t *testing.T) {
@ -2491,8 +2451,7 @@ func TestWatchFile(t *testing.T) {
t.Run("file content changed", func(t *testing.T) {
// given a `config.yaml` file being watched
v, configFile, cleanup := newViperWithConfigFile(t)
defer cleanup()
v, configFile := newViperWithConfigFile(t)
_, err := os.Stat(configFile)
require.NoError(t, err)
t.Logf("test config file: %s\n", configFile)
@ -2507,10 +2466,10 @@ func TestWatchFile(t *testing.T) {
})
v.WatchConfig()
// when overwriting the file and waiting for the custom change notification handler to be triggered
err = ioutil.WriteFile(configFile, []byte("foo: baz\n"), 0o640)
err = os.WriteFile(configFile, []byte("foo: baz\n"), 0o640)
wg.Wait()
// then the config value should have changed
require.Nil(t, err)
require.NoError(t, err)
assert.Equal(t, "baz", v.Get("foo"))
})
@ -2519,8 +2478,7 @@ func TestWatchFile(t *testing.T) {
if runtime.GOOS != "linux" {
t.Skipf("Skipping test as symlink replacements don't work on non-linux environment...")
}
v, watchDir, _, _ := newViperWithSymlinkedConfigFile(t)
// defer cleanup()
v, watchDir, _ := newViperWithSymlinkedConfigFile(t)
wg := sync.WaitGroup{}
v.WatchConfig()
v.OnConfigChange(func(in fsnotify.Event) {
@ -2531,16 +2489,16 @@ func TestWatchFile(t *testing.T) {
// when link to another `config.yaml` file
dataDir2 := path.Join(watchDir, "data2")
err := os.Mkdir(dataDir2, 0o777)
require.Nil(t, err)
require.NoError(t, err)
configFile2 := path.Join(dataDir2, "config.yaml")
err = ioutil.WriteFile(configFile2, []byte("foo: baz\n"), 0o640)
require.Nil(t, err)
err = os.WriteFile(configFile2, []byte("foo: baz\n"), 0o640)
require.NoError(t, err)
// change the symlink using the `ln -sfn` command
err = exec.Command("ln", "-sfn", dataDir2, path.Join(watchDir, "data")).Run()
require.Nil(t, err)
require.NoError(t, err)
wg.Wait()
// then
require.Nil(t, err)
require.NoError(t, err)
assert.Equal(t, "baz", v.Get("foo"))
})
}
@ -2590,13 +2548,13 @@ func TestKeyDelimiter(t *testing.T) {
err := v.unmarshalReader(r, v.config)
require.NoError(t, err)
values := map[string]interface{}{
"image": map[string]interface{}{
values := map[string]any{
"image": map[string]any{
"repository": "someImage",
"tag": "1.0.0",
},
"ingress": map[string]interface{}{
"annotations": map[string]interface{}{
"ingress": map[string]any{
"annotations": map[string]any{
"traefik.frontend.rule.type": "PathPrefix",
"traefik.ingress.kubernetes.io/ssl-redirect": "true",
},
@ -2610,13 +2568,13 @@ func TestKeyDelimiter(t *testing.T) {
type config struct {
Charts struct {
Values map[string]interface{}
Values map[string]any
}
}
expected := config{
Charts: struct {
Values map[string]interface{}
Values map[string]any
}{
Values: values,
},

View file

@ -1,5 +1,4 @@
//go:build darwin || dragonfly || freebsd || openbsd || linux || netbsd || solaris || windows
// +build darwin dragonfly freebsd openbsd linux netbsd solaris windows
package viper

View file

@ -1,5 +1,4 @@
//go:build appengine || (!darwin && !dragonfly && !freebsd && !openbsd && !linux && !netbsd && !solaris && !windows)
// +build appengine !darwin,!dragonfly,!freebsd,!openbsd,!linux,!netbsd,!solaris,!windows
package viper