mirror of
https://github.com/spf13/viper
synced 2024-12-22 19:47:01 +00:00
refactor: replace interface{} with any
This commit is contained in:
parent
8a6dc5d43c
commit
3d006fe361
28 changed files with 322 additions and 324 deletions
18
README.md
18
README.md
|
@ -544,19 +544,19 @@ go func(){
|
||||||
In Viper, there are a few ways to get a value depending on the value’s type.
|
In Viper, there are a few ways to get a value depending on the value’s type.
|
||||||
The following functions and methods exist:
|
The following functions and methods exist:
|
||||||
|
|
||||||
* `Get(key string) : interface{}`
|
* `Get(key string) : any`
|
||||||
* `GetBool(key string) : bool`
|
* `GetBool(key string) : bool`
|
||||||
* `GetFloat64(key string) : float64`
|
* `GetFloat64(key string) : float64`
|
||||||
* `GetInt(key string) : int`
|
* `GetInt(key string) : int`
|
||||||
* `GetIntSlice(key string) : []int`
|
* `GetIntSlice(key string) : []int`
|
||||||
* `GetString(key string) : string`
|
* `GetString(key string) : string`
|
||||||
* `GetStringMap(key string) : map[string]interface{}`
|
* `GetStringMap(key string) : map[string]any`
|
||||||
* `GetStringMapString(key string) : map[string]string`
|
* `GetStringMapString(key string) : map[string]string`
|
||||||
* `GetStringSlice(key string) : []string`
|
* `GetStringSlice(key string) : []string`
|
||||||
* `GetTime(key string) : time.Time`
|
* `GetTime(key string) : time.Time`
|
||||||
* `GetDuration(key string) : time.Duration`
|
* `GetDuration(key string) : time.Duration`
|
||||||
* `IsSet(key string) : bool`
|
* `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
|
One important thing to recognize is that each Get function will return a zero
|
||||||
value if it’s not found. To check if a given key exists, the `IsSet()` method
|
value if it’s not found. To check if a given key exists, the `IsSet()` method
|
||||||
|
@ -719,8 +719,8 @@ etc.
|
||||||
|
|
||||||
There are two methods to do this:
|
There are two methods to do this:
|
||||||
|
|
||||||
* `Unmarshal(rawVal interface{}) : error`
|
* `Unmarshal(rawVal any) : error`
|
||||||
* `UnmarshalKey(key string, rawVal interface{}) : error`
|
* `UnmarshalKey(key string, rawVal any) : error`
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
@ -745,9 +745,9 @@ you have to change the delimiter:
|
||||||
```go
|
```go
|
||||||
v := viper.NewWithOptions(viper.KeyDelimiter("::"))
|
v := viper.NewWithOptions(viper.KeyDelimiter("::"))
|
||||||
|
|
||||||
v.SetDefault("chart::values", map[string]interface{}{
|
v.SetDefault("chart::values", map[string]any{
|
||||||
"ingress": map[string]interface{}{
|
"ingress": map[string]any{
|
||||||
"annotations": map[string]interface{}{
|
"annotations": map[string]any{
|
||||||
"traefik.frontend.rule.type": "PathPrefix",
|
"traefik.frontend.rule.type": "PathPrefix",
|
||||||
"traefik.ingress.kubernetes.io/ssl-redirect": "true",
|
"traefik.ingress.kubernetes.io/ssl-redirect": "true",
|
||||||
},
|
},
|
||||||
|
@ -756,7 +756,7 @@ v.SetDefault("chart::values", map[string]interface{}{
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
Chart struct{
|
Chart struct{
|
||||||
Values map[string]interface{}
|
Values map[string]any
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Decoder decodes the contents of b into v.
|
// 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 {
|
type Decoder interface {
|
||||||
Decode(b []byte, v map[string]interface{}) error
|
Decode(b []byte, v map[string]any) error
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -48,7 +48,7 @@ func (e *DecoderRegistry) RegisterDecoder(format string, enc Decoder) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode calls the underlying Decoder based on the format.
|
// 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()
|
e.mu.RLock()
|
||||||
decoder, ok := e.decoders[format]
|
decoder, ok := e.decoders[format]
|
||||||
e.mu.RUnlock()
|
e.mu.RUnlock()
|
||||||
|
|
|
@ -6,10 +6,10 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type decoder struct {
|
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 {
|
for key, value := range d.v {
|
||||||
v[key] = value
|
v[key] = value
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ func TestDecoderRegistry_Decode(t *testing.T) {
|
||||||
t.Run("OK", func(t *testing.T) {
|
t.Run("OK", func(t *testing.T) {
|
||||||
registry := NewDecoderRegistry()
|
registry := NewDecoderRegistry()
|
||||||
decoder := decoder{
|
decoder := decoder{
|
||||||
v: map[string]interface{}{
|
v: map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -56,7 +56,7 @@ func TestDecoderRegistry_Decode(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
v := map[string]interface{}{}
|
v := map[string]any{}
|
||||||
|
|
||||||
err = registry.Decode("myformat", []byte("key: value"), v)
|
err = registry.Decode("myformat", []byte("key: value"), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -71,7 +71,7 @@ func TestDecoderRegistry_Decode(t *testing.T) {
|
||||||
t.Run("DecoderNotFound", func(t *testing.T) {
|
t.Run("DecoderNotFound", func(t *testing.T) {
|
||||||
registry := NewDecoderRegistry()
|
registry := NewDecoderRegistry()
|
||||||
|
|
||||||
v := map[string]interface{}{}
|
v := map[string]any{}
|
||||||
|
|
||||||
err := registry.Decode("myformat", nil, v)
|
err := registry.Decode("myformat", nil, v)
|
||||||
if err != ErrDecoderNotFound {
|
if err != ErrDecoderNotFound {
|
||||||
|
|
|
@ -15,8 +15,8 @@ const keyDelimiter = "_"
|
||||||
// (commonly called as dotenv format).
|
// (commonly called as dotenv format).
|
||||||
type Codec struct{}
|
type Codec struct{}
|
||||||
|
|
||||||
func (Codec) Encode(v map[string]interface{}) ([]byte, error) {
|
func (Codec) Encode(v map[string]any) ([]byte, error) {
|
||||||
flattened := map[string]interface{}{}
|
flattened := map[string]any{}
|
||||||
|
|
||||||
flattened = flattenAndMergeMap(flattened, v, "", keyDelimiter)
|
flattened = flattenAndMergeMap(flattened, v, "", keyDelimiter)
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ func (Codec) Encode(v map[string]interface{}) ([]byte, error) {
|
||||||
return buf.Bytes(), nil
|
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
|
var buf bytes.Buffer
|
||||||
|
|
||||||
_, err := buf.Write(b)
|
_, err := buf.Write(b)
|
||||||
|
|
|
@ -15,7 +15,7 @@ const encoded = `KEY=value
|
||||||
`
|
`
|
||||||
|
|
||||||
// Viper's internal representation
|
// Viper's internal representation
|
||||||
var data = map[string]interface{}{
|
var data = map[string]any{
|
||||||
"KEY": "value",
|
"KEY": "value",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ func TestCodec_Decode(t *testing.T) {
|
||||||
t.Run("OK", func(t *testing.T) {
|
t.Run("OK", func(t *testing.T) {
|
||||||
codec := Codec{}
|
codec := Codec{}
|
||||||
|
|
||||||
v := map[string]interface{}{}
|
v := map[string]any{}
|
||||||
|
|
||||||
err := codec.Decode([]byte(original), v)
|
err := codec.Decode([]byte(original), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -51,7 +51,7 @@ func TestCodec_Decode(t *testing.T) {
|
||||||
t.Run("InvalidData", func(t *testing.T) {
|
t.Run("InvalidData", func(t *testing.T) {
|
||||||
codec := Codec{}
|
codec := Codec{}
|
||||||
|
|
||||||
v := map[string]interface{}{}
|
v := map[string]any{}
|
||||||
|
|
||||||
err := codec.Decode([]byte(`invalid data`), v)
|
err := codec.Decode([]byte(`invalid data`), v)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
|
@ -9,25 +9,25 @@ import (
|
||||||
// flattenAndMergeMap recursively flattens the given map into a new map
|
// flattenAndMergeMap recursively flattens the given map into a new map
|
||||||
// Code is based on the function with the same name in the main package.
|
// Code is based on the function with the same name in the main package.
|
||||||
// TODO: move it to a common place
|
// 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 {
|
if shadow != nil && prefix != "" && shadow[prefix] != nil {
|
||||||
// prefix is shadowed => nothing more to flatten
|
// prefix is shadowed => nothing more to flatten
|
||||||
return shadow
|
return shadow
|
||||||
}
|
}
|
||||||
if shadow == nil {
|
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 != "" {
|
if prefix != "" {
|
||||||
prefix += delimiter
|
prefix += delimiter
|
||||||
}
|
}
|
||||||
for k, val := range m {
|
for k, val := range m {
|
||||||
fullKey := prefix + k
|
fullKey := prefix + k
|
||||||
switch val := val.(type) {
|
switch val := val.(type) {
|
||||||
case map[string]interface{}:
|
case map[string]any:
|
||||||
m2 = val
|
m2 = val
|
||||||
case map[interface{}]interface{}:
|
case map[any]any:
|
||||||
m2 = cast.ToStringMap(val)
|
m2 = cast.ToStringMap(val)
|
||||||
default:
|
default:
|
||||||
// immediate value
|
// immediate value
|
||||||
|
|
|
@ -5,9 +5,9 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Encoder encodes the contents of v into a byte representation.
|
// 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 {
|
type Encoder interface {
|
||||||
Encode(v map[string]interface{}) ([]byte, error)
|
Encode(v map[string]any) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -47,7 +47,7 @@ func (e *EncoderRegistry) RegisterEncoder(format string, enc Encoder) error {
|
||||||
return nil
|
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()
|
e.mu.RLock()
|
||||||
encoder, ok := e.encoders[format]
|
encoder, ok := e.encoders[format]
|
||||||
e.mu.RUnlock()
|
e.mu.RUnlock()
|
||||||
|
|
|
@ -8,7 +8,7 @@ type encoder struct {
|
||||||
b []byte
|
b []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e encoder) Encode(_ map[string]interface{}) ([]byte, error) {
|
func (e encoder) Encode(_ map[string]any) ([]byte, error) {
|
||||||
return e.b, nil
|
return e.b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ func TestEncoderRegistry_Decode(t *testing.T) {
|
||||||
t.Fatal(err)
|
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 {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ func TestEncoderRegistry_Decode(t *testing.T) {
|
||||||
t.Run("EncoderNotFound", func(t *testing.T) {
|
t.Run("EncoderNotFound", func(t *testing.T) {
|
||||||
registry := NewEncoderRegistry()
|
registry := NewEncoderRegistry()
|
||||||
|
|
||||||
_, err := registry.Encode("myformat", map[string]interface{}{"key": "value"})
|
_, err := registry.Encode("myformat", map[string]any{"key": "value"})
|
||||||
if err != ErrEncoderNotFound {
|
if err != ErrEncoderNotFound {
|
||||||
t.Fatalf("expected ErrEncoderNotFound, got: %v", err)
|
t.Fatalf("expected ErrEncoderNotFound, got: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
// TODO: add printer config to the codec?
|
// TODO: add printer config to the codec?
|
||||||
type Codec struct{}
|
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)
|
b, err := json.Marshal(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -35,6 +35,6 @@ func (Codec) Encode(v map[string]interface{}) ([]byte, error) {
|
||||||
return buf.Bytes(), nil
|
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)
|
return hcl.Unmarshal(b, &v)
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,24 +45,24 @@ const encoded = `"key" = "value"
|
||||||
//
|
//
|
||||||
// in case of HCL it's slightly different from Viper's internal representation
|
// in case of HCL it's slightly different from Viper's internal representation
|
||||||
// (eg. map is decoded into a list of maps)
|
// (eg. map is decoded into a list of maps)
|
||||||
var decoded = map[string]interface{}{
|
var decoded = map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
"list": []interface{}{
|
"list": []any{
|
||||||
"item1",
|
"item1",
|
||||||
"item2",
|
"item2",
|
||||||
"item3",
|
"item3",
|
||||||
},
|
},
|
||||||
"map": []map[string]interface{}{
|
"map": []map[string]any{
|
||||||
{
|
{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"nested_map": []map[string]interface{}{
|
"nested_map": []map[string]any{
|
||||||
{
|
{
|
||||||
"map": []map[string]interface{}{
|
"map": []map[string]any{
|
||||||
{
|
{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
"list": []interface{}{
|
"list": []any{
|
||||||
"item1",
|
"item1",
|
||||||
"item2",
|
"item2",
|
||||||
"item3",
|
"item3",
|
||||||
|
@ -74,20 +74,20 @@ var decoded = map[string]interface{}{
|
||||||
}
|
}
|
||||||
|
|
||||||
// Viper's internal representation
|
// Viper's internal representation
|
||||||
var data = map[string]interface{}{
|
var data = map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
"list": []interface{}{
|
"list": []any{
|
||||||
"item1",
|
"item1",
|
||||||
"item2",
|
"item2",
|
||||||
"item3",
|
"item3",
|
||||||
},
|
},
|
||||||
"map": map[string]interface{}{
|
"map": map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
},
|
},
|
||||||
"nested_map": map[string]interface{}{
|
"nested_map": map[string]any{
|
||||||
"map": map[string]interface{}{
|
"map": map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
"list": []interface{}{
|
"list": []any{
|
||||||
"item1",
|
"item1",
|
||||||
"item2",
|
"item2",
|
||||||
"item3",
|
"item3",
|
||||||
|
@ -113,7 +113,7 @@ func TestCodec_Decode(t *testing.T) {
|
||||||
t.Run("OK", func(t *testing.T) {
|
t.Run("OK", func(t *testing.T) {
|
||||||
codec := Codec{}
|
codec := Codec{}
|
||||||
|
|
||||||
v := map[string]interface{}{}
|
v := map[string]any{}
|
||||||
|
|
||||||
err := codec.Decode([]byte(original), v)
|
err := codec.Decode([]byte(original), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -128,7 +128,7 @@ func TestCodec_Decode(t *testing.T) {
|
||||||
t.Run("InvalidData", func(t *testing.T) {
|
t.Run("InvalidData", func(t *testing.T) {
|
||||||
codec := Codec{}
|
codec := Codec{}
|
||||||
|
|
||||||
v := map[string]interface{}{}
|
v := map[string]any{}
|
||||||
|
|
||||||
err := codec.Decode([]byte(`invalid data`), v)
|
err := codec.Decode([]byte(`invalid data`), v)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
|
@ -19,11 +19,11 @@ type Codec struct {
|
||||||
LoadOptions LoadOptions
|
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()
|
cfg := ini.Empty()
|
||||||
ini.PrettyFormat = false
|
ini.PrettyFormat = false
|
||||||
|
|
||||||
flattened := map[string]interface{}{}
|
flattened := map[string]any{}
|
||||||
|
|
||||||
flattened = flattenAndMergeMap(flattened, v, "", c.keyDelimiter())
|
flattened = flattenAndMergeMap(flattened, v, "", c.keyDelimiter())
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ func (c Codec) Encode(v map[string]interface{}) ([]byte, error) {
|
||||||
return buf.Bytes(), nil
|
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)
|
cfg := ini.Empty(c.LoadOptions)
|
||||||
|
|
||||||
err := cfg.Append(b)
|
err := cfg.Append(b)
|
||||||
|
|
|
@ -26,19 +26,19 @@ key=value
|
||||||
//
|
//
|
||||||
// in case of INI it's slightly different from Viper's internal representation
|
// in case of INI it's slightly different from Viper's internal representation
|
||||||
// (eg. top level keys land in a section called default)
|
// (eg. top level keys land in a section called default)
|
||||||
var decoded = map[string]interface{}{
|
var decoded = map[string]any{
|
||||||
"DEFAULT": map[string]interface{}{
|
"DEFAULT": map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
},
|
},
|
||||||
"map": map[string]interface{}{
|
"map": map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Viper's internal representation
|
// Viper's internal representation
|
||||||
var data = map[string]interface{}{
|
var data = map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
"map": map[string]interface{}{
|
"map": map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -60,11 +60,11 @@ func TestCodec_Encode(t *testing.T) {
|
||||||
t.Run("Default", func(t *testing.T) {
|
t.Run("Default", func(t *testing.T) {
|
||||||
codec := Codec{}
|
codec := Codec{}
|
||||||
|
|
||||||
data := map[string]interface{}{
|
data := map[string]any{
|
||||||
"default": map[string]interface{}{
|
"default": map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
},
|
},
|
||||||
"map": map[string]interface{}{
|
"map": map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ func TestCodec_Decode(t *testing.T) {
|
||||||
t.Run("OK", func(t *testing.T) {
|
t.Run("OK", func(t *testing.T) {
|
||||||
codec := Codec{}
|
codec := Codec{}
|
||||||
|
|
||||||
v := map[string]interface{}{}
|
v := map[string]any{}
|
||||||
|
|
||||||
err := codec.Decode([]byte(original), v)
|
err := codec.Decode([]byte(original), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -99,7 +99,7 @@ func TestCodec_Decode(t *testing.T) {
|
||||||
t.Run("InvalidData", func(t *testing.T) {
|
t.Run("InvalidData", func(t *testing.T) {
|
||||||
codec := Codec{}
|
codec := Codec{}
|
||||||
|
|
||||||
v := map[string]interface{}{}
|
v := map[string]any{}
|
||||||
|
|
||||||
err := codec.Decode([]byte(`invalid data`), v)
|
err := codec.Decode([]byte(`invalid data`), v)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
|
@ -15,22 +15,22 @@ import (
|
||||||
// In case intermediate keys do not exist, or map to a non-map value,
|
// 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:
|
// a new map is created and inserted, and the search continues from there:
|
||||||
// the initial map "m" may be modified!
|
// 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 {
|
for _, k := range path {
|
||||||
m2, ok := m[k]
|
m2, ok := m[k]
|
||||||
if !ok {
|
if !ok {
|
||||||
// intermediate key does not exist
|
// intermediate key does not exist
|
||||||
// => create it and continue from there
|
// => create it and continue from there
|
||||||
m3 := make(map[string]interface{})
|
m3 := make(map[string]any)
|
||||||
m[k] = m3
|
m[k] = m3
|
||||||
m = m3
|
m = m3
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
m3, ok := m2.(map[string]interface{})
|
m3, ok := m2.(map[string]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
// intermediate key is a value
|
// intermediate key is a value
|
||||||
// => replace with a new map
|
// => replace with a new map
|
||||||
m3 = make(map[string]interface{})
|
m3 = make(map[string]any)
|
||||||
m[k] = m3
|
m[k] = m3
|
||||||
}
|
}
|
||||||
// continue search from here
|
// continue search from here
|
||||||
|
@ -42,25 +42,25 @@ func deepSearch(m map[string]interface{}, path []string) map[string]interface{}
|
||||||
// flattenAndMergeMap recursively flattens the given map into a new map
|
// flattenAndMergeMap recursively flattens the given map into a new map
|
||||||
// Code is based on the function with the same name in the main package.
|
// Code is based on the function with the same name in the main package.
|
||||||
// TODO: move it to a common place
|
// 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 {
|
if shadow != nil && prefix != "" && shadow[prefix] != nil {
|
||||||
// prefix is shadowed => nothing more to flatten
|
// prefix is shadowed => nothing more to flatten
|
||||||
return shadow
|
return shadow
|
||||||
}
|
}
|
||||||
if shadow == nil {
|
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 != "" {
|
if prefix != "" {
|
||||||
prefix += delimiter
|
prefix += delimiter
|
||||||
}
|
}
|
||||||
for k, val := range m {
|
for k, val := range m {
|
||||||
fullKey := prefix + k
|
fullKey := prefix + k
|
||||||
switch val := val.(type) {
|
switch val := val.(type) {
|
||||||
case map[string]interface{}:
|
case map[string]any:
|
||||||
m2 = val
|
m2 = val
|
||||||
case map[interface{}]interface{}:
|
case map[any]any:
|
||||||
m2 = cast.ToStringMap(val)
|
m2 = cast.ToStringMap(val)
|
||||||
default:
|
default:
|
||||||
// immediate value
|
// immediate value
|
||||||
|
|
|
@ -20,12 +20,12 @@ type Codec struct {
|
||||||
Properties *properties.Properties
|
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 {
|
if c.Properties == nil {
|
||||||
c.Properties = properties.NewProperties()
|
c.Properties = properties.NewProperties()
|
||||||
}
|
}
|
||||||
|
|
||||||
flattened := map[string]interface{}{}
|
flattened := map[string]any{}
|
||||||
|
|
||||||
flattened = flattenAndMergeMap(flattened, v, "", c.keyDelimiter())
|
flattened = flattenAndMergeMap(flattened, v, "", c.keyDelimiter())
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ func (c *Codec) Encode(v map[string]interface{}) ([]byte, error) {
|
||||||
return buf.Bytes(), nil
|
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
|
var err error
|
||||||
c.Properties, err = properties.Load(b, properties.UTF8)
|
c.Properties, err = properties.Load(b, properties.UTF8)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -17,9 +17,9 @@ map.key = value
|
||||||
`
|
`
|
||||||
|
|
||||||
// Viper's internal representation
|
// Viper's internal representation
|
||||||
var data = map[string]interface{}{
|
var data = map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
"map": map[string]interface{}{
|
"map": map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ func TestCodec_Decode(t *testing.T) {
|
||||||
t.Run("OK", func(t *testing.T) {
|
t.Run("OK", func(t *testing.T) {
|
||||||
codec := Codec{}
|
codec := Codec{}
|
||||||
|
|
||||||
v := map[string]interface{}{}
|
v := map[string]any{}
|
||||||
|
|
||||||
err := codec.Decode([]byte(original), v)
|
err := codec.Decode([]byte(original), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -58,7 +58,7 @@ func TestCodec_Decode(t *testing.T) {
|
||||||
|
|
||||||
codec := Codec{}
|
codec := Codec{}
|
||||||
|
|
||||||
v := map[string]interface{}{}
|
v := map[string]any{}
|
||||||
|
|
||||||
codec.Decode([]byte(``), v)
|
codec.Decode([]byte(``), v)
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ func TestCodec_Decode(t *testing.T) {
|
||||||
func TestCodec_DecodeEncode(t *testing.T) {
|
func TestCodec_DecodeEncode(t *testing.T) {
|
||||||
codec := Codec{}
|
codec := Codec{}
|
||||||
|
|
||||||
v := map[string]interface{}{}
|
v := map[string]any{}
|
||||||
|
|
||||||
err := codec.Decode([]byte(original), v)
|
err := codec.Decode([]byte(original), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -15,22 +15,22 @@ import (
|
||||||
// In case intermediate keys do not exist, or map to a non-map value,
|
// 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:
|
// a new map is created and inserted, and the search continues from there:
|
||||||
// the initial map "m" may be modified!
|
// 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 {
|
for _, k := range path {
|
||||||
m2, ok := m[k]
|
m2, ok := m[k]
|
||||||
if !ok {
|
if !ok {
|
||||||
// intermediate key does not exist
|
// intermediate key does not exist
|
||||||
// => create it and continue from there
|
// => create it and continue from there
|
||||||
m3 := make(map[string]interface{})
|
m3 := make(map[string]any)
|
||||||
m[k] = m3
|
m[k] = m3
|
||||||
m = m3
|
m = m3
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
m3, ok := m2.(map[string]interface{})
|
m3, ok := m2.(map[string]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
// intermediate key is a value
|
// intermediate key is a value
|
||||||
// => replace with a new map
|
// => replace with a new map
|
||||||
m3 = make(map[string]interface{})
|
m3 = make(map[string]any)
|
||||||
m[k] = m3
|
m[k] = m3
|
||||||
}
|
}
|
||||||
// continue search from here
|
// continue search from here
|
||||||
|
@ -42,25 +42,25 @@ func deepSearch(m map[string]interface{}, path []string) map[string]interface{}
|
||||||
// flattenAndMergeMap recursively flattens the given map into a new map
|
// flattenAndMergeMap recursively flattens the given map into a new map
|
||||||
// Code is based on the function with the same name in the main package.
|
// Code is based on the function with the same name in the main package.
|
||||||
// TODO: move it to a common place
|
// 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 {
|
if shadow != nil && prefix != "" && shadow[prefix] != nil {
|
||||||
// prefix is shadowed => nothing more to flatten
|
// prefix is shadowed => nothing more to flatten
|
||||||
return shadow
|
return shadow
|
||||||
}
|
}
|
||||||
if shadow == nil {
|
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 != "" {
|
if prefix != "" {
|
||||||
prefix += delimiter
|
prefix += delimiter
|
||||||
}
|
}
|
||||||
for k, val := range m {
|
for k, val := range m {
|
||||||
fullKey := prefix + k
|
fullKey := prefix + k
|
||||||
switch val := val.(type) {
|
switch val := val.(type) {
|
||||||
case map[string]interface{}:
|
case map[string]any:
|
||||||
m2 = val
|
m2 = val
|
||||||
case map[interface{}]interface{}:
|
case map[any]any:
|
||||||
m2 = cast.ToStringMap(val)
|
m2 = cast.ToStringMap(val)
|
||||||
default:
|
default:
|
||||||
// immediate value
|
// immediate value
|
||||||
|
|
|
@ -7,11 +7,11 @@ import (
|
||||||
// Codec implements the encoding.Encoder and encoding.Decoder interfaces for JSON encoding.
|
// Codec implements the encoding.Encoder and encoding.Decoder interfaces for JSON encoding.
|
||||||
type Codec struct{}
|
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?
|
// TODO: expose prefix and indent in the Codec as setting?
|
||||||
return json.MarshalIndent(v, "", " ")
|
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)
|
return json.Unmarshal(b, &v)
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,20 +29,20 @@ const encoded = `{
|
||||||
}`
|
}`
|
||||||
|
|
||||||
// Viper's internal representation
|
// Viper's internal representation
|
||||||
var data = map[string]interface{}{
|
var data = map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
"list": []interface{}{
|
"list": []any{
|
||||||
"item1",
|
"item1",
|
||||||
"item2",
|
"item2",
|
||||||
"item3",
|
"item3",
|
||||||
},
|
},
|
||||||
"map": map[string]interface{}{
|
"map": map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
},
|
},
|
||||||
"nested_map": map[string]interface{}{
|
"nested_map": map[string]any{
|
||||||
"map": map[string]interface{}{
|
"map": map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
"list": []interface{}{
|
"list": []any{
|
||||||
"item1",
|
"item1",
|
||||||
"item2",
|
"item2",
|
||||||
"item3",
|
"item3",
|
||||||
|
@ -68,7 +68,7 @@ func TestCodec_Decode(t *testing.T) {
|
||||||
t.Run("OK", func(t *testing.T) {
|
t.Run("OK", func(t *testing.T) {
|
||||||
codec := Codec{}
|
codec := Codec{}
|
||||||
|
|
||||||
v := map[string]interface{}{}
|
v := map[string]any{}
|
||||||
|
|
||||||
err := codec.Decode([]byte(encoded), v)
|
err := codec.Decode([]byte(encoded), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -83,7 +83,7 @@ func TestCodec_Decode(t *testing.T) {
|
||||||
t.Run("InvalidData", func(t *testing.T) {
|
t.Run("InvalidData", func(t *testing.T) {
|
||||||
codec := Codec{}
|
codec := Codec{}
|
||||||
|
|
||||||
v := map[string]interface{}{}
|
v := map[string]any{}
|
||||||
|
|
||||||
err := codec.Decode([]byte(`invalid data`), v)
|
err := codec.Decode([]byte(`invalid data`), v)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
|
@ -7,10 +7,10 @@ import (
|
||||||
// Codec implements the encoding.Encoder and encoding.Decoder interfaces for TOML encoding.
|
// Codec implements the encoding.Encoder and encoding.Decoder interfaces for TOML encoding.
|
||||||
type Codec struct{}
|
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)
|
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)
|
return toml.Unmarshal(b, &v)
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,20 +39,20 @@ list = ['item1', 'item2', 'item3']
|
||||||
`
|
`
|
||||||
|
|
||||||
// Viper's internal representation
|
// Viper's internal representation
|
||||||
var data = map[string]interface{}{
|
var data = map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
"list": []interface{}{
|
"list": []any{
|
||||||
"item1",
|
"item1",
|
||||||
"item2",
|
"item2",
|
||||||
"item3",
|
"item3",
|
||||||
},
|
},
|
||||||
"map": map[string]interface{}{
|
"map": map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
},
|
},
|
||||||
"nested_map": map[string]interface{}{
|
"nested_map": map[string]any{
|
||||||
"map": map[string]interface{}{
|
"map": map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
"list": []interface{}{
|
"list": []any{
|
||||||
"item1",
|
"item1",
|
||||||
"item2",
|
"item2",
|
||||||
"item3",
|
"item3",
|
||||||
|
@ -78,7 +78,7 @@ func TestCodec_Decode(t *testing.T) {
|
||||||
t.Run("OK", func(t *testing.T) {
|
t.Run("OK", func(t *testing.T) {
|
||||||
codec := Codec{}
|
codec := Codec{}
|
||||||
|
|
||||||
v := map[string]interface{}{}
|
v := map[string]any{}
|
||||||
|
|
||||||
err := codec.Decode([]byte(original), v)
|
err := codec.Decode([]byte(original), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -93,7 +93,7 @@ func TestCodec_Decode(t *testing.T) {
|
||||||
t.Run("InvalidData", func(t *testing.T) {
|
t.Run("InvalidData", func(t *testing.T) {
|
||||||
codec := Codec{}
|
codec := Codec{}
|
||||||
|
|
||||||
v := map[string]interface{}{}
|
v := map[string]any{}
|
||||||
|
|
||||||
err := codec.Decode([]byte(`invalid data`), v)
|
err := codec.Decode([]byte(`invalid data`), v)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
|
@ -5,10 +5,10 @@ import "gopkg.in/yaml.v3"
|
||||||
// Codec implements the encoding.Encoder and encoding.Decoder interfaces for YAML encoding.
|
// Codec implements the encoding.Encoder and encoding.Decoder interfaces for YAML encoding.
|
||||||
type Codec struct{}
|
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)
|
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)
|
return yaml.Unmarshal(b, &v)
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,20 +47,20 @@ nested_map:
|
||||||
//
|
//
|
||||||
// in case of YAML it's slightly different from Viper's internal representation
|
// in case of YAML it's slightly different from Viper's internal representation
|
||||||
// (eg. map is decoded into a map with interface key)
|
// (eg. map is decoded into a map with interface key)
|
||||||
var decoded = map[string]interface{}{
|
var decoded = map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
"list": []interface{}{
|
"list": []any{
|
||||||
"item1",
|
"item1",
|
||||||
"item2",
|
"item2",
|
||||||
"item3",
|
"item3",
|
||||||
},
|
},
|
||||||
"map": map[string]interface{}{
|
"map": map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
},
|
},
|
||||||
"nested_map": map[string]interface{}{
|
"nested_map": map[string]any{
|
||||||
"map": map[string]interface{}{
|
"map": map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
"list": []interface{}{
|
"list": []any{
|
||||||
"item1",
|
"item1",
|
||||||
"item2",
|
"item2",
|
||||||
"item3",
|
"item3",
|
||||||
|
@ -70,20 +70,20 @@ var decoded = map[string]interface{}{
|
||||||
}
|
}
|
||||||
|
|
||||||
// Viper's internal representation
|
// Viper's internal representation
|
||||||
var data = map[string]interface{}{
|
var data = map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
"list": []interface{}{
|
"list": []any{
|
||||||
"item1",
|
"item1",
|
||||||
"item2",
|
"item2",
|
||||||
"item3",
|
"item3",
|
||||||
},
|
},
|
||||||
"map": map[string]interface{}{
|
"map": map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
},
|
},
|
||||||
"nested_map": map[string]interface{}{
|
"nested_map": map[string]any{
|
||||||
"map": map[string]interface{}{
|
"map": map[string]any{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
"list": []interface{}{
|
"list": []any{
|
||||||
"item1",
|
"item1",
|
||||||
"item2",
|
"item2",
|
||||||
"item3",
|
"item3",
|
||||||
|
@ -109,7 +109,7 @@ func TestCodec_Decode(t *testing.T) {
|
||||||
t.Run("OK", func(t *testing.T) {
|
t.Run("OK", func(t *testing.T) {
|
||||||
codec := Codec{}
|
codec := Codec{}
|
||||||
|
|
||||||
v := map[string]interface{}{}
|
v := map[string]any{}
|
||||||
|
|
||||||
err := codec.Decode([]byte(original), v)
|
err := codec.Decode([]byte(original), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -124,7 +124,7 @@ func TestCodec_Decode(t *testing.T) {
|
||||||
t.Run("InvalidData", func(t *testing.T) {
|
t.Run("InvalidData", func(t *testing.T) {
|
||||||
codec := Codec{}
|
codec := Codec{}
|
||||||
|
|
||||||
v := map[string]interface{}{}
|
v := map[string]any{}
|
||||||
|
|
||||||
err := codec.Decode([]byte(`invalid data`), v)
|
err := codec.Decode([]byte(`invalid data`), v)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
10
logger.go
10
logger.go
|
@ -16,30 +16,30 @@ type Logger interface {
|
||||||
//
|
//
|
||||||
// Even more fine-grained information than Debug events.
|
// Even more fine-grained information than Debug events.
|
||||||
// Loggers not supporting this level should fall back to Debug.
|
// 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.
|
// Debug logs a Debug event.
|
||||||
//
|
//
|
||||||
// A verbose series of information events.
|
// A verbose series of information events.
|
||||||
// They are useful when debugging the system.
|
// They are useful when debugging the system.
|
||||||
Debug(msg string, keyvals ...interface{})
|
Debug(msg string, keyvals ...any)
|
||||||
|
|
||||||
// Info logs an Info event.
|
// Info logs an Info event.
|
||||||
//
|
//
|
||||||
// General information about what's happening inside the system.
|
// 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.
|
// Warn logs a Warn(ing) event.
|
||||||
//
|
//
|
||||||
// Non-critical events that should be looked at.
|
// Non-critical events that should be looked at.
|
||||||
Warn(msg string, keyvals ...interface{})
|
Warn(msg string, keyvals ...any)
|
||||||
|
|
||||||
// Error logs an Error event.
|
// Error logs an Error event.
|
||||||
//
|
//
|
||||||
// Critical events that require immediate attention.
|
// Critical events that require immediate attention.
|
||||||
// Loggers commonly provide Fatal and Panic levels above Error level,
|
// Loggers commonly provide Fatal and Panic levels above Error level,
|
||||||
// but exiting and panicking is out of scope for a logging library.
|
// but exiting and panicking is out of scope for a logging library.
|
||||||
Error(msg string, keyvals ...interface{})
|
Error(msg string, keyvals ...any)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithLogger sets a custom logger.
|
// WithLogger sets a custom logger.
|
||||||
|
|
|
@ -46,11 +46,11 @@ func TestNestedOverrides(t *testing.T) {
|
||||||
deepCheckValue(assert, v, overrideLayer, []string{"tom", "size"}, 4)
|
deepCheckValue(assert, v, overrideLayer, []string{"tom", "size"}, 4)
|
||||||
|
|
||||||
// Case 4: key:value overridden by a map
|
// 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}
|
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(4, v.Get("tom.size")) // "tom.size" should still be reachable
|
||||||
assert.Equal(10, v.Get("tom.age")) // new value should be there
|
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
|
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 = override(assert, "tom.size", 4, "tom", map[string]any{"age": 10})
|
||||||
assert.Nil(v.Get("tom.size"))
|
assert.Nil(v.Get("tom.size"))
|
||||||
assert.Equal(10, v.Get("tom.age"))
|
assert.Equal(10, v.Get("tom.age"))
|
||||||
deepCheckValue(assert, v, overrideLayer, []string{"tom", "age"}, 10)
|
deepCheckValue(assert, v, overrideLayer, []string{"tom", "age"}, 10)
|
||||||
|
@ -75,11 +75,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)
|
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)
|
return overrideFromLayer(overrideLayer, assert, firstPath, firstValue, secondPath, secondValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ func override(assert *assert.Assertions, firstPath string, firstValue interface{
|
||||||
//
|
//
|
||||||
// After each assignment, the value is checked, retrieved both by its full path
|
// After each assignment, the value is checked, retrieved both by its full path
|
||||||
// and by its key sequence (successive maps).
|
// 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()
|
v := New()
|
||||||
firstKeys := strings.Split(firstPath, v.keyDelim)
|
firstKeys := strings.Split(firstPath, v.keyDelim)
|
||||||
if assert == nil ||
|
if assert == nil ||
|
||||||
|
@ -128,14 +128,14 @@ func overrideFromLayer(l layer, assert *assert.Assertions, firstPath string, fir
|
||||||
|
|
||||||
// deepCheckValue checks that all given keys correspond to a valid path in the
|
// 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
|
// 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 ||
|
if assert == nil || v == nil ||
|
||||||
len(keys) == 0 || len(keys[0]) == 0 {
|
len(keys) == 0 || len(keys[0]) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// init
|
// init
|
||||||
var val interface{}
|
var val any
|
||||||
var ms string
|
var ms string
|
||||||
switch l {
|
switch l {
|
||||||
case defaultLayer:
|
case defaultLayer:
|
||||||
|
@ -147,22 +147,22 @@ func deepCheckValue(assert *assert.Assertions, v *Viper, l layer, keys []string,
|
||||||
}
|
}
|
||||||
|
|
||||||
// loop through map
|
// loop through map
|
||||||
var m map[string]interface{}
|
var m map[string]any
|
||||||
err := false
|
err := false
|
||||||
for _, k := range keys {
|
for _, k := range keys {
|
||||||
if val == nil {
|
if val == nil {
|
||||||
assert.Fail(fmt.Sprintf("%s is not a map[string]interface{}", ms))
|
assert.Fail(fmt.Sprintf("%s is not a map[string]any", ms))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// deep scan of the map to get the final value
|
// deep scan of the map to get the final value
|
||||||
switch val := val.(type) {
|
switch val := val.(type) {
|
||||||
case map[interface{}]interface{}:
|
case map[any]any:
|
||||||
m = cast.ToStringMap(val)
|
m = cast.ToStringMap(val)
|
||||||
case map[string]interface{}:
|
case map[string]any:
|
||||||
m = val
|
m = val
|
||||||
default:
|
default:
|
||||||
assert.Fail(fmt.Sprintf("%s is not a map[string]interface{}", ms))
|
assert.Fail(fmt.Sprintf("%s is not a map[string]any", ms))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ms = ms + "[\"" + k + "\"]"
|
ms = ms + "[\"" + k + "\"]"
|
||||||
|
|
36
util.go
36
util.go
|
@ -39,11 +39,11 @@ func (pe ConfigParseError) Unwrap() error {
|
||||||
|
|
||||||
// toCaseInsensitiveValue checks if the value is a map;
|
// toCaseInsensitiveValue checks if the value is a map;
|
||||||
// if so, create a copy and lower-case the keys recursively.
|
// 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) {
|
switch v := value.(type) {
|
||||||
case map[interface{}]interface{}:
|
case map[any]any:
|
||||||
value = copyAndInsensitiviseMap(cast.ToStringMap(v))
|
value = copyAndInsensitiviseMap(cast.ToStringMap(v))
|
||||||
case map[string]interface{}:
|
case map[string]any:
|
||||||
value = copyAndInsensitiviseMap(v)
|
value = copyAndInsensitiviseMap(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,15 +52,15 @@ func toCaseInsensitiveValue(value interface{}) interface{} {
|
||||||
|
|
||||||
// copyAndInsensitiviseMap behaves like insensitiviseMap, but creates a copy of
|
// copyAndInsensitiviseMap behaves like insensitiviseMap, but creates a copy of
|
||||||
// any map it makes case insensitive.
|
// any map it makes case insensitive.
|
||||||
func copyAndInsensitiviseMap(m map[string]interface{}) map[string]interface{} {
|
func copyAndInsensitiviseMap(m map[string]any) map[string]any {
|
||||||
nm := make(map[string]interface{})
|
nm := make(map[string]any)
|
||||||
|
|
||||||
for key, val := range m {
|
for key, val := range m {
|
||||||
lkey := strings.ToLower(key)
|
lkey := strings.ToLower(key)
|
||||||
switch v := val.(type) {
|
switch v := val.(type) {
|
||||||
case map[interface{}]interface{}:
|
case map[any]any:
|
||||||
nm[lkey] = copyAndInsensitiviseMap(cast.ToStringMap(v))
|
nm[lkey] = copyAndInsensitiviseMap(cast.ToStringMap(v))
|
||||||
case map[string]interface{}:
|
case map[string]any:
|
||||||
nm[lkey] = copyAndInsensitiviseMap(v)
|
nm[lkey] = copyAndInsensitiviseMap(v)
|
||||||
default:
|
default:
|
||||||
nm[lkey] = v
|
nm[lkey] = v
|
||||||
|
@ -70,23 +70,23 @@ func copyAndInsensitiviseMap(m map[string]interface{}) map[string]interface{} {
|
||||||
return nm
|
return nm
|
||||||
}
|
}
|
||||||
|
|
||||||
func insensitiviseVal(val interface{}) interface{} {
|
func insensitiviseVal(val any) any {
|
||||||
switch v := val.(type) {
|
switch v := val.(type) {
|
||||||
case map[interface{}]interface{}:
|
case map[any]any:
|
||||||
// nested map: cast and recursively insensitivise
|
// nested map: cast and recursively insensitivise
|
||||||
val = cast.ToStringMap(val)
|
val = cast.ToStringMap(val)
|
||||||
insensitiviseMap(val.(map[string]interface{}))
|
insensitiviseMap(val.(map[string]any))
|
||||||
case map[string]interface{}:
|
case map[string]any:
|
||||||
// nested map: recursively insensitivise
|
// nested map: recursively insensitivise
|
||||||
insensitiviseMap(v)
|
insensitiviseMap(v)
|
||||||
case []interface{}:
|
case []any:
|
||||||
// nested array: recursively insensitivise
|
// nested array: recursively insensitivise
|
||||||
insensitiveArray(v)
|
insensitiveArray(v)
|
||||||
}
|
}
|
||||||
return val
|
return val
|
||||||
}
|
}
|
||||||
|
|
||||||
func insensitiviseMap(m map[string]interface{}) {
|
func insensitiviseMap(m map[string]any) {
|
||||||
for key, val := range m {
|
for key, val := range m {
|
||||||
val = insensitiviseVal(val)
|
val = insensitiviseVal(val)
|
||||||
lower := strings.ToLower(key)
|
lower := strings.ToLower(key)
|
||||||
|
@ -99,7 +99,7 @@ func insensitiviseMap(m map[string]interface{}) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func insensitiveArray(a []interface{}) {
|
func insensitiveArray(a []any) {
|
||||||
for i, val := range a {
|
for i, val := range a {
|
||||||
a[i] = insensitiviseVal(val)
|
a[i] = insensitiviseVal(val)
|
||||||
}
|
}
|
||||||
|
@ -198,22 +198,22 @@ func parseSizeInBytes(sizeStr string) uint {
|
||||||
// In case intermediate keys do not exist, or map to a non-map value,
|
// 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:
|
// a new map is created and inserted, and the search continues from there:
|
||||||
// the initial map "m" may be modified!
|
// 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 {
|
for _, k := range path {
|
||||||
m2, ok := m[k]
|
m2, ok := m[k]
|
||||||
if !ok {
|
if !ok {
|
||||||
// intermediate key does not exist
|
// intermediate key does not exist
|
||||||
// => create it and continue from there
|
// => create it and continue from there
|
||||||
m3 := make(map[string]interface{})
|
m3 := make(map[string]any)
|
||||||
m[k] = m3
|
m[k] = m3
|
||||||
m = m3
|
m = m3
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
m3, ok := m2.(map[string]interface{})
|
m3, ok := m2.(map[string]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
// intermediate key is a value
|
// intermediate key is a value
|
||||||
// => replace with a new map
|
// => replace with a new map
|
||||||
m3 = make(map[string]interface{})
|
m3 = make(map[string]any)
|
||||||
m[k] = m3
|
m[k] = m3
|
||||||
}
|
}
|
||||||
// continue search from here
|
// continue search from here
|
||||||
|
|
10
util_test.go
10
util_test.go
|
@ -21,16 +21,16 @@ import (
|
||||||
|
|
||||||
func TestCopyAndInsensitiviseMap(t *testing.T) {
|
func TestCopyAndInsensitiviseMap(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
given = map[string]interface{}{
|
given = map[string]any{
|
||||||
"Foo": 32,
|
"Foo": 32,
|
||||||
"Bar": map[interface{}]interface{}{
|
"Bar": map[any]any{
|
||||||
"ABc": "A",
|
"ABc": "A",
|
||||||
"cDE": "B",
|
"cDE": "B",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
expected = map[string]interface{}{
|
expected = map[string]any{
|
||||||
"foo": 32,
|
"foo": 32,
|
||||||
"bar": map[string]interface{}{
|
"bar": map[string]any{
|
||||||
"abc": "A",
|
"abc": "A",
|
||||||
"cde": "B",
|
"cde": "B",
|
||||||
},
|
},
|
||||||
|
@ -51,7 +51,7 @@ func TestCopyAndInsensitiviseMap(t *testing.T) {
|
||||||
t.Fatal("Input map changed")
|
t.Fatal("Input map changed")
|
||||||
}
|
}
|
||||||
|
|
||||||
m := given["Bar"].(map[interface{}]interface{})
|
m := given["Bar"].(map[any]any)
|
||||||
if _, ok := m["ABc"]; !ok {
|
if _, ok := m["ABc"]; !ok {
|
||||||
t.Fatal("Input map changed")
|
t.Fatal("Input map changed")
|
||||||
}
|
}
|
||||||
|
|
190
viper.go
190
viper.go
|
@ -207,10 +207,10 @@ type Viper struct {
|
||||||
allowEmptyEnv bool
|
allowEmptyEnv bool
|
||||||
|
|
||||||
parents []string
|
parents []string
|
||||||
config map[string]interface{}
|
config map[string]any
|
||||||
override map[string]interface{}
|
override map[string]any
|
||||||
defaults map[string]interface{}
|
defaults map[string]any
|
||||||
kvstore map[string]interface{}
|
kvstore map[string]any
|
||||||
pflags map[string]FlagValue
|
pflags map[string]FlagValue
|
||||||
env map[string][]string
|
env map[string][]string
|
||||||
aliases map[string]string
|
aliases map[string]string
|
||||||
|
@ -232,11 +232,11 @@ func New() *Viper {
|
||||||
v.configName = "config"
|
v.configName = "config"
|
||||||
v.configPermissions = os.FileMode(0o644)
|
v.configPermissions = os.FileMode(0o644)
|
||||||
v.fs = afero.NewOsFs()
|
v.fs = afero.NewOsFs()
|
||||||
v.config = make(map[string]interface{})
|
v.config = make(map[string]any)
|
||||||
v.parents = []string{}
|
v.parents = []string{}
|
||||||
v.override = make(map[string]interface{})
|
v.override = make(map[string]any)
|
||||||
v.defaults = make(map[string]interface{})
|
v.defaults = make(map[string]any)
|
||||||
v.kvstore = make(map[string]interface{})
|
v.kvstore = make(map[string]any)
|
||||||
v.pflags = make(map[string]FlagValue)
|
v.pflags = make(map[string]FlagValue)
|
||||||
v.env = make(map[string][]string)
|
v.env = make(map[string][]string)
|
||||||
v.aliases = make(map[string]string)
|
v.aliases = make(map[string]string)
|
||||||
|
@ -660,7 +660,7 @@ func (v *Viper) providerPathExists(p *defaultRemoteProvider) bool {
|
||||||
// searchMap recursively searches for a value for path in source map.
|
// searchMap recursively searches for a value for path in source map.
|
||||||
// Returns nil if not found.
|
// Returns nil if not found.
|
||||||
// Note: This assumes that the path entries and map keys are lower cased.
|
// 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 {
|
if len(path) == 0 {
|
||||||
return source
|
return source
|
||||||
}
|
}
|
||||||
|
@ -674,9 +674,9 @@ func (v *Viper) searchMap(source map[string]interface{}, path []string) interfac
|
||||||
|
|
||||||
// Nested case
|
// Nested case
|
||||||
switch next := next.(type) {
|
switch next := next.(type) {
|
||||||
case map[interface{}]interface{}:
|
case map[any]any:
|
||||||
return v.searchMap(cast.ToStringMap(next), path[1:])
|
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
|
// Type assertion is safe here since it is only reached
|
||||||
// if the type of `next` is the same as the type being asserted
|
// if the type of `next` is the same as the type being asserted
|
||||||
return v.searchMap(next, path[1:])
|
return v.searchMap(next, path[1:])
|
||||||
|
@ -699,7 +699,7 @@ func (v *Viper) searchMap(source map[string]interface{}, path []string) interfac
|
||||||
// in their keys).
|
// in their keys).
|
||||||
//
|
//
|
||||||
// Note: This assumes that the path entries and map keys are lower cased.
|
// 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 {
|
if len(path) == 0 {
|
||||||
return source
|
return source
|
||||||
}
|
}
|
||||||
|
@ -708,11 +708,11 @@ func (v *Viper) searchIndexableWithPathPrefixes(source interface{}, path []strin
|
||||||
for i := len(path); i > 0; i-- {
|
for i := len(path); i > 0; i-- {
|
||||||
prefixKey := strings.ToLower(strings.Join(path[0:i], v.keyDelim))
|
prefixKey := strings.ToLower(strings.Join(path[0:i], v.keyDelim))
|
||||||
|
|
||||||
var val interface{}
|
var val any
|
||||||
switch sourceIndexable := source.(type) {
|
switch sourceIndexable := source.(type) {
|
||||||
case []interface{}:
|
case []any:
|
||||||
val = v.searchSliceWithPathPrefixes(sourceIndexable, prefixKey, i, path)
|
val = v.searchSliceWithPathPrefixes(sourceIndexable, prefixKey, i, path)
|
||||||
case map[string]interface{}:
|
case map[string]any:
|
||||||
val = v.searchMapWithPathPrefixes(sourceIndexable, prefixKey, i, path)
|
val = v.searchMapWithPathPrefixes(sourceIndexable, prefixKey, i, path)
|
||||||
}
|
}
|
||||||
if val != nil {
|
if val != nil {
|
||||||
|
@ -729,11 +729,11 @@ func (v *Viper) searchIndexableWithPathPrefixes(source interface{}, path []strin
|
||||||
// This function is part of the searchIndexableWithPathPrefixes recurring search and
|
// This function is part of the searchIndexableWithPathPrefixes recurring search and
|
||||||
// should not be called directly from functions other than searchIndexableWithPathPrefixes.
|
// should not be called directly from functions other than searchIndexableWithPathPrefixes.
|
||||||
func (v *Viper) searchSliceWithPathPrefixes(
|
func (v *Viper) searchSliceWithPathPrefixes(
|
||||||
sourceSlice []interface{},
|
sourceSlice []any,
|
||||||
prefixKey string,
|
prefixKey string,
|
||||||
pathIndex int,
|
pathIndex int,
|
||||||
path []string,
|
path []string,
|
||||||
) interface{} {
|
) any {
|
||||||
// if the prefixKey is not a number or it is out of bounds of the slice
|
// if the prefixKey is not a number or it is out of bounds of the slice
|
||||||
index, err := strconv.Atoi(prefixKey)
|
index, err := strconv.Atoi(prefixKey)
|
||||||
if err != nil || len(sourceSlice) <= index {
|
if err != nil || len(sourceSlice) <= index {
|
||||||
|
@ -748,9 +748,9 @@ func (v *Viper) searchSliceWithPathPrefixes(
|
||||||
}
|
}
|
||||||
|
|
||||||
switch n := next.(type) {
|
switch n := next.(type) {
|
||||||
case map[interface{}]interface{}:
|
case map[any]any:
|
||||||
return v.searchIndexableWithPathPrefixes(cast.ToStringMap(n), path[pathIndex:])
|
return v.searchIndexableWithPathPrefixes(cast.ToStringMap(n), path[pathIndex:])
|
||||||
case map[string]interface{}, []interface{}:
|
case map[string]any, []any:
|
||||||
return v.searchIndexableWithPathPrefixes(n, path[pathIndex:])
|
return v.searchIndexableWithPathPrefixes(n, path[pathIndex:])
|
||||||
default:
|
default:
|
||||||
// got a value but nested key expected, do nothing and look for next prefix
|
// got a value but nested key expected, do nothing and look for next prefix
|
||||||
|
@ -765,11 +765,11 @@ func (v *Viper) searchSliceWithPathPrefixes(
|
||||||
// This function is part of the searchIndexableWithPathPrefixes recurring search and
|
// This function is part of the searchIndexableWithPathPrefixes recurring search and
|
||||||
// should not be called directly from functions other than searchIndexableWithPathPrefixes.
|
// should not be called directly from functions other than searchIndexableWithPathPrefixes.
|
||||||
func (v *Viper) searchMapWithPathPrefixes(
|
func (v *Viper) searchMapWithPathPrefixes(
|
||||||
sourceMap map[string]interface{},
|
sourceMap map[string]any,
|
||||||
prefixKey string,
|
prefixKey string,
|
||||||
pathIndex int,
|
pathIndex int,
|
||||||
path []string,
|
path []string,
|
||||||
) interface{} {
|
) any {
|
||||||
next, ok := sourceMap[prefixKey]
|
next, ok := sourceMap[prefixKey]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
|
@ -782,9 +782,9 @@ func (v *Viper) searchMapWithPathPrefixes(
|
||||||
|
|
||||||
// Nested case
|
// Nested case
|
||||||
switch n := next.(type) {
|
switch n := next.(type) {
|
||||||
case map[interface{}]interface{}:
|
case map[any]any:
|
||||||
return v.searchIndexableWithPathPrefixes(cast.ToStringMap(n), path[pathIndex:])
|
return v.searchIndexableWithPathPrefixes(cast.ToStringMap(n), path[pathIndex:])
|
||||||
case map[string]interface{}, []interface{}:
|
case map[string]any, []any:
|
||||||
return v.searchIndexableWithPathPrefixes(n, path[pathIndex:])
|
return v.searchIndexableWithPathPrefixes(n, path[pathIndex:])
|
||||||
default:
|
default:
|
||||||
// got a value but nested key expected, do nothing and look for next prefix
|
// got a value but nested key expected, do nothing and look for next prefix
|
||||||
|
@ -799,8 +799,8 @@ func (v *Viper) searchMapWithPathPrefixes(
|
||||||
// e.g., if "foo.bar" has a value in the given map, it “shadows”
|
// e.g., if "foo.bar" has a value in the given map, it “shadows”
|
||||||
//
|
//
|
||||||
// "foo.bar.baz" in a lower-priority map
|
// "foo.bar.baz" in a lower-priority map
|
||||||
func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]interface{}) string {
|
func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]any) string {
|
||||||
var parentVal interface{}
|
var parentVal any
|
||||||
for i := 1; i < len(path); i++ {
|
for i := 1; i < len(path); i++ {
|
||||||
parentVal = v.searchMap(m, path[0:i])
|
parentVal = v.searchMap(m, path[0:i])
|
||||||
if parentVal == nil {
|
if parentVal == nil {
|
||||||
|
@ -808,9 +808,9 @@ func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]interface{})
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
switch parentVal.(type) {
|
switch parentVal.(type) {
|
||||||
case map[interface{}]interface{}:
|
case map[any]any:
|
||||||
continue
|
continue
|
||||||
case map[string]interface{}:
|
case map[string]any:
|
||||||
continue
|
continue
|
||||||
default:
|
default:
|
||||||
// parentVal is a regular value which shadows "path"
|
// parentVal is a regular value which shadows "path"
|
||||||
|
@ -825,9 +825,9 @@ func (v *Viper) isPathShadowedInDeepMap(path []string, m map[string]interface{})
|
||||||
// e.g., if "foo.bar" has a value in the given map, it “shadows”
|
// e.g., if "foo.bar" has a value in the given map, it “shadows”
|
||||||
//
|
//
|
||||||
// "foo.bar.baz" in a lower-priority map
|
// "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
|
// unify input map
|
||||||
var m map[string]interface{}
|
var m map[string]any
|
||||||
switch mi.(type) {
|
switch mi.(type) {
|
||||||
case map[string]string, map[string]FlagValue:
|
case map[string]string, map[string]FlagValue:
|
||||||
m = cast.ToStringMap(mi)
|
m = cast.ToStringMap(mi)
|
||||||
|
@ -894,9 +894,9 @@ func GetViper() *Viper {
|
||||||
// override, flag, env, config file, key/value store, default
|
// override, flag, env, config file, key/value store, default
|
||||||
//
|
//
|
||||||
// Get returns an interface. For a specific value use one of the Get____ methods.
|
// Get returns an interface. For a specific value use one of the Get____ methods.
|
||||||
func Get(key string) interface{} { return v.Get(key) }
|
func Get(key string) any { return v.Get(key) }
|
||||||
|
|
||||||
func (v *Viper) Get(key string) interface{} {
|
func (v *Viper) Get(key string) any {
|
||||||
lcaseKey := strings.ToLower(key)
|
lcaseKey := strings.ToLower(key)
|
||||||
val := v.find(lcaseKey, true)
|
val := v.find(lcaseKey, true)
|
||||||
if val == nil {
|
if val == nil {
|
||||||
|
@ -1066,9 +1066,9 @@ func (v *Viper) GetStringSlice(key string) []string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetStringMap returns the value associated with the key as a map of interfaces.
|
// GetStringMap returns the value associated with the key as a map of interfaces.
|
||||||
func GetStringMap(key string) map[string]interface{} { return v.GetStringMap(key) }
|
func GetStringMap(key string) map[string]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))
|
return cast.ToStringMap(v.Get(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1096,27 +1096,27 @@ func (v *Viper) GetSizeInBytes(key string) uint {
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalKey takes a single key and unmarshals it into a Struct.
|
// 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...)
|
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...))
|
return decode(v.Get(key), defaultDecoderConfig(rawVal, opts...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unmarshal unmarshals the config into a Struct. Make sure that the tags
|
// Unmarshal unmarshals the config into a Struct. Make sure that the tags
|
||||||
// on the fields of the structure are properly set.
|
// 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...)
|
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...))
|
return decode(v.AllSettings(), defaultDecoderConfig(rawVal, opts...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// defaultDecoderConfig returns default mapstructure.DecoderConfig with support
|
// defaultDecoderConfig returns default mapstructure.DecoderConfig with support
|
||||||
// of time.Duration values & string slices
|
// 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{
|
c := &mapstructure.DecoderConfig{
|
||||||
Metadata: nil,
|
Metadata: nil,
|
||||||
Result: output,
|
Result: output,
|
||||||
|
@ -1133,7 +1133,7 @@ func defaultDecoderConfig(output interface{}, opts ...DecoderConfigOption) *maps
|
||||||
}
|
}
|
||||||
|
|
||||||
// A wrapper around mapstructure.Decode that mimics the WeakDecode functionality
|
// 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)
|
decoder, err := mapstructure.NewDecoder(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1143,11 +1143,11 @@ func decode(input interface{}, config *mapstructure.DecoderConfig) error {
|
||||||
|
|
||||||
// UnmarshalExact unmarshals the config into a Struct, erroring if a field is nonexistent
|
// UnmarshalExact unmarshals the config into a Struct, erroring if a field is nonexistent
|
||||||
// in the destination struct.
|
// in the destination struct.
|
||||||
func UnmarshalExact(rawVal interface{}, opts ...DecoderConfigOption) error {
|
func UnmarshalExact(rawVal any, opts ...DecoderConfigOption) error {
|
||||||
return v.UnmarshalExact(rawVal, opts...)
|
return v.UnmarshalExact(rawVal, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Viper) UnmarshalExact(rawVal interface{}, opts ...DecoderConfigOption) error {
|
func (v *Viper) UnmarshalExact(rawVal any, opts ...DecoderConfigOption) error {
|
||||||
config := defaultDecoderConfig(rawVal, opts...)
|
config := defaultDecoderConfig(rawVal, opts...)
|
||||||
config.ErrorUnused = true
|
config.ErrorUnused = true
|
||||||
|
|
||||||
|
@ -1244,9 +1244,9 @@ func (v *Viper) MustBindEnv(input ...string) {
|
||||||
// corresponds to a flag, the flag's default value is returned.
|
// corresponds to a flag, the flag's default value is returned.
|
||||||
//
|
//
|
||||||
// Note: this assumes a lower-cased key given.
|
// 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 (
|
var (
|
||||||
val interface{}
|
val any
|
||||||
exists bool
|
exists bool
|
||||||
path = strings.Split(lcaseKey, v.keyDelim)
|
path = strings.Split(lcaseKey, v.keyDelim)
|
||||||
nested = len(path) > 1
|
nested = len(path) > 1
|
||||||
|
@ -1405,19 +1405,19 @@ 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
|
// 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
|
// alterations are: errors are swallowed, map[string]any is returned in order to enable cast.ToStringMap
|
||||||
func stringToStringConv(val string) interface{} {
|
func stringToStringConv(val string) any {
|
||||||
val = strings.Trim(val, "[]")
|
val = strings.Trim(val, "[]")
|
||||||
// An empty string would cause an empty map
|
// An empty string would cause an empty map
|
||||||
if len(val) == 0 {
|
if len(val) == 0 {
|
||||||
return map[string]interface{}{}
|
return map[string]any{}
|
||||||
}
|
}
|
||||||
r := csv.NewReader(strings.NewReader(val))
|
r := csv.NewReader(strings.NewReader(val))
|
||||||
ss, err := r.Read()
|
ss, err := r.Read()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
out := make(map[string]interface{}, len(ss))
|
out := make(map[string]any, len(ss))
|
||||||
for _, pair := range ss {
|
for _, pair := range ss {
|
||||||
kv := strings.SplitN(pair, "=", 2)
|
kv := strings.SplitN(pair, "=", 2)
|
||||||
if len(kv) != 2 {
|
if len(kv) != 2 {
|
||||||
|
@ -1429,15 +1429,15 @@ func stringToStringConv(val string) interface{} {
|
||||||
}
|
}
|
||||||
|
|
||||||
// mostly copied from pflag's implementation of this operation here https://github.com/spf13/pflag/blob/d5e0c0615acee7028e1e2740a11102313be88de1/string_to_int.go#L68
|
// 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
|
// alterations are: errors are swallowed, map[string]any is returned in order to enable cast.ToStringMap
|
||||||
func stringToIntConv(val string) interface{} {
|
func stringToIntConv(val string) any {
|
||||||
val = strings.Trim(val, "[]")
|
val = strings.Trim(val, "[]")
|
||||||
// An empty string would cause an empty map
|
// An empty string would cause an empty map
|
||||||
if len(val) == 0 {
|
if len(val) == 0 {
|
||||||
return map[string]interface{}{}
|
return map[string]any{}
|
||||||
}
|
}
|
||||||
ss := strings.Split(val, ",")
|
ss := strings.Split(val, ",")
|
||||||
out := make(map[string]interface{}, len(ss))
|
out := make(map[string]any, len(ss))
|
||||||
for _, pair := range ss {
|
for _, pair := range ss {
|
||||||
kv := strings.SplitN(pair, "=", 2)
|
kv := strings.SplitN(pair, "=", 2)
|
||||||
if len(kv) != 2 {
|
if len(kv) != 2 {
|
||||||
|
@ -1545,9 +1545,9 @@ func (v *Viper) InConfig(key string) bool {
|
||||||
// SetDefault sets the default value for this key.
|
// SetDefault sets the default value for this key.
|
||||||
// SetDefault is case-insensitive for a key.
|
// SetDefault is case-insensitive for a key.
|
||||||
// Default only used when no value is provided by the user via flag, config or ENV.
|
// Default only used when no value is provided by the user via flag, config or ENV.
|
||||||
func SetDefault(key string, value interface{}) { v.SetDefault(key, value) }
|
func SetDefault(key string, value 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
|
// If alias passed in, then set the proper default
|
||||||
key = v.realKey(strings.ToLower(key))
|
key = v.realKey(strings.ToLower(key))
|
||||||
value = toCaseInsensitiveValue(value)
|
value = toCaseInsensitiveValue(value)
|
||||||
|
@ -1564,9 +1564,9 @@ func (v *Viper) SetDefault(key string, value interface{}) {
|
||||||
// Set is case-insensitive for a key.
|
// Set is case-insensitive for a key.
|
||||||
// Will be used instead of values obtained via
|
// Will be used instead of values obtained via
|
||||||
// flags, config file, ENV, default, or key/value store.
|
// flags, config file, ENV, default, or key/value store.
|
||||||
func Set(key string, value interface{}) { v.Set(key, value) }
|
func Set(key string, value 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
|
// If alias passed in, then set the proper override
|
||||||
key = v.realKey(strings.ToLower(key))
|
key = v.realKey(strings.ToLower(key))
|
||||||
value = toCaseInsensitiveValue(value)
|
value = toCaseInsensitiveValue(value)
|
||||||
|
@ -1600,7 +1600,7 @@ func (v *Viper) ReadInConfig() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
config := make(map[string]interface{})
|
config := make(map[string]any)
|
||||||
|
|
||||||
err = v.unmarshalReader(bytes.NewReader(file), config)
|
err = v.unmarshalReader(bytes.NewReader(file), config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1638,7 +1638,7 @@ func (v *Viper) MergeInConfig() error {
|
||||||
func ReadConfig(in io.Reader) error { return v.ReadConfig(in) }
|
func ReadConfig(in io.Reader) error { return v.ReadConfig(in) }
|
||||||
|
|
||||||
func (v *Viper) ReadConfig(in io.Reader) error {
|
func (v *Viper) ReadConfig(in io.Reader) error {
|
||||||
v.config = make(map[string]interface{})
|
v.config = make(map[string]any)
|
||||||
return v.unmarshalReader(in, v.config)
|
return v.unmarshalReader(in, v.config)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1646,7 +1646,7 @@ func (v *Viper) ReadConfig(in io.Reader) error {
|
||||||
func MergeConfig(in io.Reader) error { return v.MergeConfig(in) }
|
func MergeConfig(in io.Reader) error { return v.MergeConfig(in) }
|
||||||
|
|
||||||
func (v *Viper) MergeConfig(in io.Reader) error {
|
func (v *Viper) MergeConfig(in io.Reader) error {
|
||||||
cfg := make(map[string]interface{})
|
cfg := make(map[string]any)
|
||||||
if err := v.unmarshalReader(in, cfg); err != nil {
|
if err := v.unmarshalReader(in, cfg); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1655,11 +1655,11 @@ func (v *Viper) MergeConfig(in io.Reader) error {
|
||||||
|
|
||||||
// MergeConfigMap merges the configuration from the map given with an existing config.
|
// MergeConfigMap merges the configuration from the map given with an existing config.
|
||||||
// Note that the map given may be modified.
|
// Note that the map given may be modified.
|
||||||
func MergeConfigMap(cfg map[string]interface{}) error { return v.MergeConfigMap(cfg) }
|
func MergeConfigMap(cfg map[string]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 {
|
if v.config == nil {
|
||||||
v.config = make(map[string]interface{})
|
v.config = make(map[string]any)
|
||||||
}
|
}
|
||||||
insensitiviseMap(cfg)
|
insensitiviseMap(cfg)
|
||||||
mergeMaps(cfg, v.config, nil)
|
mergeMaps(cfg, v.config, nil)
|
||||||
|
@ -1724,7 +1724,7 @@ func (v *Viper) writeConfig(filename string, force bool) error {
|
||||||
return UnsupportedConfigError(configType)
|
return UnsupportedConfigError(configType)
|
||||||
}
|
}
|
||||||
if v.config == nil {
|
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
|
flags := os.O_CREATE | os.O_TRUNC | os.O_WRONLY
|
||||||
if !force {
|
if !force {
|
||||||
|
@ -1745,11 +1745,11 @@ func (v *Viper) writeConfig(filename string, force bool) error {
|
||||||
|
|
||||||
// Unmarshal a Reader into a map.
|
// Unmarshal a Reader into a map.
|
||||||
// Should probably be an unexported function.
|
// 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)
|
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 := new(bytes.Buffer)
|
||||||
buf.ReadFrom(in)
|
buf.ReadFrom(in)
|
||||||
|
|
||||||
|
@ -1783,7 +1783,7 @@ func (v *Viper) marshalWriter(f afero.File, configType string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func keyExists(k string, m map[string]interface{}) string {
|
func keyExists(k string, m map[string]any) string {
|
||||||
lk := strings.ToLower(k)
|
lk := strings.ToLower(k)
|
||||||
for mk := range m {
|
for mk := range m {
|
||||||
lmk := strings.ToLower(mk)
|
lmk := strings.ToLower(mk)
|
||||||
|
@ -1795,33 +1795,33 @@ func keyExists(k string, m map[string]interface{}) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func castToMapStringInterface(
|
func castToMapStringInterface(
|
||||||
src map[interface{}]interface{},
|
src map[any]any,
|
||||||
) map[string]interface{} {
|
) map[string]any {
|
||||||
tgt := map[string]interface{}{}
|
tgt := map[string]any{}
|
||||||
for k, v := range src {
|
for k, v := range src {
|
||||||
tgt[fmt.Sprintf("%v", k)] = v
|
tgt[fmt.Sprintf("%v", k)] = v
|
||||||
}
|
}
|
||||||
return tgt
|
return tgt
|
||||||
}
|
}
|
||||||
|
|
||||||
func castMapStringSliceToMapInterface(src map[string][]string) map[string]interface{} {
|
func castMapStringSliceToMapInterface(src map[string][]string) map[string]any {
|
||||||
tgt := map[string]interface{}{}
|
tgt := map[string]any{}
|
||||||
for k, v := range src {
|
for k, v := range src {
|
||||||
tgt[k] = v
|
tgt[k] = v
|
||||||
}
|
}
|
||||||
return tgt
|
return tgt
|
||||||
}
|
}
|
||||||
|
|
||||||
func castMapStringToMapInterface(src map[string]string) map[string]interface{} {
|
func castMapStringToMapInterface(src map[string]string) map[string]any {
|
||||||
tgt := map[string]interface{}{}
|
tgt := map[string]any{}
|
||||||
for k, v := range src {
|
for k, v := range src {
|
||||||
tgt[k] = v
|
tgt[k] = v
|
||||||
}
|
}
|
||||||
return tgt
|
return tgt
|
||||||
}
|
}
|
||||||
|
|
||||||
func castMapFlagToMapInterface(src map[string]FlagValue) map[string]interface{} {
|
func castMapFlagToMapInterface(src map[string]FlagValue) map[string]any {
|
||||||
tgt := map[string]interface{}{}
|
tgt := map[string]any{}
|
||||||
for k, v := range src {
|
for k, v := range src {
|
||||||
tgt[k] = v
|
tgt[k] = v
|
||||||
}
|
}
|
||||||
|
@ -1829,13 +1829,11 @@ func castMapFlagToMapInterface(src map[string]FlagValue) map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// mergeMaps merges two maps. The `itgt` parameter is for handling go-yaml's
|
// 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
|
// 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
|
// deep. Both map types are supported as there is a go-yaml fork that uses
|
||||||
// `map[string]interface{}` instead.
|
// `map[string]any` instead.
|
||||||
func mergeMaps(
|
func mergeMaps(src, tgt map[string]any, itgt map[any]any) {
|
||||||
src, tgt map[string]interface{}, itgt map[interface{}]interface{},
|
|
||||||
) {
|
|
||||||
for sk, sv := range src {
|
for sk, sv := range src {
|
||||||
tk := keyExists(sk, tgt)
|
tk := keyExists(sk, tgt)
|
||||||
if tk == "" {
|
if tk == "" {
|
||||||
|
@ -1870,12 +1868,12 @@ func mergeMaps(
|
||||||
)
|
)
|
||||||
|
|
||||||
switch ttv := tv.(type) {
|
switch ttv := tv.(type) {
|
||||||
case map[interface{}]interface{}:
|
case map[any]any:
|
||||||
v.logger.Debug("merging maps (must convert)")
|
v.logger.Debug("merging maps (must convert)")
|
||||||
tsv, ok := sv.(map[interface{}]interface{})
|
tsv, ok := sv.(map[any]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
v.logger.Error(
|
v.logger.Error(
|
||||||
"Could not cast sv to map[interface{}]interface{}",
|
"Could not cast sv to map[any]any",
|
||||||
"key", sk,
|
"key", sk,
|
||||||
"st", svType,
|
"st", svType,
|
||||||
"tt", tvType,
|
"tt", tvType,
|
||||||
|
@ -1888,12 +1886,12 @@ func mergeMaps(
|
||||||
ssv := castToMapStringInterface(tsv)
|
ssv := castToMapStringInterface(tsv)
|
||||||
stv := castToMapStringInterface(ttv)
|
stv := castToMapStringInterface(ttv)
|
||||||
mergeMaps(ssv, stv, ttv)
|
mergeMaps(ssv, stv, ttv)
|
||||||
case map[string]interface{}:
|
case map[string]any:
|
||||||
v.logger.Debug("merging maps")
|
v.logger.Debug("merging maps")
|
||||||
tsv, ok := sv.(map[string]interface{})
|
tsv, ok := sv.(map[string]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
v.logger.Error(
|
v.logger.Error(
|
||||||
"Could not cast sv to map[string]interface{}",
|
"Could not cast sv to map[string]any",
|
||||||
"key", sk,
|
"key", sk,
|
||||||
"st", svType,
|
"st", svType,
|
||||||
"tt", tvType,
|
"tt", tvType,
|
||||||
|
@ -1955,7 +1953,7 @@ func (v *Viper) getKeyValueConfig() error {
|
||||||
return RemoteConfigError("No Files Found")
|
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)
|
reader, err := RemoteConfig.Get(provider)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -2004,7 +2002,7 @@ func (v *Viper) watchKeyValueConfig() error {
|
||||||
return RemoteConfigError("No Files Found")
|
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)
|
reader, err := RemoteConfig.Watch(provider)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -2043,7 +2041,7 @@ func (v *Viper) AllKeys() []string {
|
||||||
// it is skipped.
|
// it is skipped.
|
||||||
//
|
//
|
||||||
// The resulting set of paths is merged to the given shadow set at the same time.
|
// 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] {
|
if shadow != nil && prefix != "" && shadow[prefix] {
|
||||||
// prefix is shadowed => nothing more to flatten
|
// prefix is shadowed => nothing more to flatten
|
||||||
return shadow
|
return shadow
|
||||||
|
@ -2052,16 +2050,16 @@ func (v *Viper) flattenAndMergeMap(shadow map[string]bool, m map[string]interfac
|
||||||
shadow = make(map[string]bool)
|
shadow = make(map[string]bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
var m2 map[string]interface{}
|
var m2 map[string]any
|
||||||
if prefix != "" {
|
if prefix != "" {
|
||||||
prefix += v.keyDelim
|
prefix += v.keyDelim
|
||||||
}
|
}
|
||||||
for k, val := range m {
|
for k, val := range m {
|
||||||
fullKey := prefix + k
|
fullKey := prefix + k
|
||||||
switch val := val.(type) {
|
switch val := val.(type) {
|
||||||
case map[string]interface{}:
|
case map[string]any:
|
||||||
m2 = val
|
m2 = val
|
||||||
case map[interface{}]interface{}:
|
case map[any]any:
|
||||||
m2 = cast.ToStringMap(val)
|
m2 = cast.ToStringMap(val)
|
||||||
default:
|
default:
|
||||||
// immediate value
|
// immediate value
|
||||||
|
@ -2076,7 +2074,7 @@ func (v *Viper) flattenAndMergeMap(shadow map[string]bool, m map[string]interfac
|
||||||
|
|
||||||
// mergeFlatMap merges the given maps, excluding values of the second map
|
// mergeFlatMap merges the given maps, excluding values of the second map
|
||||||
// shadowed by values from the first 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
|
// scan keys
|
||||||
outer:
|
outer:
|
||||||
for k := range m {
|
for k := range m {
|
||||||
|
@ -2096,11 +2094,11 @@ outer:
|
||||||
return shadow
|
return shadow
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllSettings merges all settings and returns them as a map[string]interface{}.
|
// AllSettings merges all settings and returns them as a map[string]any.
|
||||||
func AllSettings() map[string]interface{} { return v.AllSettings() }
|
func AllSettings() map[string]any { return v.AllSettings() }
|
||||||
|
|
||||||
func (v *Viper) AllSettings() map[string]interface{} {
|
func (v *Viper) AllSettings() map[string]any {
|
||||||
m := map[string]interface{}{}
|
m := map[string]any{}
|
||||||
// start from the list of keys, and construct the map one value at a time
|
// start from the list of keys, and construct the map one value at a time
|
||||||
for _, k := range v.AllKeys() {
|
for _, k := range v.AllKeys() {
|
||||||
value := v.Get(k)
|
value := v.Get(k)
|
||||||
|
|
120
viper_test.go
120
viper_test.go
|
@ -496,8 +496,8 @@ func TestUnmarshaling(t *testing.T) {
|
||||||
assert.False(t, InConfig("state"))
|
assert.False(t, InConfig("state"))
|
||||||
assert.False(t, InConfig("clothing.hat"))
|
assert.False(t, InConfig("clothing.hat"))
|
||||||
assert.Equal(t, "steve", Get("name"))
|
assert.Equal(t, "steve", Get("name"))
|
||||||
assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, Get("hobbies"))
|
assert.Equal(t, []any{"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, map[string]any{"jacket": "leather", "trousers": "denim", "pants": map[string]any{"size": "large"}}, Get("clothing"))
|
||||||
assert.Equal(t, 35, Get("age"))
|
assert.Equal(t, 35, Get("age"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -774,14 +774,14 @@ func TestAllKeys(t *testing.T) {
|
||||||
"name_dotenv",
|
"name_dotenv",
|
||||||
}
|
}
|
||||||
dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
|
dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
|
||||||
all := map[string]interface{}{
|
all := map[string]any{
|
||||||
"owner": map[string]interface{}{
|
"owner": map[string]any{
|
||||||
"organization": "MongoDB",
|
"organization": "MongoDB",
|
||||||
"bio": "MongoDB Chief Developer Advocate & Hacker at Large",
|
"bio": "MongoDB Chief Developer Advocate & Hacker at Large",
|
||||||
"dob": dob,
|
"dob": dob,
|
||||||
},
|
},
|
||||||
"title": "TOML Example",
|
"title": "TOML Example",
|
||||||
"author": map[string]interface{}{
|
"author": map[string]any{
|
||||||
"e-mail": "fake@localhost",
|
"e-mail": "fake@localhost",
|
||||||
"github": "https://github.com/Unknown",
|
"github": "https://github.com/Unknown",
|
||||||
"name": "Unknown",
|
"name": "Unknown",
|
||||||
|
@ -789,28 +789,28 @@ func TestAllKeys(t *testing.T) {
|
||||||
},
|
},
|
||||||
"ppu": 0.55,
|
"ppu": 0.55,
|
||||||
"eyes": "brown",
|
"eyes": "brown",
|
||||||
"clothing": map[string]interface{}{
|
"clothing": map[string]any{
|
||||||
"trousers": "denim",
|
"trousers": "denim",
|
||||||
"jacket": "leather",
|
"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",
|
"import_path": "gopkg.in/ini.v1",
|
||||||
"name": "ini",
|
"name": "ini",
|
||||||
"version": "v1",
|
"version": "v1",
|
||||||
},
|
},
|
||||||
"id": "0001",
|
"id": "0001",
|
||||||
"batters": map[string]interface{}{
|
"batters": map[string]any{
|
||||||
"batter": []interface{}{
|
"batter": []any{
|
||||||
map[string]interface{}{"type": "Regular"},
|
map[string]any{"type": "Regular"},
|
||||||
map[string]interface{}{"type": "Chocolate"},
|
map[string]any{"type": "Chocolate"},
|
||||||
map[string]interface{}{"type": "Blueberry"},
|
map[string]any{"type": "Blueberry"},
|
||||||
map[string]interface{}{"type": "Devil's Food"},
|
map[string]any{"type": "Devil's Food"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"hacker": true,
|
"hacker": true,
|
||||||
"beard": true,
|
"beard": true,
|
||||||
"hobbies": []interface{}{
|
"hobbies": []any{
|
||||||
"skateboarding",
|
"skateboarding",
|
||||||
"snowboarding",
|
"snowboarding",
|
||||||
"go",
|
"go",
|
||||||
|
@ -822,13 +822,13 @@ func TestAllKeys(t *testing.T) {
|
||||||
"p_id": "0001",
|
"p_id": "0001",
|
||||||
"p_ppu": "0.55",
|
"p_ppu": "0.55",
|
||||||
"p_name": "Cake",
|
"p_name": "Cake",
|
||||||
"p_batters": map[string]interface{}{
|
"p_batters": map[string]any{
|
||||||
"batter": map[string]interface{}{"type": "Regular"},
|
"batter": map[string]any{"type": "Regular"},
|
||||||
},
|
},
|
||||||
"p_type": "donut",
|
"p_type": "donut",
|
||||||
"foos": []map[string]interface{}{
|
"foos": []map[string]any{
|
||||||
{
|
{
|
||||||
"foo": []map[string]interface{}{
|
"foo": []map[string]any{
|
||||||
{"key": 1},
|
{"key": 1},
|
||||||
{"key": 2},
|
{"key": 2},
|
||||||
{"key": 3},
|
{"key": 3},
|
||||||
|
@ -937,7 +937,7 @@ func TestUnmarshalWithDecoderOptions(t *testing.T) {
|
||||||
mapstructure.StringToTimeDurationHookFunc(),
|
mapstructure.StringToTimeDurationHookFunc(),
|
||||||
mapstructure.StringToSliceHookFunc(","),
|
mapstructure.StringToSliceHookFunc(","),
|
||||||
// Custom Decode Hook Function
|
// 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 {
|
if rf != reflect.String || rt != reflect.Map {
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
@ -1328,38 +1328,38 @@ func TestFindsNestedKeys(t *testing.T) {
|
||||||
initConfigs()
|
initConfigs()
|
||||||
dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
|
dob, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
|
||||||
|
|
||||||
Set("super", map[string]interface{}{
|
Set("super", map[string]any{
|
||||||
"deep": map[string]interface{}{
|
"deep": map[string]any{
|
||||||
"nested": "value",
|
"nested": "value",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
expected := map[string]interface{}{
|
expected := map[string]any{
|
||||||
"super": map[string]interface{}{
|
"super": map[string]any{
|
||||||
"deep": map[string]interface{}{
|
"deep": map[string]any{
|
||||||
"nested": "value",
|
"nested": "value",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"super.deep": map[string]interface{}{
|
"super.deep": map[string]any{
|
||||||
"nested": "value",
|
"nested": "value",
|
||||||
},
|
},
|
||||||
"super.deep.nested": "value",
|
"super.deep.nested": "value",
|
||||||
"owner.organization": "MongoDB",
|
"owner.organization": "MongoDB",
|
||||||
"batters.batter": []interface{}{
|
"batters.batter": []any{
|
||||||
map[string]interface{}{
|
map[string]any{
|
||||||
"type": "Regular",
|
"type": "Regular",
|
||||||
},
|
},
|
||||||
map[string]interface{}{
|
map[string]any{
|
||||||
"type": "Chocolate",
|
"type": "Chocolate",
|
||||||
},
|
},
|
||||||
map[string]interface{}{
|
map[string]any{
|
||||||
"type": "Blueberry",
|
"type": "Blueberry",
|
||||||
},
|
},
|
||||||
map[string]interface{}{
|
map[string]any{
|
||||||
"type": "Devil's Food",
|
"type": "Devil's Food",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"hobbies": []interface{}{
|
"hobbies": []any{
|
||||||
"skateboarding", "snowboarding", "go",
|
"skateboarding", "snowboarding", "go",
|
||||||
},
|
},
|
||||||
"TITLE_DOTENV": "DotEnv Example",
|
"TITLE_DOTENV": "DotEnv Example",
|
||||||
|
@ -1367,25 +1367,25 @@ func TestFindsNestedKeys(t *testing.T) {
|
||||||
"NAME_DOTENV": "Cake",
|
"NAME_DOTENV": "Cake",
|
||||||
"title": "TOML Example",
|
"title": "TOML Example",
|
||||||
"newkey": "remote",
|
"newkey": "remote",
|
||||||
"batters": map[string]interface{}{
|
"batters": map[string]any{
|
||||||
"batter": []interface{}{
|
"batter": []any{
|
||||||
map[string]interface{}{
|
map[string]any{
|
||||||
"type": "Regular",
|
"type": "Regular",
|
||||||
},
|
},
|
||||||
map[string]interface{}{
|
map[string]any{
|
||||||
"type": "Chocolate",
|
"type": "Chocolate",
|
||||||
},
|
},
|
||||||
map[string]interface{}{
|
map[string]any{
|
||||||
"type": "Blueberry",
|
"type": "Blueberry",
|
||||||
},
|
},
|
||||||
map[string]interface{}{
|
map[string]any{
|
||||||
"type": "Devil's Food",
|
"type": "Devil's Food",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"eyes": "brown",
|
"eyes": "brown",
|
||||||
"age": 35,
|
"age": 35,
|
||||||
"owner": map[string]interface{}{
|
"owner": map[string]any{
|
||||||
"organization": "MongoDB",
|
"organization": "MongoDB",
|
||||||
"bio": "MongoDB Chief Developer Advocate & Hacker at Large",
|
"bio": "MongoDB Chief Developer Advocate & Hacker at Large",
|
||||||
"dob": dob,
|
"dob": dob,
|
||||||
|
@ -1396,10 +1396,10 @@ func TestFindsNestedKeys(t *testing.T) {
|
||||||
"name": "Cake",
|
"name": "Cake",
|
||||||
"hacker": true,
|
"hacker": true,
|
||||||
"ppu": 0.55,
|
"ppu": 0.55,
|
||||||
"clothing": map[string]interface{}{
|
"clothing": map[string]any{
|
||||||
"jacket": "leather",
|
"jacket": "leather",
|
||||||
"trousers": "denim",
|
"trousers": "denim",
|
||||||
"pants": map[string]interface{}{
|
"pants": map[string]any{
|
||||||
"size": "large",
|
"size": "large",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1408,9 +1408,9 @@ func TestFindsNestedKeys(t *testing.T) {
|
||||||
"clothing.trousers": "denim",
|
"clothing.trousers": "denim",
|
||||||
"owner.dob": dob,
|
"owner.dob": dob,
|
||||||
"beard": true,
|
"beard": true,
|
||||||
"foos": []map[string]interface{}{
|
"foos": []map[string]any{
|
||||||
{
|
{
|
||||||
"foo": []map[string]interface{}{
|
"foo": []map[string]any{
|
||||||
{
|
{
|
||||||
"key": 1,
|
"key": 1,
|
||||||
},
|
},
|
||||||
|
@ -1444,8 +1444,8 @@ func TestReadBufConfig(t *testing.T) {
|
||||||
assert.False(t, v.InConfig("state"))
|
assert.False(t, v.InConfig("state"))
|
||||||
assert.False(t, v.InConfig("clothing.hat"))
|
assert.False(t, v.InConfig("clothing.hat"))
|
||||||
assert.Equal(t, "steve", v.Get("name"))
|
assert.Equal(t, "steve", v.Get("name"))
|
||||||
assert.Equal(t, []interface{}{"skateboarding", "snowboarding", "go"}, v.Get("hobbies"))
|
assert.Equal(t, []any{"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, map[string]any{"jacket": "leather", "trousers": "denim", "pants": map[string]any{"size": "large"}}, v.Get("clothing"))
|
||||||
assert.Equal(t, 35, v.Get("age"))
|
assert.Equal(t, 35, v.Get("age"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2180,11 +2180,11 @@ func TestMergeConfigMap(t *testing.T) {
|
||||||
|
|
||||||
assert(37890)
|
assert(37890)
|
||||||
|
|
||||||
update := map[string]interface{}{
|
update := map[string]any{
|
||||||
"Hello": map[string]interface{}{
|
"Hello": map[string]any{
|
||||||
"Pop": 1234,
|
"Pop": 1234,
|
||||||
},
|
},
|
||||||
"World": map[interface{}]interface{}{
|
"World": map[any]any{
|
||||||
"Rock": 345,
|
"Rock": 345,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -2255,7 +2255,7 @@ clothing:
|
||||||
assert.Nil(t, Get("clothing.jacket.price"))
|
assert.Nil(t, Get("clothing.jacket.price"))
|
||||||
assert.Equal(t, polyester, GetString("clothing.shirt"))
|
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, "leather", clothingSettings["jacket"])
|
||||||
assert.Equal(t, polyester, clothingSettings["shirt"])
|
assert.Equal(t, polyester, clothingSettings["shirt"])
|
||||||
}
|
}
|
||||||
|
@ -2267,7 +2267,7 @@ func TestDotParameter(t *testing.T) {
|
||||||
unmarshalReader(r, v.config)
|
unmarshalReader(r, v.config)
|
||||||
|
|
||||||
actual := Get("batters.batter")
|
actual := Get("batters.batter")
|
||||||
expected := []interface{}{map[string]interface{}{"type": "Small"}}
|
expected := []any{map[string]any{"type": "Small"}}
|
||||||
assert.Equal(t, expected, actual)
|
assert.Equal(t, expected, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2318,17 +2318,17 @@ R = 6
|
||||||
|
|
||||||
func TestCaseInsensitiveSet(t *testing.T) {
|
func TestCaseInsensitiveSet(t *testing.T) {
|
||||||
Reset()
|
Reset()
|
||||||
m1 := map[string]interface{}{
|
m1 := map[string]any{
|
||||||
"Foo": 32,
|
"Foo": 32,
|
||||||
"Bar": map[interface{}]interface{}{
|
"Bar": map[any]any{
|
||||||
"ABc": "A",
|
"ABc": "A",
|
||||||
"cDE": "B",
|
"cDE": "B",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
m2 := map[string]interface{}{
|
m2 := map[string]any{
|
||||||
"Foo": 52,
|
"Foo": 52,
|
||||||
"Bar": map[interface{}]interface{}{
|
"Bar": map[any]any{
|
||||||
"bCd": "A",
|
"bCd": "A",
|
||||||
"eFG": "B",
|
"eFG": "B",
|
||||||
},
|
},
|
||||||
|
@ -2559,13 +2559,13 @@ func TestKeyDelimiter(t *testing.T) {
|
||||||
err := v.unmarshalReader(r, v.config)
|
err := v.unmarshalReader(r, v.config)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
values := map[string]interface{}{
|
values := map[string]any{
|
||||||
"image": map[string]interface{}{
|
"image": map[string]any{
|
||||||
"repository": "someImage",
|
"repository": "someImage",
|
||||||
"tag": "1.0.0",
|
"tag": "1.0.0",
|
||||||
},
|
},
|
||||||
"ingress": map[string]interface{}{
|
"ingress": map[string]any{
|
||||||
"annotations": map[string]interface{}{
|
"annotations": map[string]any{
|
||||||
"traefik.frontend.rule.type": "PathPrefix",
|
"traefik.frontend.rule.type": "PathPrefix",
|
||||||
"traefik.ingress.kubernetes.io/ssl-redirect": "true",
|
"traefik.ingress.kubernetes.io/ssl-redirect": "true",
|
||||||
},
|
},
|
||||||
|
@ -2579,13 +2579,13 @@ func TestKeyDelimiter(t *testing.T) {
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
Charts struct {
|
Charts struct {
|
||||||
Values map[string]interface{}
|
Values map[string]any
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := config{
|
expected := config{
|
||||||
Charts: struct {
|
Charts: struct {
|
||||||
Values map[string]interface{}
|
Values map[string]any
|
||||||
}{
|
}{
|
||||||
Values: values,
|
Values: values,
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue