summaryrefslogtreecommitdiff
path: root/vendor/github.com/spf13
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/spf13')
-rw-r--r--vendor/github.com/spf13/afero/.editorconfig12
-rw-r--r--vendor/github.com/spf13/afero/.golangci.yaml18
-rw-r--r--vendor/github.com/spf13/afero/README.md2
-rw-r--r--vendor/github.com/spf13/afero/iofs.go1
-rw-r--r--vendor/github.com/spf13/afero/memmap.go2
-rw-r--r--vendor/github.com/spf13/cast/README.md2
-rw-r--r--vendor/github.com/spf13/cast/caste.go98
-rw-r--r--vendor/github.com/spf13/viper/.golangci.yaml3
-rw-r--r--vendor/github.com/spf13/viper/README.md21
-rw-r--r--vendor/github.com/spf13/viper/UPDATES.md126
-rw-r--r--vendor/github.com/spf13/viper/encoding.go181
-rw-r--r--vendor/github.com/spf13/viper/experimental.go8
-rw-r--r--vendor/github.com/spf13/viper/file.go54
-rw-r--r--vendor/github.com/spf13/viper/file_finder.go38
-rw-r--r--vendor/github.com/spf13/viper/finder.go55
-rw-r--r--vendor/github.com/spf13/viper/flake.lock303
-rw-r--r--vendor/github.com/spf13/viper/flake.nix2
-rw-r--r--vendor/github.com/spf13/viper/internal/encoding/decoder.go61
-rw-r--r--vendor/github.com/spf13/viper/internal/encoding/encoder.go60
-rw-r--r--vendor/github.com/spf13/viper/internal/encoding/error.go7
-rw-r--r--vendor/github.com/spf13/viper/internal/encoding/hcl/codec.go40
-rw-r--r--vendor/github.com/spf13/viper/internal/encoding/ini/codec.go99
-rw-r--r--vendor/github.com/spf13/viper/internal/encoding/ini/map_utils.go74
-rw-r--r--vendor/github.com/spf13/viper/internal/encoding/javaproperties/codec.go86
-rw-r--r--vendor/github.com/spf13/viper/internal/encoding/javaproperties/map_utils.go74
-rw-r--r--vendor/github.com/spf13/viper/internal/features/finder.go5
-rw-r--r--vendor/github.com/spf13/viper/internal/features/finder_default.go5
-rw-r--r--vendor/github.com/spf13/viper/logger.go39
-rw-r--r--vendor/github.com/spf13/viper/remote.go256
-rw-r--r--vendor/github.com/spf13/viper/util.go11
-rw-r--r--vendor/github.com/spf13/viper/viper.go539
31 files changed, 1199 insertions, 1083 deletions
diff --git a/vendor/github.com/spf13/afero/.editorconfig b/vendor/github.com/spf13/afero/.editorconfig
new file mode 100644
index 000000000..4492e9f9f
--- /dev/null
+++ b/vendor/github.com/spf13/afero/.editorconfig
@@ -0,0 +1,12 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+indent_size = 4
+indent_style = space
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.go]
+indent_style = tab
diff --git a/vendor/github.com/spf13/afero/.golangci.yaml b/vendor/github.com/spf13/afero/.golangci.yaml
new file mode 100644
index 000000000..806289a25
--- /dev/null
+++ b/vendor/github.com/spf13/afero/.golangci.yaml
@@ -0,0 +1,18 @@
+linters-settings:
+ gci:
+ sections:
+ - standard
+ - default
+ - prefix(github.com/spf13/afero)
+
+linters:
+ disable-all: true
+ enable:
+ - gci
+ - gofmt
+ - gofumpt
+ - staticcheck
+
+issues:
+ exclude-dirs:
+ - gcsfs/internal/stiface
diff --git a/vendor/github.com/spf13/afero/README.md b/vendor/github.com/spf13/afero/README.md
index 3bafbfdfc..619af574f 100644
--- a/vendor/github.com/spf13/afero/README.md
+++ b/vendor/github.com/spf13/afero/README.md
@@ -12,7 +12,7 @@ types and methods. Afero has an exceptionally clean interface and simple design
without needless constructors or initialization methods.
Afero is also a library providing a base set of interoperable backend
-filesystems that make it easy to work with afero while retaining all the power
+filesystems that make it easy to work with, while retaining all the power
and benefit of the os and ioutil packages.
Afero provides significant improvements over using the os package alone, most
diff --git a/vendor/github.com/spf13/afero/iofs.go b/vendor/github.com/spf13/afero/iofs.go
index 938b9316e..b13155ca4 100644
--- a/vendor/github.com/spf13/afero/iofs.go
+++ b/vendor/github.com/spf13/afero/iofs.go
@@ -255,7 +255,6 @@ func (f fromIOFSFile) Readdir(count int) ([]os.FileInfo, error) {
ret := make([]os.FileInfo, len(entries))
for i := range entries {
ret[i], err = entries[i].Info()
-
if err != nil {
return nil, err
}
diff --git a/vendor/github.com/spf13/afero/memmap.go b/vendor/github.com/spf13/afero/memmap.go
index d6c744e8d..ed92f5649 100644
--- a/vendor/github.com/spf13/afero/memmap.go
+++ b/vendor/github.com/spf13/afero/memmap.go
@@ -16,11 +16,9 @@ package afero
import (
"fmt"
"io"
-
"log"
"os"
"path/filepath"
-
"sort"
"strings"
"sync"
diff --git a/vendor/github.com/spf13/cast/README.md b/vendor/github.com/spf13/cast/README.md
index 0e9e14593..1be666a45 100644
--- a/vendor/github.com/spf13/cast/README.md
+++ b/vendor/github.com/spf13/cast/README.md
@@ -1,6 +1,6 @@
# cast
-[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/spf13/cast/ci.yaml?branch=master&style=flat-square)](https://github.com/spf13/cast/actions/workflows/ci.yaml)
+[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/spf13/cast/test.yaml?branch=master&style=flat-square)](https://github.com/spf13/cast/actions/workflows/test.yaml)
[![PkgGoDev](https://pkg.go.dev/badge/mod/github.com/spf13/cast)](https://pkg.go.dev/mod/github.com/spf13/cast)
![Go Version](https://img.shields.io/badge/go%20version-%3E=1.16-61CFDD.svg?style=flat-square)
[![Go Report Card](https://goreportcard.com/badge/github.com/spf13/cast?style=flat-square)](https://goreportcard.com/report/github.com/spf13/cast)
diff --git a/vendor/github.com/spf13/cast/caste.go b/vendor/github.com/spf13/cast/caste.go
index d49bbf83e..4181a2e75 100644
--- a/vendor/github.com/spf13/cast/caste.go
+++ b/vendor/github.com/spf13/cast/caste.go
@@ -18,6 +18,14 @@ import (
var errNegativeNotAllowed = errors.New("unable to cast negative value")
+type float64EProvider interface {
+ Float64() (float64, error)
+}
+
+type float64Provider interface {
+ Float64() float64
+}
+
// ToTimeE casts an interface to a time.Time type.
func ToTimeE(i interface{}) (tim time.Time, err error) {
return ToTimeInDefaultLocationE(i, time.UTC)
@@ -77,11 +85,14 @@ func ToDurationE(i interface{}) (d time.Duration, err error) {
d, err = time.ParseDuration(s + "ns")
}
return
- case json.Number:
+ case float64EProvider:
var v float64
v, err = s.Float64()
d = time.Duration(v)
return
+ case float64Provider:
+ d = time.Duration(s.Float64())
+ return
default:
err = fmt.Errorf("unable to cast %#v of type %T to Duration", i, i)
return
@@ -174,12 +185,14 @@ func ToFloat64E(i interface{}) (float64, error) {
return v, nil
}
return 0, fmt.Errorf("unable to cast %#v of type %T to float64", i, i)
- case json.Number:
+ case float64EProvider:
v, err := s.Float64()
if err == nil {
return v, nil
}
return 0, fmt.Errorf("unable to cast %#v of type %T to float64", i, i)
+ case float64Provider:
+ return s.Float64(), nil
case bool:
if s {
return 1, nil
@@ -230,12 +243,14 @@ func ToFloat32E(i interface{}) (float32, error) {
return float32(v), nil
}
return 0, fmt.Errorf("unable to cast %#v of type %T to float32", i, i)
- case json.Number:
+ case float64EProvider:
v, err := s.Float64()
if err == nil {
return float32(v), nil
}
return 0, fmt.Errorf("unable to cast %#v of type %T to float32", i, i)
+ case float64Provider:
+ return float32(s.Float64()), nil
case bool:
if s {
return 1, nil
@@ -598,12 +613,12 @@ func ToUint64E(i interface{}) (uint64, error) {
switch s := i.(type) {
case string:
- v, err := strconv.ParseInt(trimZeroDecimal(s), 0, 0)
+ v, err := strconv.ParseUint(trimZeroDecimal(s), 0, 0)
if err == nil {
if v < 0 {
return 0, errNegativeNotAllowed
}
- return uint64(v), nil
+ return v, nil
}
return 0, fmt.Errorf("unable to cast %#v of type %T to uint64", i, i)
case json.Number:
@@ -917,8 +932,8 @@ func indirectToStringerOrError(a interface{}) interface{} {
return nil
}
- var errorType = reflect.TypeOf((*error)(nil)).Elem()
- var fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
+ errorType := reflect.TypeOf((*error)(nil)).Elem()
+ fmtStringerType := reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
v := reflect.ValueOf(a)
for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Ptr && !v.IsNil() {
@@ -987,7 +1002,7 @@ func ToStringE(i interface{}) (string, error) {
// ToStringMapStringE casts an interface to a map[string]string type.
func ToStringMapStringE(i interface{}) (map[string]string, error) {
- var m = map[string]string{}
+ m := map[string]string{}
switch v := i.(type) {
case map[string]string:
@@ -1017,7 +1032,7 @@ func ToStringMapStringE(i interface{}) (map[string]string, error) {
// ToStringMapStringSliceE casts an interface to a map[string][]string type.
func ToStringMapStringSliceE(i interface{}) (map[string][]string, error) {
- var m = map[string][]string{}
+ m := map[string][]string{}
switch v := i.(type) {
case map[string][]string:
@@ -1081,7 +1096,7 @@ func ToStringMapStringSliceE(i interface{}) (map[string][]string, error) {
// ToStringMapBoolE casts an interface to a map[string]bool type.
func ToStringMapBoolE(i interface{}) (map[string]bool, error) {
- var m = map[string]bool{}
+ m := map[string]bool{}
switch v := i.(type) {
case map[interface{}]interface{}:
@@ -1106,7 +1121,7 @@ func ToStringMapBoolE(i interface{}) (map[string]bool, error) {
// ToStringMapE casts an interface to a map[string]interface{} type.
func ToStringMapE(i interface{}) (map[string]interface{}, error) {
- var m = map[string]interface{}{}
+ m := map[string]interface{}{}
switch v := i.(type) {
case map[interface{}]interface{}:
@@ -1126,7 +1141,7 @@ func ToStringMapE(i interface{}) (map[string]interface{}, error) {
// ToStringMapIntE casts an interface to a map[string]int{} type.
func ToStringMapIntE(i interface{}) (map[string]int, error) {
- var m = map[string]int{}
+ m := map[string]int{}
if i == nil {
return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int", i, i)
}
@@ -1167,7 +1182,7 @@ func ToStringMapIntE(i interface{}) (map[string]int, error) {
// ToStringMapInt64E casts an interface to a map[string]int64{} type.
func ToStringMapInt64E(i interface{}) (map[string]int64, error) {
- var m = map[string]int64{}
+ m := map[string]int64{}
if i == nil {
return m, fmt.Errorf("unable to cast %#v of type %T to map[string]int64", i, i)
}
@@ -1404,38 +1419,35 @@ func (f timeFormat) hasTimezone() bool {
return f.typ >= timeFormatNumericTimezone && f.typ <= timeFormatNumericAndNamedTimezone
}
-var (
- timeFormats = []timeFormat{
- // Keep common formats at the top.
- {"2006-01-02", timeFormatNoTimezone},
- {time.RFC3339, timeFormatNumericTimezone},
- {"2006-01-02T15:04:05", timeFormatNoTimezone}, // iso8601 without timezone
- {time.RFC1123Z, timeFormatNumericTimezone},
- {time.RFC1123, timeFormatNamedTimezone},
- {time.RFC822Z, timeFormatNumericTimezone},
- {time.RFC822, timeFormatNamedTimezone},
- {time.RFC850, timeFormatNamedTimezone},
- {"2006-01-02 15:04:05.999999999 -0700 MST", timeFormatNumericAndNamedTimezone}, // Time.String()
- {"2006-01-02T15:04:05-0700", timeFormatNumericTimezone}, // RFC3339 without timezone hh:mm colon
- {"2006-01-02 15:04:05Z0700", timeFormatNumericTimezone}, // RFC3339 without T or timezone hh:mm colon
- {"2006-01-02 15:04:05", timeFormatNoTimezone},
- {time.ANSIC, timeFormatNoTimezone},
- {time.UnixDate, timeFormatNamedTimezone},
- {time.RubyDate, timeFormatNumericTimezone},
- {"2006-01-02 15:04:05Z07:00", timeFormatNumericTimezone},
- {"02 Jan 2006", timeFormatNoTimezone},
- {"2006-01-02 15:04:05 -07:00", timeFormatNumericTimezone},
- {"2006-01-02 15:04:05 -0700", timeFormatNumericTimezone},
- {time.Kitchen, timeFormatTimeOnly},
- {time.Stamp, timeFormatTimeOnly},
- {time.StampMilli, timeFormatTimeOnly},
- {time.StampMicro, timeFormatTimeOnly},
- {time.StampNano, timeFormatTimeOnly},
- }
-)
+var timeFormats = []timeFormat{
+ // Keep common formats at the top.
+ {"2006-01-02", timeFormatNoTimezone},
+ {time.RFC3339, timeFormatNumericTimezone},
+ {"2006-01-02T15:04:05", timeFormatNoTimezone}, // iso8601 without timezone
+ {time.RFC1123Z, timeFormatNumericTimezone},
+ {time.RFC1123, timeFormatNamedTimezone},
+ {time.RFC822Z, timeFormatNumericTimezone},
+ {time.RFC822, timeFormatNamedTimezone},
+ {time.RFC850, timeFormatNamedTimezone},
+ {"2006-01-02 15:04:05.999999999 -0700 MST", timeFormatNumericAndNamedTimezone}, // Time.String()
+ {"2006-01-02T15:04:05-0700", timeFormatNumericTimezone}, // RFC3339 without timezone hh:mm colon
+ {"2006-01-02 15:04:05Z0700", timeFormatNumericTimezone}, // RFC3339 without T or timezone hh:mm colon
+ {"2006-01-02 15:04:05", timeFormatNoTimezone},
+ {time.ANSIC, timeFormatNoTimezone},
+ {time.UnixDate, timeFormatNamedTimezone},
+ {time.RubyDate, timeFormatNumericTimezone},
+ {"2006-01-02 15:04:05Z07:00", timeFormatNumericTimezone},
+ {"02 Jan 2006", timeFormatNoTimezone},
+ {"2006-01-02 15:04:05 -07:00", timeFormatNumericTimezone},
+ {"2006-01-02 15:04:05 -0700", timeFormatNumericTimezone},
+ {time.Kitchen, timeFormatTimeOnly},
+ {time.Stamp, timeFormatTimeOnly},
+ {time.StampMilli, timeFormatTimeOnly},
+ {time.StampMicro, timeFormatTimeOnly},
+ {time.StampNano, timeFormatTimeOnly},
+}
func parseDateWith(s string, location *time.Location, formats []timeFormat) (d time.Time, e error) {
-
for _, format := range formats {
if d, e = time.Parse(format.format, s); e == nil {
diff --git a/vendor/github.com/spf13/viper/.golangci.yaml b/vendor/github.com/spf13/viper/.golangci.yaml
index 1faeae42c..474f41633 100644
--- a/vendor/github.com/spf13/viper/.golangci.yaml
+++ b/vendor/github.com/spf13/viper/.golangci.yaml
@@ -17,8 +17,6 @@ linters-settings:
disabled-checks:
- importShadow
- unnamedResult
- golint:
- min-confidence: 0
goimports:
local-prefixes: github.com/spf13/viper
@@ -30,7 +28,6 @@ linters:
- dupl
- durationcheck
- exhaustive
- - exportloopref
- gci
- gocritic
- godot
diff --git a/vendor/github.com/spf13/viper/README.md b/vendor/github.com/spf13/viper/README.md
index 3fc7d84f1..769a5d900 100644
--- a/vendor/github.com/spf13/viper/README.md
+++ b/vendor/github.com/spf13/viper/README.md
@@ -3,7 +3,8 @@
>
> **Thank you!**
-![Viper](.github/logo.png?raw=true)
+![viper logo](https://github.com/user-attachments/assets/acae9193-2974-41f3-808d-2d433f5ada5e)
+
[![Mentioned in Awesome Go](https://awesome.re/mentioned-badge-flat.svg)](https://github.com/avelino/awesome-go#configuration)
[![run on repl.it](https://repl.it/badge/github/sagikazarmark/Viper-example)](https://repl.it/@sagikazarmark/Viper-example#main.go)
@@ -11,7 +12,7 @@
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/spf13/viper/ci.yaml?branch=master&style=flat-square)](https://github.com/spf13/viper/actions?query=workflow%3ACI)
[![Join the chat at https://gitter.im/spf13/viper](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/spf13/viper?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Go Report Card](https://goreportcard.com/badge/github.com/spf13/viper?style=flat-square)](https://goreportcard.com/report/github.com/spf13/viper)
-![Go Version](https://img.shields.io/badge/go%20version-%3E=1.20-61CFDD.svg?style=flat-square)
+![Go Version](https://img.shields.io/badge/go%20version-%3E=1.21-61CFDD.svg?style=flat-square)
[![PkgGoDev](https://pkg.go.dev/badge/mod/github.com/spf13/viper)](https://pkg.go.dev/mod/github.com/spf13/viper)
**Go configuration with fangs!**
@@ -802,7 +803,7 @@ if err != nil {
}
```
-Viper uses [github.com/mitchellh/mapstructure](https://github.com/mitchellh/mapstructure) under the hood for unmarshaling values which uses `mapstructure` tags by default.
+Viper uses [github.com/go-viper/mapstructure](https://github.com/go-viper/mapstructure) under the hood for unmarshaling values which uses `mapstructure` tags by default.
### Decoding custom formats
@@ -836,13 +837,15 @@ func yamlStringSettings() string {
## Viper or Vipers?
-Viper comes ready to use out of the box. There is no configuration or
-initialization needed to begin using Viper. Since most applications will want
-to use a single central repository for their configuration, the viper package
-provides this. It is similar to a singleton.
+Viper comes with a global instance (singleton) out of the box.
+
+Although it makes setting up configuration easy,
+using it is generally discouraged as it makes testing harder and can lead to unexpected behavior.
+
+The best practice is to initialize a Viper instance and pass that around when necessary.
-In all of the examples above, they demonstrate using viper in its singleton
-style approach.
+The global instance _MAY_ be deprecated in the future.
+See [#1855](https://github.com/spf13/viper/issues/1855) for more details.
### Working with multiple vipers
diff --git a/vendor/github.com/spf13/viper/UPDATES.md b/vendor/github.com/spf13/viper/UPDATES.md
new file mode 100644
index 000000000..ccf413ed7
--- /dev/null
+++ b/vendor/github.com/spf13/viper/UPDATES.md
@@ -0,0 +1,126 @@
+# Update Log
+
+**This document details any major updates required to use new features or improvements in Viper.**
+
+## v1.20.x
+
+### New file searching API
+
+Viper now includes a new file searching API that allows users to customize how Viper looks for config files.
+
+Viper accepts a custom [`Finder`](https://pkg.go.dev/github.com/spf13/viper#Finder) interface implementation:
+
+```go
+// Finder looks for files and directories in an [afero.Fs] filesystem.
+type Finder interface {
+ Find(fsys afero.Fs) ([]string, error)
+}
+```
+
+It is supposed to return a list of paths to config files.
+
+The default implementation uses [github.com/sagikazarmark/locafero](https://github.com/sagikazarmark/locafero) under the hood.
+
+You can supply your own implementation using `WithFinder`:
+
+```go
+v := viper.NewWithOptions(
+ viper.WithFinder(&MyFinder{}),
+)
+```
+
+For more information, check out the [Finder examples](https://pkg.go.dev/github.com/spf13/viper#Finder)
+and the [documentation](https://pkg.go.dev/github.com/sagikazarmark/locafero) for the locafero package.
+
+### New encoding API
+
+Viper now allows customizing the encoding layer by providing an API for encoding and decoding configuration data:
+
+```go
+// Encoder encodes Viper's internal data structures into a byte representation.
+// It's primarily used for encoding a map[string]any into a file format.
+type Encoder interface {
+ Encode(v map[string]any) ([]byte, error)
+}
+
+// Decoder decodes the contents of a byte slice into Viper's internal data structures.
+// It's primarily used for decoding contents of a file into a map[string]any.
+type Decoder interface {
+ Decode(b []byte, v map[string]any) error
+}
+
+// Codec combines [Encoder] and [Decoder] interfaces.
+type Codec interface {
+ Encoder
+ Decoder
+}
+```
+
+By default, Viper includes the following codecs:
+
+- JSON
+- TOML
+- YAML
+- Dotenv
+
+The rest of the codecs are moved to [github.com/go-viper/encoding](https://github.com/go-viper/encoding)
+
+Customizing the encoding layer is possible by providing a custom registry of codecs:
+
+- [Encoder](https://pkg.go.dev/github.com/spf13/viper#Encoder) -> [EncoderRegistry](https://pkg.go.dev/github.com/spf13/viper#EncoderRegistry)
+- [Decoder](https://pkg.go.dev/github.com/spf13/viper#Decoder) -> [DecoderRegistry](https://pkg.go.dev/github.com/spf13/viper#DecoderRegistry)
+- [Codec](https://pkg.go.dev/github.com/spf13/viper#Codec) -> [CodecRegistry](https://pkg.go.dev/github.com/spf13/viper#CodecRegistry)
+
+You can supply the registry of codecs to Viper using the appropriate `With*Registry` function:
+
+```go
+codecRegistry := viper.NewCodecRegistry()
+
+codecRegistry.RegisterCodec("myformat", &MyCodec{})
+
+v := viper.NewWithOptions(
+ viper.WithCodecRegistry(codecRegistry),
+)
+```
+
+### BREAKING: HCL, Java properties, INI removed from core
+
+In order to reduce third-party dependencies, Viper dropped support for the following formats from the core:
+
+- HCL
+- Java properties
+- INI
+
+You can still use these formats though by importing them from [github.com/go-viper/encoding](https://github.com/go-viper/encoding):
+
+```go
+import (
+ "github.com/go-viper/encoding/hcl"
+ "github.com/go-viper/encoding/javaproperties"
+ "github.com/go-viper/encoding/ini"
+)
+
+codecRegistry := viper.NewCodecRegistry()
+
+{
+ codec := hcl.Codec{}
+
+ codecRegistry.RegisterCodec("hcl", codec)
+ codecRegistry.RegisterCodec("tfvars", codec)
+
+}
+
+{
+ codec := &javaproperties.Codec{}
+
+ codecRegistry.RegisterCodec("properties", codec)
+ codecRegistry.RegisterCodec("props", codec)
+ codecRegistry.RegisterCodec("prop", codec)
+}
+
+codecRegistry.RegisterCodec("ini", ini.Codec{})
+
+v := viper.NewWithOptions(
+ viper.WithCodecRegistry(codecRegistry),
+)
+```
diff --git a/vendor/github.com/spf13/viper/encoding.go b/vendor/github.com/spf13/viper/encoding.go
new file mode 100644
index 000000000..a7da55860
--- /dev/null
+++ b/vendor/github.com/spf13/viper/encoding.go
@@ -0,0 +1,181 @@
+package viper
+
+import (
+ "errors"
+ "strings"
+ "sync"
+
+ "github.com/spf13/viper/internal/encoding/dotenv"
+ "github.com/spf13/viper/internal/encoding/json"
+ "github.com/spf13/viper/internal/encoding/toml"
+ "github.com/spf13/viper/internal/encoding/yaml"
+)
+
+// Encoder encodes Viper's internal data structures into a byte representation.
+// It's primarily used for encoding a map[string]any into a file format.
+type Encoder interface {
+ Encode(v map[string]any) ([]byte, error)
+}
+
+// Decoder decodes the contents of a byte slice into Viper's internal data structures.
+// It's primarily used for decoding contents of a file into a map[string]any.
+type Decoder interface {
+ Decode(b []byte, v map[string]any) error
+}
+
+// Codec combines [Encoder] and [Decoder] interfaces.
+type Codec interface {
+ Encoder
+ Decoder
+}
+
+// TODO: consider adding specific errors for not found scenarios
+
+// EncoderRegistry returns an [Encoder] for a given format.
+//
+// Format is case-insensitive.
+//
+// [EncoderRegistry] returns an error if no [Encoder] is registered for the format.
+type EncoderRegistry interface {
+ Encoder(format string) (Encoder, error)
+}
+
+// DecoderRegistry returns an [Decoder] for a given format.
+//
+// Format is case-insensitive.
+//
+// [DecoderRegistry] returns an error if no [Decoder] is registered for the format.
+type DecoderRegistry interface {
+ Decoder(format string) (Decoder, error)
+}
+
+// [CodecRegistry] combines [EncoderRegistry] and [DecoderRegistry] interfaces.
+type CodecRegistry interface {
+ EncoderRegistry
+ DecoderRegistry
+}
+
+// WithEncoderRegistry sets a custom [EncoderRegistry].
+func WithEncoderRegistry(r EncoderRegistry) Option {
+ return optionFunc(func(v *Viper) {
+ if r == nil {
+ return
+ }
+
+ v.encoderRegistry = r
+ })
+}
+
+// WithDecoderRegistry sets a custom [DecoderRegistry].
+func WithDecoderRegistry(r DecoderRegistry) Option {
+ return optionFunc(func(v *Viper) {
+ if r == nil {
+ return
+ }
+
+ v.decoderRegistry = r
+ })
+}
+
+// WithCodecRegistry sets a custom [EncoderRegistry] and [DecoderRegistry].
+func WithCodecRegistry(r CodecRegistry) Option {
+ return optionFunc(func(v *Viper) {
+ if r == nil {
+ return
+ }
+
+ v.encoderRegistry = r
+ v.decoderRegistry = r
+ })
+}
+
+// DefaultCodecRegistry is a simple implementation of [CodecRegistry] that allows registering custom [Codec]s.
+type DefaultCodecRegistry struct {
+ codecs map[string]Codec
+
+ mu sync.RWMutex
+ once sync.Once
+}
+
+// NewCodecRegistry returns a new [CodecRegistry], ready to accept custom [Codec]s.
+func NewCodecRegistry() *DefaultCodecRegistry {
+ r := &DefaultCodecRegistry{}
+
+ r.init()
+
+ return r
+}
+
+func (r *DefaultCodecRegistry) init() {
+ r.once.Do(func() {
+ r.codecs = map[string]Codec{}
+ })
+}
+
+// RegisterCodec registers a custom [Codec].
+//
+// Format is case-insensitive.
+func (r *DefaultCodecRegistry) RegisterCodec(format string, codec Codec) error {
+ r.init()
+
+ r.mu.Lock()
+ defer r.mu.Unlock()
+
+ r.codecs[strings.ToLower(format)] = codec
+
+ return nil
+}
+
+// Encoder implements the [EncoderRegistry] interface.
+//
+// Format is case-insensitive.
+func (r *DefaultCodecRegistry) Encoder(format string) (Encoder, error) {
+ encoder, ok := r.codec(format)
+ if !ok {
+ return nil, errors.New("encoder not found for this format")
+ }
+
+ return encoder, nil
+}
+
+// Decoder implements the [DecoderRegistry] interface.
+//
+// Format is case-insensitive.
+func (r *DefaultCodecRegistry) Decoder(format string) (Decoder, error) {
+ decoder, ok := r.codec(format)
+ if !ok {
+ return nil, errors.New("decoder not found for this format")
+ }
+
+ return decoder, nil
+}
+
+func (r *DefaultCodecRegistry) codec(format string) (Codec, bool) {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+
+ format = strings.ToLower(format)
+
+ if r.codecs != nil {
+ codec, ok := r.codecs[format]
+ if ok {
+ return codec, true
+ }
+ }
+
+ switch format {
+ case "yaml", "yml":
+ return yaml.Codec{}, true
+
+ case "json":
+ return json.Codec{}, true
+
+ case "toml":
+ return toml.Codec{}, true
+
+ case "dotenv", "env":
+ return &dotenv.Codec{}, true
+ }
+
+ return nil, false
+}
diff --git a/vendor/github.com/spf13/viper/experimental.go b/vendor/github.com/spf13/viper/experimental.go
new file mode 100644
index 000000000..6e19e8a10
--- /dev/null
+++ b/vendor/github.com/spf13/viper/experimental.go
@@ -0,0 +1,8 @@
+package viper
+
+// ExperimentalBindStruct tells Viper to use the new bind struct feature.
+func ExperimentalBindStruct() Option {
+ return optionFunc(func(v *Viper) {
+ v.experimentalBindStruct = true
+ })
+}
diff --git a/vendor/github.com/spf13/viper/file.go b/vendor/github.com/spf13/viper/file.go
index a54fe5a7a..50a40581d 100644
--- a/vendor/github.com/spf13/viper/file.go
+++ b/vendor/github.com/spf13/viper/file.go
@@ -1,5 +1,3 @@
-//go:build !finder
-
package viper
import (
@@ -7,12 +5,62 @@ import (
"os"
"path/filepath"
+ "github.com/sagikazarmark/locafero"
"github.com/spf13/afero"
)
+// ExperimentalFinder tells Viper to use the new Finder interface for finding configuration files.
+func ExperimentalFinder() Option {
+ return optionFunc(func(v *Viper) {
+ v.experimentalFinder = true
+ })
+}
+
+// Search for a config file.
+func (v *Viper) findConfigFile() (string, error) {
+ finder := v.finder
+
+ if finder == nil && v.experimentalFinder {
+ var names []string
+
+ if v.configType != "" {
+ names = locafero.NameWithOptionalExtensions(v.configName, SupportedExts...)
+ } else {
+ names = locafero.NameWithExtensions(v.configName, SupportedExts...)
+ }
+
+ finder = locafero.Finder{
+ Paths: v.configPaths,
+ Names: names,
+ Type: locafero.FileTypeFile,
+ }
+ }
+
+ if finder != nil {
+ return v.findConfigFileWithFinder(finder)
+ }
+
+ return v.findConfigFileOld()
+}
+
+func (v *Viper) findConfigFileWithFinder(finder Finder) (string, error) {
+ results, err := finder.Find(v.fs)
+ if err != nil {
+ return "", err
+ }
+
+ if len(results) == 0 {
+ return "", ConfigFileNotFoundError{v.configName, fmt.Sprintf("%s", v.configPaths)}
+ }
+
+ // We call clean on the final result to ensure that the path is in its canonical form.
+ // This is mostly for consistent path handling and to make sure tests pass.
+ return results[0], nil
+}
+
// Search all configPaths for any config file.
// Returns the first path that exists (and is a config file).
-func (v *Viper) findConfigFile() (string, error) {
+func (v *Viper) findConfigFileOld() (string, error) {
v.logger.Info("searching for config in paths", "paths", v.configPaths)
for _, cp := range v.configPaths {
diff --git a/vendor/github.com/spf13/viper/file_finder.go b/vendor/github.com/spf13/viper/file_finder.go
deleted file mode 100644
index d96a1bd22..000000000
--- a/vendor/github.com/spf13/viper/file_finder.go
+++ /dev/null
@@ -1,38 +0,0 @@
-//go:build finder
-
-package viper
-
-import (
- "fmt"
-
- "github.com/sagikazarmark/locafero"
-)
-
-// Search all configPaths for any config file.
-// Returns the first path that exists (and is a config file).
-func (v *Viper) findConfigFile() (string, error) {
- var names []string
-
- if v.configType != "" {
- names = locafero.NameWithOptionalExtensions(v.configName, SupportedExts...)
- } else {
- names = locafero.NameWithExtensions(v.configName, SupportedExts...)
- }
-
- finder := locafero.Finder{
- Paths: v.configPaths,
- Names: names,
- Type: locafero.FileTypeFile,
- }
-
- results, err := finder.Find(v.fs)
- if err != nil {
- return "", err
- }
-
- if len(results) == 0 {
- return "", ConfigFileNotFoundError{v.configName, fmt.Sprintf("%s", v.configPaths)}
- }
-
- return results[0], nil
-}
diff --git a/vendor/github.com/spf13/viper/finder.go b/vendor/github.com/spf13/viper/finder.go
new file mode 100644
index 000000000..9b203ea69
--- /dev/null
+++ b/vendor/github.com/spf13/viper/finder.go
@@ -0,0 +1,55 @@
+package viper
+
+import (
+ "errors"
+
+ "github.com/spf13/afero"
+)
+
+// WithFinder sets a custom [Finder].
+func WithFinder(f Finder) Option {
+ return optionFunc(func(v *Viper) {
+ if f == nil {
+ return
+ }
+
+ v.finder = f
+ })
+}
+
+// Finder looks for files and directories in an [afero.Fs] filesystem.
+type Finder interface {
+ Find(fsys afero.Fs) ([]string, error)
+}
+
+// Finders combines multiple finders into one.
+func Finders(finders ...Finder) Finder {
+ return &combinedFinder{finders: finders}
+}
+
+// combinedFinder is a Finder that combines multiple finders.
+type combinedFinder struct {
+ finders []Finder
+}
+
+// Find implements the [Finder] interface.
+func (c *combinedFinder) Find(fsys afero.Fs) ([]string, error) {
+ var results []string
+ var errs []error
+
+ for _, finder := range c.finders {
+ if finder == nil {
+ continue
+ }
+
+ r, err := finder.Find(fsys)
+ if err != nil {
+ errs = append(errs, err)
+ continue
+ }
+
+ results = append(results, r...)
+ }
+
+ return results, errors.Join(errs...)
+}
diff --git a/vendor/github.com/spf13/viper/flake.lock b/vendor/github.com/spf13/viper/flake.lock
index 3840614fa..d76dfbddd 100644
--- a/vendor/github.com/spf13/viper/flake.lock
+++ b/vendor/github.com/spf13/viper/flake.lock
@@ -1,22 +1,84 @@
{
"nodes": {
+ "cachix": {
+ "inputs": {
+ "devenv": "devenv_2",
+ "flake-compat": [
+ "devenv",
+ "flake-compat"
+ ],
+ "nixpkgs": [
+ "devenv",
+ "nixpkgs"
+ ],
+ "pre-commit-hooks": [
+ "devenv",
+ "pre-commit-hooks"
+ ]
+ },
+ "locked": {
+ "lastModified": 1712055811,
+ "narHash": "sha256-7FcfMm5A/f02yyzuavJe06zLa9hcMHsagE28ADcmQvk=",
+ "owner": "cachix",
+ "repo": "cachix",
+ "rev": "02e38da89851ec7fec3356a5c04bc8349cae0e30",
+ "type": "github"
+ },
+ "original": {
+ "owner": "cachix",
+ "repo": "cachix",
+ "type": "github"
+ }
+ },
"devenv": {
"inputs": {
- "flake-compat": "flake-compat",
+ "cachix": "cachix",
+ "flake-compat": "flake-compat_2",
+ "nix": "nix_2",
+ "nixpkgs": "nixpkgs_2",
+ "pre-commit-hooks": "pre-commit-hooks"
+ },
+ "locked": {
+ "lastModified": 1724763216,
+ "narHash": "sha256-oW2bwCrJpIzibCNK6zfIDaIQw765yMAuMSG2gyZfGv0=",
+ "owner": "cachix",
+ "repo": "devenv",
+ "rev": "1e4ef61205b9aa20fe04bf1c468b6a316281c4f1",
+ "type": "github"
+ },
+ "original": {
+ "owner": "cachix",
+ "repo": "devenv",
+ "type": "github"
+ }
+ },
+ "devenv_2": {
+ "inputs": {
+ "flake-compat": [
+ "devenv",
+ "cachix",
+ "flake-compat"
+ ],
"nix": "nix",
"nixpkgs": "nixpkgs",
- "pre-commit-hooks": "pre-commit-hooks"
+ "poetry2nix": "poetry2nix",
+ "pre-commit-hooks": [
+ "devenv",
+ "cachix",
+ "pre-commit-hooks"
+ ]
},
"locked": {
- "lastModified": 1707817777,
- "narHash": "sha256-vHyIs1OULQ3/91wD6xOiuayfI71JXALGA5KLnDKAcy0=",
+ "lastModified": 1708704632,
+ "narHash": "sha256-w+dOIW60FKMaHI1q5714CSibk99JfYxm0CzTinYWr+Q=",
"owner": "cachix",
"repo": "devenv",
- "rev": "5a30b9e5ac7c6167e61b1f4193d5130bb9f8defa",
+ "rev": "2ee4450b0f4b95a1b90f2eb5ffea98b90e48c196",
"type": "github"
},
"original": {
"owner": "cachix",
+ "ref": "python-rewrite",
"repo": "devenv",
"type": "github"
}
@@ -37,16 +99,32 @@
"type": "github"
}
},
+ "flake-compat_2": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1696426674,
+ "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=",
+ "owner": "edolstra",
+ "repo": "flake-compat",
+ "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33",
+ "type": "github"
+ },
+ "original": {
+ "owner": "edolstra",
+ "repo": "flake-compat",
+ "type": "github"
+ }
+ },
"flake-parts": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
- "lastModified": 1706830856,
- "narHash": "sha256-a0NYyp+h9hlb7ddVz4LUn1vT/PLwqfrWYcHMvFB1xYg=",
+ "lastModified": 1722555600,
+ "narHash": "sha256-XOQkdLafnb/p9ij77byFQjDf5m5QYl9b2REiVClC+x4=",
"owner": "hercules-ci",
"repo": "flake-parts",
- "rev": "b253292d9c0a5ead9bc98c4e9a26c6312e27d69f",
+ "rev": "8471fe90ad337a8074e957b69ca4d0089218391d",
"type": "github"
},
"original": {
@@ -60,11 +138,29 @@
"systems": "systems"
},
"locked": {
- "lastModified": 1685518550,
- "narHash": "sha256-o2d0KcvaXzTrPRIo0kOLV0/QXHhDQ5DTi+OxcjO8xqY=",
+ "lastModified": 1689068808,
+ "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "flake-utils_2": {
+ "inputs": {
+ "systems": "systems_2"
+ },
+ "locked": {
+ "lastModified": 1710146030,
+ "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
"owner": "numtide",
"repo": "flake-utils",
- "rev": "a1720a10a6cfe8234c0e93907ffe81be440f4cef",
+ "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
"type": "github"
},
"original": {
@@ -82,11 +178,11 @@
]
},
"locked": {
- "lastModified": 1660459072,
- "narHash": "sha256-8DFJjXG8zqoONA1vXtgeKXy68KdJL5UaXR8NtVMUbx8=",
+ "lastModified": 1709087332,
+ "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
"owner": "hercules-ci",
"repo": "gitignore.nix",
- "rev": "a20de23b925fd8264fd7fad6454652e142fd7f73",
+ "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
"type": "github"
},
"original": {
@@ -95,53 +191,90 @@
"type": "github"
}
},
- "lowdown-src": {
- "flake": false,
+ "nix": {
+ "inputs": {
+ "flake-compat": "flake-compat",
+ "nixpkgs": [
+ "devenv",
+ "cachix",
+ "devenv",
+ "nixpkgs"
+ ],
+ "nixpkgs-regression": "nixpkgs-regression"
+ },
"locked": {
- "lastModified": 1633514407,
- "narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=",
- "owner": "kristapsdz",
- "repo": "lowdown",
- "rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8",
+ "lastModified": 1712911606,
+ "narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=",
+ "owner": "domenkozar",
+ "repo": "nix",
+ "rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12",
"type": "github"
},
"original": {
- "owner": "kristapsdz",
- "repo": "lowdown",
+ "owner": "domenkozar",
+ "ref": "devenv-2.21",
+ "repo": "nix",
"type": "github"
}
},
- "nix": {
+ "nix-github-actions": {
+ "inputs": {
+ "nixpkgs": [
+ "devenv",
+ "cachix",
+ "devenv",
+ "poetry2nix",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1688870561,
+ "narHash": "sha256-4UYkifnPEw1nAzqqPOTL2MvWtm3sNGw1UTYTalkTcGY=",
+ "owner": "nix-community",
+ "repo": "nix-github-actions",
+ "rev": "165b1650b753316aa7f1787f3005a8d2da0f5301",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-community",
+ "repo": "nix-github-actions",
+ "type": "github"
+ }
+ },
+ "nix_2": {
"inputs": {
- "lowdown-src": "lowdown-src",
+ "flake-compat": [
+ "devenv",
+ "flake-compat"
+ ],
"nixpkgs": [
"devenv",
"nixpkgs"
],
- "nixpkgs-regression": "nixpkgs-regression"
+ "nixpkgs-regression": "nixpkgs-regression_2"
},
"locked": {
- "lastModified": 1676545802,
- "narHash": "sha256-EK4rZ+Hd5hsvXnzSzk2ikhStJnD63odF7SzsQ8CuSPU=",
+ "lastModified": 1712911606,
+ "narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=",
"owner": "domenkozar",
"repo": "nix",
- "rev": "7c91803598ffbcfe4a55c44ac6d49b2cf07a527f",
+ "rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12",
"type": "github"
},
"original": {
"owner": "domenkozar",
- "ref": "relaxed-flakes",
+ "ref": "devenv-2.21",
"repo": "nix",
"type": "github"
}
},
"nixpkgs": {
"locked": {
- "lastModified": 1678875422,
- "narHash": "sha256-T3o6NcQPwXjxJMn2shz86Chch4ljXgZn746c2caGxd8=",
+ "lastModified": 1692808169,
+ "narHash": "sha256-x9Opq06rIiwdwGeK2Ykj69dNc2IvUH1fY55Wm7atwrE=",
"owner": "NixOS",
"repo": "nixpkgs",
- "rev": "126f49a01de5b7e35a43fd43f891ecf6d3a51459",
+ "rev": "9201b5ff357e781bf014d0330d18555695df7ba8",
"type": "github"
},
"original": {
@@ -153,23 +286,33 @@
},
"nixpkgs-lib": {
"locked": {
- "dir": "lib",
- "lastModified": 1706550542,
- "narHash": "sha256-UcsnCG6wx++23yeER4Hg18CXWbgNpqNXcHIo5/1Y+hc=",
+ "lastModified": 1722555339,
+ "narHash": "sha256-uFf2QeW7eAHlYXuDktm9c25OxOyCoUOQmh5SZ9amE5Q=",
+ "type": "tarball",
+ "url": "https://github.com/NixOS/nixpkgs/archive/a5d394176e64ab29c852d03346c1fc9b0b7d33eb.tar.gz"
+ },
+ "original": {
+ "type": "tarball",
+ "url": "https://github.com/NixOS/nixpkgs/archive/a5d394176e64ab29c852d03346c1fc9b0b7d33eb.tar.gz"
+ }
+ },
+ "nixpkgs-regression": {
+ "locked": {
+ "lastModified": 1643052045,
+ "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
"owner": "NixOS",
"repo": "nixpkgs",
- "rev": "97b17f32362e475016f942bbdfda4a4a72a8a652",
+ "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
"type": "github"
},
"original": {
- "dir": "lib",
"owner": "NixOS",
- "ref": "nixos-unstable",
"repo": "nixpkgs",
+ "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2",
"type": "github"
}
},
- "nixpkgs-regression": {
+ "nixpkgs-regression_2": {
"locked": {
"lastModified": 1643052045,
"narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=",
@@ -187,27 +330,43 @@
},
"nixpkgs-stable": {
"locked": {
- "lastModified": 1685801374,
- "narHash": "sha256-otaSUoFEMM+LjBI1XL/xGB5ao6IwnZOXc47qhIgJe8U=",
+ "lastModified": 1710695816,
+ "narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=",
"owner": "NixOS",
"repo": "nixpkgs",
- "rev": "c37ca420157f4abc31e26f436c1145f8951ff373",
+ "rev": "614b4613980a522ba49f0d194531beddbb7220d3",
"type": "github"
},
"original": {
"owner": "NixOS",
- "ref": "nixos-23.05",
+ "ref": "nixos-23.11",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
- "lastModified": 1707939175,
- "narHash": "sha256-D1xan0lgxbmXDyzVqXTiSYHLmAMrMRdD+alKzEO/p3w=",
+ "lastModified": 1713361204,
+ "narHash": "sha256-TA6EDunWTkc5FvDCqU3W2T3SFn0gRZqh6D/hJnM02MM=",
+ "owner": "cachix",
+ "repo": "devenv-nixpkgs",
+ "rev": "285676e87ad9f0ca23d8714a6ab61e7e027020c6",
+ "type": "github"
+ },
+ "original": {
+ "owner": "cachix",
+ "ref": "rolling",
+ "repo": "devenv-nixpkgs",
+ "type": "github"
+ }
+ },
+ "nixpkgs_3": {
+ "locked": {
+ "lastModified": 1724748588,
+ "narHash": "sha256-NlpGA4+AIf1dKNq76ps90rxowlFXUsV9x7vK/mN37JM=",
"owner": "NixOS",
"repo": "nixpkgs",
- "rev": "f7e8132daca31b1e3859ac0fb49741754375ac3d",
+ "rev": "a6292e34000dc93d43bccf78338770c1c5ec8a99",
"type": "github"
},
"original": {
@@ -217,13 +376,38 @@
"type": "github"
}
},
+ "poetry2nix": {
+ "inputs": {
+ "flake-utils": "flake-utils",
+ "nix-github-actions": "nix-github-actions",
+ "nixpkgs": [
+ "devenv",
+ "cachix",
+ "devenv",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1692876271,
+ "narHash": "sha256-IXfZEkI0Mal5y1jr6IRWMqK8GW2/f28xJenZIPQqkY0=",
+ "owner": "nix-community",
+ "repo": "poetry2nix",
+ "rev": "d5006be9c2c2417dafb2e2e5034d83fabd207ee3",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-community",
+ "repo": "poetry2nix",
+ "type": "github"
+ }
+ },
"pre-commit-hooks": {
"inputs": {
"flake-compat": [
"devenv",
"flake-compat"
],
- "flake-utils": "flake-utils",
+ "flake-utils": "flake-utils_2",
"gitignore": "gitignore",
"nixpkgs": [
"devenv",
@@ -232,11 +416,11 @@
"nixpkgs-stable": "nixpkgs-stable"
},
"locked": {
- "lastModified": 1704725188,
- "narHash": "sha256-qq8NbkhRZF1vVYQFt1s8Mbgo8knj+83+QlL5LBnYGpI=",
+ "lastModified": 1713775815,
+ "narHash": "sha256-Wu9cdYTnGQQwtT20QQMg7jzkANKQjwBD9iccfGKkfls=",
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
- "rev": "ea96f0c05924341c551a797aaba8126334c505d2",
+ "rev": "2ac4dcbf55ed43f3be0bae15e181f08a57af24a4",
"type": "github"
},
"original": {
@@ -249,7 +433,7 @@
"inputs": {
"devenv": "devenv",
"flake-parts": "flake-parts",
- "nixpkgs": "nixpkgs_2"
+ "nixpkgs": "nixpkgs_3"
}
},
"systems": {
@@ -266,6 +450,21 @@
"repo": "default",
"type": "github"
}
+ },
+ "systems_2": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
}
},
"root": "root",
diff --git a/vendor/github.com/spf13/viper/flake.nix b/vendor/github.com/spf13/viper/flake.nix
index 0230668cf..52ad7d581 100644
--- a/vendor/github.com/spf13/viper/flake.nix
+++ b/vendor/github.com/spf13/viper/flake.nix
@@ -20,7 +20,7 @@
default = {
languages = {
go.enable = true;
- go.package = pkgs.go_1_22;
+ go.package = pkgs.go_1_23;
};
pre-commit.hooks = {
diff --git a/vendor/github.com/spf13/viper/internal/encoding/decoder.go b/vendor/github.com/spf13/viper/internal/encoding/decoder.go
deleted file mode 100644
index 8a7b1dbc9..000000000
--- a/vendor/github.com/spf13/viper/internal/encoding/decoder.go
+++ /dev/null
@@ -1,61 +0,0 @@
-package encoding
-
-import (
- "sync"
-)
-
-// Decoder decodes the contents of b into v.
-// It's primarily used for decoding contents of a file into a map[string]any.
-type Decoder interface {
- Decode(b []byte, v map[string]any) error
-}
-
-const (
- // ErrDecoderNotFound is returned when there is no decoder registered for a format.
- ErrDecoderNotFound = encodingError("decoder not found for this format")
-
- // ErrDecoderFormatAlreadyRegistered is returned when an decoder is already registered for a format.
- ErrDecoderFormatAlreadyRegistered = encodingError("decoder already registered for this format")
-)
-
-// DecoderRegistry can choose an appropriate Decoder based on the provided format.
-type DecoderRegistry struct {
- decoders map[string]Decoder
-
- mu sync.RWMutex
-}
-
-// NewDecoderRegistry returns a new, initialized DecoderRegistry.
-func NewDecoderRegistry() *DecoderRegistry {
- return &DecoderRegistry{
- decoders: make(map[string]Decoder),
- }
-}
-
-// RegisterDecoder registers a Decoder for a format.
-// Registering a Decoder for an already existing format is not supported.
-func (e *DecoderRegistry) RegisterDecoder(format string, enc Decoder) error {
- e.mu.Lock()
- defer e.mu.Unlock()
-
- if _, ok := e.decoders[format]; ok {
- return ErrDecoderFormatAlreadyRegistered
- }
-
- e.decoders[format] = enc
-
- return nil
-}
-
-// Decode calls the underlying Decoder based on the format.
-func (e *DecoderRegistry) Decode(format string, b []byte, v map[string]any) error {
- e.mu.RLock()
- decoder, ok := e.decoders[format]
- e.mu.RUnlock()
-
- if !ok {
- return ErrDecoderNotFound
- }
-
- return decoder.Decode(b, v)
-}
diff --git a/vendor/github.com/spf13/viper/internal/encoding/encoder.go b/vendor/github.com/spf13/viper/internal/encoding/encoder.go
deleted file mode 100644
index 659585962..000000000
--- a/vendor/github.com/spf13/viper/internal/encoding/encoder.go
+++ /dev/null
@@ -1,60 +0,0 @@
-package encoding
-
-import (
- "sync"
-)
-
-// Encoder encodes the contents of v into a byte representation.
-// It's primarily used for encoding a map[string]any into a file format.
-type Encoder interface {
- Encode(v map[string]any) ([]byte, error)
-}
-
-const (
- // ErrEncoderNotFound is returned when there is no encoder registered for a format.
- ErrEncoderNotFound = encodingError("encoder not found for this format")
-
- // ErrEncoderFormatAlreadyRegistered is returned when an encoder is already registered for a format.
- ErrEncoderFormatAlreadyRegistered = encodingError("encoder already registered for this format")
-)
-
-// EncoderRegistry can choose an appropriate Encoder based on the provided format.
-type EncoderRegistry struct {
- encoders map[string]Encoder
-
- mu sync.RWMutex
-}
-
-// NewEncoderRegistry returns a new, initialized EncoderRegistry.
-func NewEncoderRegistry() *EncoderRegistry {
- return &EncoderRegistry{
- encoders: make(map[string]Encoder),
- }
-}
-
-// RegisterEncoder registers an Encoder for a format.
-// Registering a Encoder for an already existing format is not supported.
-func (e *EncoderRegistry) RegisterEncoder(format string, enc Encoder) error {
- e.mu.Lock()
- defer e.mu.Unlock()
-
- if _, ok := e.encoders[format]; ok {
- return ErrEncoderFormatAlreadyRegistered
- }
-
- e.encoders[format] = enc
-
- return nil
-}
-
-func (e *EncoderRegistry) Encode(format string, v map[string]any) ([]byte, error) {
- e.mu.RLock()
- encoder, ok := e.encoders[format]
- e.mu.RUnlock()
-
- if !ok {
- return nil, ErrEncoderNotFound
- }
-
- return encoder.Encode(v)
-}
diff --git a/vendor/github.com/spf13/viper/internal/encoding/error.go b/vendor/github.com/spf13/viper/internal/encoding/error.go
deleted file mode 100644
index e4cde02d7..000000000
--- a/vendor/github.com/spf13/viper/internal/encoding/error.go
+++ /dev/null
@@ -1,7 +0,0 @@
-package encoding
-
-type encodingError string
-
-func (e encodingError) Error() string {
- return string(e)
-}
diff --git a/vendor/github.com/spf13/viper/internal/encoding/hcl/codec.go b/vendor/github.com/spf13/viper/internal/encoding/hcl/codec.go
deleted file mode 100644
index d7fa8a1b7..000000000
--- a/vendor/github.com/spf13/viper/internal/encoding/hcl/codec.go
+++ /dev/null
@@ -1,40 +0,0 @@
-package hcl
-
-import (
- "bytes"
- "encoding/json"
-
- "github.com/hashicorp/hcl"
- "github.com/hashicorp/hcl/hcl/printer"
-)
-
-// Codec implements the encoding.Encoder and encoding.Decoder interfaces for HCL encoding.
-// TODO: add printer config to the codec?
-type Codec struct{}
-
-func (Codec) Encode(v map[string]any) ([]byte, error) {
- b, err := json.Marshal(v)
- if err != nil {
- return nil, err
- }
-
- // TODO: use printer.Format? Is the trailing newline an issue?
-
- ast, err := hcl.Parse(string(b))
- if err != nil {
- return nil, err
- }
-
- var buf bytes.Buffer
-
- err = printer.Fprint(&buf, ast.Node)
- if err != nil {
- return nil, err
- }
-
- return buf.Bytes(), nil
-}
-
-func (Codec) Decode(b []byte, v map[string]any) error {
- return hcl.Unmarshal(b, &v)
-}
diff --git a/vendor/github.com/spf13/viper/internal/encoding/ini/codec.go b/vendor/github.com/spf13/viper/internal/encoding/ini/codec.go
deleted file mode 100644
index d91cf59d2..000000000
--- a/vendor/github.com/spf13/viper/internal/encoding/ini/codec.go
+++ /dev/null
@@ -1,99 +0,0 @@
-package ini
-
-import (
- "bytes"
- "sort"
- "strings"
-
- "github.com/spf13/cast"
- "gopkg.in/ini.v1"
-)
-
-// LoadOptions contains all customized options used for load data source(s).
-// This type is added here for convenience: this way consumers can import a single package called "ini".
-type LoadOptions = ini.LoadOptions
-
-// Codec implements the encoding.Encoder and encoding.Decoder interfaces for INI encoding.
-type Codec struct {
- KeyDelimiter string
- LoadOptions LoadOptions
-}
-
-func (c Codec) Encode(v map[string]any) ([]byte, error) {
- cfg := ini.Empty()
- ini.PrettyFormat = false
-
- flattened := map[string]any{}
-
- flattened = flattenAndMergeMap(flattened, v, "", c.keyDelimiter())
-
- keys := make([]string, 0, len(flattened))
-
- for key := range flattened {
- keys = append(keys, key)
- }
-
- sort.Strings(keys)
-
- for _, key := range keys {
- sectionName, keyName := "", key
-
- lastSep := strings.LastIndex(key, ".")
- if lastSep != -1 {
- sectionName = key[:(lastSep)]
- keyName = key[(lastSep + 1):]
- }
-
- // TODO: is this a good idea?
- if sectionName == "default" {
- sectionName = ""
- }
-
- cfg.Section(sectionName).Key(keyName).SetValue(cast.ToString(flattened[key]))
- }
-
- var buf bytes.Buffer
-
- _, err := cfg.WriteTo(&buf)
- if err != nil {
- return nil, err
- }
-
- return buf.Bytes(), nil
-}
-
-func (c Codec) Decode(b []byte, v map[string]any) error {
- cfg := ini.Empty(c.LoadOptions)
-
- err := cfg.Append(b)
- if err != nil {
- return err
- }
-
- sections := cfg.Sections()
-
- for i := 0; i < len(sections); i++ {
- section := sections[i]
- keys := section.Keys()
-
- for j := 0; j < len(keys); j++ {
- key := keys[j]
- value := cfg.Section(section.Name()).Key(key.Name()).String()
-
- deepestMap := deepSearch(v, strings.Split(section.Name(), c.keyDelimiter()))
-
- // set innermost value
- deepestMap[key.Name()] = value
- }
- }
-
- return nil
-}
-
-func (c Codec) keyDelimiter() string {
- if c.KeyDelimiter == "" {
- return "."
- }
-
- return c.KeyDelimiter
-}
diff --git a/vendor/github.com/spf13/viper/internal/encoding/ini/map_utils.go b/vendor/github.com/spf13/viper/internal/encoding/ini/map_utils.go
deleted file mode 100644
index 490ab594e..000000000
--- a/vendor/github.com/spf13/viper/internal/encoding/ini/map_utils.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package ini
-
-import (
- "strings"
-
- "github.com/spf13/cast"
-)
-
-// THIS CODE IS COPIED HERE: IT SHOULD NOT BE MODIFIED
-// AT SOME POINT IT WILL BE MOVED TO A COMMON PLACE
-// deepSearch scans deep maps, following the key indexes listed in the
-// sequence "path".
-// The last value is expected to be another map, and is returned.
-//
-// In case intermediate keys do not exist, or map to a non-map value,
-// a new map is created and inserted, and the search continues from there:
-// the initial map "m" may be modified!
-func deepSearch(m map[string]any, path []string) map[string]any {
- for _, k := range path {
- m2, ok := m[k]
- if !ok {
- // intermediate key does not exist
- // => create it and continue from there
- m3 := make(map[string]any)
- m[k] = m3
- m = m3
- continue
- }
- m3, ok := m2.(map[string]any)
- if !ok {
- // intermediate key is a value
- // => replace with a new map
- m3 = make(map[string]any)
- m[k] = m3
- }
- // continue search from here
- m = m3
- }
- return m
-}
-
-// flattenAndMergeMap recursively flattens the given map into a new map
-// Code is based on the function with the same name in the main package.
-// TODO: move it to a common place.
-func flattenAndMergeMap(shadow, m map[string]any, prefix, delimiter string) map[string]any {
- if shadow != nil && prefix != "" && shadow[prefix] != nil {
- // prefix is shadowed => nothing more to flatten
- return shadow
- }
- if shadow == nil {
- shadow = make(map[string]any)
- }
-
- var m2 map[string]any
- if prefix != "" {
- prefix += delimiter
- }
- for k, val := range m {
- fullKey := prefix + k
- switch val := val.(type) {
- case map[string]any:
- m2 = val
- case map[any]any:
- m2 = cast.ToStringMap(val)
- default:
- // immediate value
- shadow[strings.ToLower(fullKey)] = val
- continue
- }
- // recursively merge to shadow map
- shadow = flattenAndMergeMap(shadow, m2, fullKey, delimiter)
- }
- return shadow
-}
diff --git a/vendor/github.com/spf13/viper/internal/encoding/javaproperties/codec.go b/vendor/github.com/spf13/viper/internal/encoding/javaproperties/codec.go
deleted file mode 100644
index e92e5172c..000000000
--- a/vendor/github.com/spf13/viper/internal/encoding/javaproperties/codec.go
+++ /dev/null
@@ -1,86 +0,0 @@
-package javaproperties
-
-import (
- "bytes"
- "sort"
- "strings"
-
- "github.com/magiconair/properties"
- "github.com/spf13/cast"
-)
-
-// Codec implements the encoding.Encoder and encoding.Decoder interfaces for Java properties encoding.
-type Codec struct {
- KeyDelimiter string
-
- // Store read properties on the object so that we can write back in order with comments.
- // This will only be used if the configuration read is a properties file.
- // TODO: drop this feature in v2
- // TODO: make use of the global properties object optional
- Properties *properties.Properties
-}
-
-func (c *Codec) Encode(v map[string]any) ([]byte, error) {
- if c.Properties == nil {
- c.Properties = properties.NewProperties()
- }
-
- flattened := map[string]any{}
-
- flattened = flattenAndMergeMap(flattened, v, "", c.keyDelimiter())
-
- keys := make([]string, 0, len(flattened))
-
- for key := range flattened {
- keys = append(keys, key)
- }
-
- sort.Strings(keys)
-
- for _, key := range keys {
- _, _, err := c.Properties.Set(key, cast.ToString(flattened[key]))
- if err != nil {
- return nil, err
- }
- }
-
- var buf bytes.Buffer
-
- _, err := c.Properties.WriteComment(&buf, "#", properties.UTF8)
- if err != nil {
- return nil, err
- }
-
- return buf.Bytes(), nil
-}
-
-func (c *Codec) Decode(b []byte, v map[string]any) error {
- var err error
- c.Properties, err = properties.Load(b, properties.UTF8)
- if err != nil {
- return err
- }
-
- for _, key := range c.Properties.Keys() {
- // ignore existence check: we know it's there
- value, _ := c.Properties.Get(key)
-
- // recursively build nested maps
- path := strings.Split(key, c.keyDelimiter())
- lastKey := strings.ToLower(path[len(path)-1])
- deepestMap := deepSearch(v, path[0:len(path)-1])
-
- // set innermost value
- deepestMap[lastKey] = value
- }
-
- return nil
-}
-
-func (c Codec) keyDelimiter() string {
- if c.KeyDelimiter == "" {
- return "."
- }
-
- return c.KeyDelimiter
-}
diff --git a/vendor/github.com/spf13/viper/internal/encoding/javaproperties/map_utils.go b/vendor/github.com/spf13/viper/internal/encoding/javaproperties/map_utils.go
deleted file mode 100644
index 6e1aff223..000000000
--- a/vendor/github.com/spf13/viper/internal/encoding/javaproperties/map_utils.go
+++ /dev/null
@@ -1,74 +0,0 @@
-package javaproperties
-
-import (
- "strings"
-
- "github.com/spf13/cast"
-)
-
-// THIS CODE IS COPIED HERE: IT SHOULD NOT BE MODIFIED
-// AT SOME POINT IT WILL BE MOVED TO A COMMON PLACE
-// deepSearch scans deep maps, following the key indexes listed in the
-// sequence "path".
-// The last value is expected to be another map, and is returned.
-//
-// In case intermediate keys do not exist, or map to a non-map value,
-// a new map is created and inserted, and the search continues from there:
-// the initial map "m" may be modified!
-func deepSearch(m map[string]any, path []string) map[string]any {
- for _, k := range path {
- m2, ok := m[k]
- if !ok {
- // intermediate key does not exist
- // => create it and continue from there
- m3 := make(map[string]any)
- m[k] = m3
- m = m3
- continue
- }
- m3, ok := m2.(map[string]any)
- if !ok {
- // intermediate key is a value
- // => replace with a new map
- m3 = make(map[string]any)
- m[k] = m3
- }
- // continue search from here
- m = m3
- }
- return m
-}
-
-// flattenAndMergeMap recursively flattens the given map into a new map
-// Code is based on the function with the same name in the main package.
-// TODO: move it to a common place.
-func flattenAndMergeMap(shadow, m map[string]any, prefix, delimiter string) map[string]any {
- if shadow != nil && prefix != "" && shadow[prefix] != nil {
- // prefix is shadowed => nothing more to flatten
- return shadow
- }
- if shadow == nil {
- shadow = make(map[string]any)
- }
-
- var m2 map[string]any
- if prefix != "" {
- prefix += delimiter
- }
- for k, val := range m {
- fullKey := prefix + k
- switch val := val.(type) {
- case map[string]any:
- m2 = val
- case map[any]any:
- m2 = cast.ToStringMap(val)
- default:
- // immediate value
- shadow[strings.ToLower(fullKey)] = val
- continue
- }
- // recursively merge to shadow map
- shadow = flattenAndMergeMap(shadow, m2, fullKey, delimiter)
- }
- return shadow
-}
diff --git a/vendor/github.com/spf13/viper/internal/features/finder.go b/vendor/github.com/spf13/viper/internal/features/finder.go
new file mode 100644
index 000000000..983ea3a9d
--- /dev/null
+++ b/vendor/github.com/spf13/viper/internal/features/finder.go
@@ -0,0 +1,5 @@
+//go:build viper_finder
+
+package features
+
+const Finder = true
diff --git a/vendor/github.com/spf13/viper/internal/features/finder_default.go b/vendor/github.com/spf13/viper/internal/features/finder_default.go
new file mode 100644
index 000000000..89bcb06ee
--- /dev/null
+++ b/vendor/github.com/spf13/viper/internal/features/finder_default.go
@@ -0,0 +1,5 @@
+//go:build !viper_finder
+
+package features
+
+const Finder = false
diff --git a/vendor/github.com/spf13/viper/logger.go b/vendor/github.com/spf13/viper/logger.go
index 8938053b3..828042f29 100644
--- a/vendor/github.com/spf13/viper/logger.go
+++ b/vendor/github.com/spf13/viper/logger.go
@@ -2,46 +2,9 @@ package viper
import (
"context"
-
- slog "github.com/sagikazarmark/slog-shim"
+ "log/slog"
)
-// Logger is a unified interface for various logging use cases and practices, including:
-// - leveled logging
-// - structured logging
-//
-// Deprecated: use `log/slog` instead.
-type Logger interface {
- // Trace logs a Trace event.
- //
- // Even more fine-grained information than Debug events.
- // Loggers not supporting this level should fall back to Debug.
- Trace(msg string, keyvals ...any)
-
- // Debug logs a Debug event.
- //
- // A verbose series of information events.
- // They are useful when debugging the system.
- Debug(msg string, keyvals ...any)
-
- // Info logs an Info event.
- //
- // General information about what's happening inside the system.
- Info(msg string, keyvals ...any)
-
- // Warn logs a Warn(ing) event.
- //
- // Non-critical events that should be looked at.
- Warn(msg string, keyvals ...any)
-
- // Error logs an Error event.
- //
- // Critical events that require immediate attention.
- // Loggers commonly provide Fatal and Panic levels above Error level,
- // but exiting and panicking is out of scope for a logging library.
- Error(msg string, keyvals ...any)
-}
-
// WithLogger sets a custom logger.
func WithLogger(l *slog.Logger) Option {
return optionFunc(func(v *Viper) {
diff --git a/vendor/github.com/spf13/viper/remote.go b/vendor/github.com/spf13/viper/remote.go
new file mode 100644
index 000000000..bdde7de26
--- /dev/null
+++ b/vendor/github.com/spf13/viper/remote.go
@@ -0,0 +1,256 @@
+package viper
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "reflect"
+ "slices"
+)
+
+// SupportedRemoteProviders are universally supported remote providers.
+var SupportedRemoteProviders = []string{"etcd", "etcd3", "consul", "firestore", "nats"}
+
+func resetRemote() {
+ SupportedRemoteProviders = []string{"etcd", "etcd3", "consul", "firestore", "nats"}
+}
+
+type remoteConfigFactory interface {
+ Get(rp RemoteProvider) (io.Reader, error)
+ Watch(rp RemoteProvider) (io.Reader, error)
+ WatchChannel(rp RemoteProvider) (<-chan *RemoteResponse, chan bool)
+}
+
+type RemoteResponse struct {
+ Value []byte
+ Error error
+}
+
+// RemoteConfig is optional, see the remote package.
+var RemoteConfig remoteConfigFactory
+
+// UnsupportedRemoteProviderError denotes encountering an unsupported remote
+// provider. Currently only etcd and Consul are supported.
+type UnsupportedRemoteProviderError string
+
+// Error returns the formatted remote provider error.
+func (str UnsupportedRemoteProviderError) Error() string {
+ return fmt.Sprintf("Unsupported Remote Provider Type %q", string(str))
+}
+
+// RemoteConfigError denotes encountering an error while trying to
+// pull the configuration from the remote provider.
+type RemoteConfigError string
+
+// Error returns the formatted remote provider error.
+func (rce RemoteConfigError) Error() string {
+ return fmt.Sprintf("Remote Configurations Error: %s", string(rce))
+}
+
+type defaultRemoteProvider struct {
+ provider string
+ endpoint string
+ path string
+ secretKeyring string
+}
+
+func (rp defaultRemoteProvider) Provider() string {
+ return rp.provider
+}
+
+func (rp defaultRemoteProvider) Endpoint() string {
+ return rp.endpoint
+}
+
+func (rp defaultRemoteProvider) Path() string {
+ return rp.path
+}
+
+func (rp defaultRemoteProvider) SecretKeyring() string {
+ return rp.secretKeyring
+}
+
+// RemoteProvider stores the configuration necessary
+// to connect to a remote key/value store.
+// Optional secretKeyring to unencrypt encrypted values
+// can be provided.
+type RemoteProvider interface {
+ Provider() string
+ Endpoint() string
+ Path() string
+ SecretKeyring() string
+}
+
+// AddRemoteProvider adds a remote configuration source.
+// Remote Providers are searched in the order they are added.
+// provider is a string value: "etcd", "etcd3", "consul", "firestore" or "nats" are currently supported.
+// endpoint is the url. etcd requires http://ip:port, consul requires ip:port, nats requires nats://ip:port
+// path is the path in the k/v store to retrieve configuration
+// To retrieve a config file called myapp.json from /configs/myapp.json
+// you should set path to /configs and set config name (SetConfigName()) to
+// "myapp".
+func AddRemoteProvider(provider, endpoint, path string) error {
+ return v.AddRemoteProvider(provider, endpoint, path)
+}
+
+func (v *Viper) AddRemoteProvider(provider, endpoint, path string) error {
+ if !slices.Contains(SupportedRemoteProviders, provider) {
+ return UnsupportedRemoteProviderError(provider)
+ }
+ if provider != "" && endpoint != "" {
+ v.logger.Info("adding remote provider", "provider", provider, "endpoint", endpoint)
+
+ rp := &defaultRemoteProvider{
+ endpoint: endpoint,
+ provider: provider,
+ path: path,
+ }
+ if !v.providerPathExists(rp) {
+ v.remoteProviders = append(v.remoteProviders, rp)
+ }
+ }
+ return nil
+}
+
+// AddSecureRemoteProvider adds a remote configuration source.
+// Secure Remote Providers are searched in the order they are added.
+// provider is a string value: "etcd", "etcd3", "consul", "firestore" or "nats" are currently supported.
+// endpoint is the url. etcd requires http://ip:port consul requires ip:port
+// secretkeyring is the filepath to your openpgp secret keyring. e.g. /etc/secrets/myring.gpg
+// path is the path in the k/v store to retrieve configuration
+// To retrieve a config file called myapp.json from /configs/myapp.json
+// you should set path to /configs and set config name (SetConfigName()) to
+// "myapp".
+// Secure Remote Providers are implemented with github.com/sagikazarmark/crypt.
+func AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error {
+ return v.AddSecureRemoteProvider(provider, endpoint, path, secretkeyring)
+}
+
+func (v *Viper) AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error {
+ if !slices.Contains(SupportedRemoteProviders, provider) {
+ return UnsupportedRemoteProviderError(provider)
+ }
+ if provider != "" && endpoint != "" {
+ v.logger.Info("adding remote provider", "provider", provider, "endpoint", endpoint)
+
+ rp := &defaultRemoteProvider{
+ endpoint: endpoint,
+ provider: provider,
+ path: path,
+ secretKeyring: secretkeyring,
+ }
+ if !v.providerPathExists(rp) {
+ v.remoteProviders = append(v.remoteProviders, rp)
+ }
+ }
+ return nil
+}
+
+func (v *Viper) providerPathExists(p *defaultRemoteProvider) bool {
+ for _, y := range v.remoteProviders {
+ if reflect.DeepEqual(y, p) {
+ return true
+ }
+ }
+ return false
+}
+
+// ReadRemoteConfig attempts to get configuration from a remote source
+// and read it in the remote configuration registry.
+func ReadRemoteConfig() error { return v.ReadRemoteConfig() }
+
+func (v *Viper) ReadRemoteConfig() error {
+ return v.getKeyValueConfig()
+}
+
+func WatchRemoteConfig() error { return v.WatchRemoteConfig() }
+func (v *Viper) WatchRemoteConfig() error {
+ return v.watchKeyValueConfig()
+}
+
+func (v *Viper) WatchRemoteConfigOnChannel() error {
+ return v.watchKeyValueConfigOnChannel()
+}
+
+// Retrieve the first found remote configuration.
+func (v *Viper) getKeyValueConfig() error {
+ if RemoteConfig == nil {
+ return RemoteConfigError("Enable the remote features by doing a blank import of the viper/remote package: '_ github.com/spf13/viper/remote'")
+ }
+
+ if len(v.remoteProviders) == 0 {
+ return RemoteConfigError("No Remote Providers")
+ }
+
+ for _, rp := range v.remoteProviders {
+ val, err := v.getRemoteConfig(rp)
+ if err != nil {
+ v.logger.Error(fmt.Errorf("get remote config: %w", err).Error())
+
+ continue
+ }
+
+ v.kvstore = val
+
+ return nil
+ }
+ return RemoteConfigError("No Files Found")
+}
+
+func (v *Viper) getRemoteConfig(provider RemoteProvider) (map[string]any, error) {
+ reader, err := RemoteConfig.Get(provider)
+ if err != nil {
+ return nil, err
+ }
+ err = v.unmarshalReader(reader, v.kvstore)
+ return v.kvstore, err
+}
+
+// Retrieve the first found remote configuration.
+func (v *Viper) watchKeyValueConfigOnChannel() error {
+ if len(v.remoteProviders) == 0 {
+ return RemoteConfigError("No Remote Providers")
+ }
+
+ for _, rp := range v.remoteProviders {
+ respc, _ := RemoteConfig.WatchChannel(rp)
+ // Todo: Add quit channel
+ go func(rc <-chan *RemoteResponse) {
+ for {
+ b := <-rc
+ reader := bytes.NewReader(b.Value)
+ v.unmarshalReader(reader, v.kvstore)
+ }
+ }(respc)
+ return nil
+ }
+ return RemoteConfigError("No Files Found")
+}
+
+// Retrieve the first found remote configuration.
+func (v *Viper) watchKeyValueConfig() error {
+ if len(v.remoteProviders) == 0 {
+ return RemoteConfigError("No Remote Providers")
+ }
+
+ for _, rp := range v.remoteProviders {
+ val, err := v.watchRemoteConfig(rp)
+ if err != nil {
+ v.logger.Error(fmt.Errorf("watch remote config: %w", err).Error())
+
+ continue
+ }
+ v.kvstore = val
+ return nil
+ }
+ return RemoteConfigError("No Files Found")
+}
+
+func (v *Viper) watchRemoteConfig(provider RemoteProvider) (map[string]any, error) {
+ reader, err := RemoteConfig.Watch(provider)
+ if err != nil {
+ return nil, err
+ }
+ err = v.unmarshalReader(reader, v.kvstore)
+ return v.kvstore, err
+}
diff --git a/vendor/github.com/spf13/viper/util.go b/vendor/github.com/spf13/viper/util.go
index 117c6ac31..2a08074bc 100644
--- a/vendor/github.com/spf13/viper/util.go
+++ b/vendor/github.com/spf13/viper/util.go
@@ -12,13 +12,13 @@ package viper
import (
"fmt"
+ "log/slog"
"os"
"path/filepath"
"runtime"
"strings"
"unicode"
- slog "github.com/sagikazarmark/slog-shim"
"github.com/spf13/cast"
)
@@ -128,15 +128,6 @@ func absPathify(logger *slog.Logger, inPath string) string {
return ""
}
-func stringInSlice(a string, list []string) bool {
- for _, b := range list {
- if b == a {
- return true
- }
- }
- return false
-}
-
func userHomeDir() string {
if runtime.GOOS == "windows" {
home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
diff --git a/vendor/github.com/spf13/viper/viper.go b/vendor/github.com/spf13/viper/viper.go
index da68d9944..f900e58b1 100644
--- a/vendor/github.com/spf13/viper/viper.go
+++ b/vendor/github.com/spf13/viper/viper.go
@@ -25,29 +25,22 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"os"
"path/filepath"
"reflect"
+ "slices"
"strconv"
"strings"
"sync"
"time"
"github.com/fsnotify/fsnotify"
- "github.com/mitchellh/mapstructure"
- slog "github.com/sagikazarmark/slog-shim"
+ "github.com/go-viper/mapstructure/v2"
"github.com/spf13/afero"
"github.com/spf13/cast"
"github.com/spf13/pflag"
- "github.com/spf13/viper/internal/encoding"
- "github.com/spf13/viper/internal/encoding/dotenv"
- "github.com/spf13/viper/internal/encoding/hcl"
- "github.com/spf13/viper/internal/encoding/ini"
- "github.com/spf13/viper/internal/encoding/javaproperties"
- "github.com/spf13/viper/internal/encoding/json"
- "github.com/spf13/viper/internal/encoding/toml"
- "github.com/spf13/viper/internal/encoding/yaml"
"github.com/spf13/viper/internal/features"
)
@@ -63,24 +56,10 @@ func (e ConfigMarshalError) Error() string {
var v *Viper
-type RemoteResponse struct {
- Value []byte
- Error error
-}
-
func init() {
v = New()
}
-type remoteConfigFactory interface {
- Get(rp RemoteProvider) (io.Reader, error)
- Watch(rp RemoteProvider) (io.Reader, error)
- WatchChannel(rp RemoteProvider) (<-chan *RemoteResponse, chan bool)
-}
-
-// RemoteConfig is optional, see the remote package.
-var RemoteConfig remoteConfigFactory
-
// UnsupportedConfigError denotes encountering an unsupported
// configuration filetype.
type UnsupportedConfigError string
@@ -90,24 +69,6 @@ func (str UnsupportedConfigError) Error() string {
return fmt.Sprintf("Unsupported Config Type %q", string(str))
}
-// UnsupportedRemoteProviderError denotes encountering an unsupported remote
-// provider. Currently only etcd and Consul are supported.
-type UnsupportedRemoteProviderError string
-
-// Error returns the formatted remote provider error.
-func (str UnsupportedRemoteProviderError) Error() string {
- return fmt.Sprintf("Unsupported Remote Provider Type %q", string(str))
-}
-
-// RemoteConfigError denotes encountering an error while trying to
-// pull the configuration from the remote provider.
-type RemoteConfigError string
-
-// Error returns the formatted remote provider error.
-func (rce RemoteConfigError) Error() string {
- return fmt.Sprintf("Remote Configurations Error: %s", string(rce))
-}
-
// ConfigFileNotFoundError denotes failing to find configuration file.
type ConfigFileNotFoundError struct {
name, locations string
@@ -190,6 +151,8 @@ type Viper struct {
// The filesystem to read config from.
fs afero.Fs
+ finder Finder
+
// A set of remote providers to search for the configuration
remoteProviders []*defaultRemoteProvider
@@ -200,9 +163,6 @@ type Viper struct {
configPermissions os.FileMode
envPrefix string
- // Specific commands for ini parsing
- iniLoadOptions ini.LoadOptions
-
automaticEnvApplied bool
envKeyReplacer StringReplacer
allowEmptyEnv bool
@@ -221,9 +181,13 @@ type Viper struct {
logger *slog.Logger
- // TODO: should probably be protected with a mutex
- encoderRegistry *encoding.EncoderRegistry
- decoderRegistry *encoding.DecoderRegistry
+ encoderRegistry EncoderRegistry
+ decoderRegistry DecoderRegistry
+
+ decodeHook mapstructure.DecodeHookFunc
+
+ experimentalFinder bool
+ experimentalBindStruct bool
}
// New returns an initialized Viper instance.
@@ -244,7 +208,13 @@ func New() *Viper {
v.typeByDefValue = false
v.logger = slog.New(&discardHandler{})
- v.resetEncoding()
+ codecRegistry := NewCodecRegistry()
+
+ v.encoderRegistry = codecRegistry
+ v.decoderRegistry = codecRegistry
+
+ v.experimentalFinder = features.Finder
+ v.experimentalBindStruct = features.BindStruct
return v
}
@@ -280,10 +250,25 @@ type StringReplacer interface {
// EnvKeyReplacer sets a replacer used for mapping environment variables to internal keys.
func EnvKeyReplacer(r StringReplacer) Option {
return optionFunc(func(v *Viper) {
+ if r == nil {
+ return
+ }
+
v.envKeyReplacer = r
})
}
+// WithDecodeHook sets a default decode hook for mapstructure.
+func WithDecodeHook(h mapstructure.DecodeHookFunc) Option {
+ return optionFunc(func(v *Viper) {
+ if h == nil {
+ return
+ }
+
+ v.decodeHook = h
+ })
+}
+
// NewWithOptions creates a new Viper instance.
func NewWithOptions(opts ...Option) *Viper {
v := New()
@@ -292,138 +277,32 @@ func NewWithOptions(opts ...Option) *Viper {
opt.apply(v)
}
- v.resetEncoding()
-
return v
}
+// SetOptions sets the options on the global Viper instance.
+//
+// Be careful when using this function: subsequent calls may override options you set.
+// It's always better to use a local Viper instance.
+func SetOptions(opts ...Option) {
+ for _, opt := range opts {
+ opt.apply(v)
+ }
+}
+
// Reset is intended for testing, will reset all to default settings.
// In the public interface for the viper package so applications
// can use it in their testing as well.
func Reset() {
v = New()
SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}
- SupportedRemoteProviders = []string{"etcd", "etcd3", "consul", "firestore", "nats"}
-}
-
-// TODO: make this lazy initialization instead.
-func (v *Viper) resetEncoding() {
- encoderRegistry := encoding.NewEncoderRegistry()
- decoderRegistry := encoding.NewDecoderRegistry()
-
- {
- codec := yaml.Codec{}
-
- encoderRegistry.RegisterEncoder("yaml", codec)
- decoderRegistry.RegisterDecoder("yaml", codec)
-
- encoderRegistry.RegisterEncoder("yml", codec)
- decoderRegistry.RegisterDecoder("yml", codec)
- }
-
- {
- codec := json.Codec{}
-
- encoderRegistry.RegisterEncoder("json", codec)
- decoderRegistry.RegisterDecoder("json", codec)
- }
-
- {
- codec := toml.Codec{}
-
- encoderRegistry.RegisterEncoder("toml", codec)
- decoderRegistry.RegisterDecoder("toml", codec)
- }
-
- {
- codec := hcl.Codec{}
-
- encoderRegistry.RegisterEncoder("hcl", codec)
- decoderRegistry.RegisterDecoder("hcl", codec)
-
- encoderRegistry.RegisterEncoder("tfvars", codec)
- decoderRegistry.RegisterDecoder("tfvars", codec)
- }
-
- {
- codec := ini.Codec{
- KeyDelimiter: v.keyDelim,
- LoadOptions: v.iniLoadOptions,
- }
-
- encoderRegistry.RegisterEncoder("ini", codec)
- decoderRegistry.RegisterDecoder("ini", codec)
- }
-
- {
- codec := &javaproperties.Codec{
- KeyDelimiter: v.keyDelim,
- }
-
- encoderRegistry.RegisterEncoder("properties", codec)
- decoderRegistry.RegisterDecoder("properties", codec)
-
- encoderRegistry.RegisterEncoder("props", codec)
- decoderRegistry.RegisterDecoder("props", codec)
-
- encoderRegistry.RegisterEncoder("prop", codec)
- decoderRegistry.RegisterDecoder("prop", codec)
- }
-
- {
- codec := &dotenv.Codec{}
-
- encoderRegistry.RegisterEncoder("dotenv", codec)
- decoderRegistry.RegisterDecoder("dotenv", codec)
-
- encoderRegistry.RegisterEncoder("env", codec)
- decoderRegistry.RegisterDecoder("env", codec)
- }
- v.encoderRegistry = encoderRegistry
- v.decoderRegistry = decoderRegistry
-}
-
-type defaultRemoteProvider struct {
- provider string
- endpoint string
- path string
- secretKeyring string
-}
-
-func (rp defaultRemoteProvider) Provider() string {
- return rp.provider
-}
-
-func (rp defaultRemoteProvider) Endpoint() string {
- return rp.endpoint
-}
-
-func (rp defaultRemoteProvider) Path() string {
- return rp.path
-}
-
-func (rp defaultRemoteProvider) SecretKeyring() string {
- return rp.secretKeyring
-}
-
-// RemoteProvider stores the configuration necessary
-// to connect to a remote key/value store.
-// Optional secretKeyring to unencrypt encrypted values
-// can be provided.
-type RemoteProvider interface {
- Provider() string
- Endpoint() string
- Path() string
- SecretKeyring() string
+ resetRemote()
}
// SupportedExts are universally supported extensions.
var SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}
-// SupportedRemoteProviders are universally supported remote providers.
-var SupportedRemoteProviders = []string{"etcd", "etcd3", "consul", "firestore", "nats"}
-
// OnConfigChange sets the event handler that is called when a config file changes.
func OnConfigChange(run func(in fsnotify.Event)) { v.OnConfigChange(run) }
@@ -574,90 +453,20 @@ func (v *Viper) ConfigFileUsed() string { return v.configFile }
func AddConfigPath(in string) { v.AddConfigPath(in) }
func (v *Viper) AddConfigPath(in string) {
+ if v.finder != nil {
+ v.logger.Warn("ineffective call to function: custom finder takes precedence", slog.String("function", "AddConfigPath"))
+ }
+
if in != "" {
absin := absPathify(v.logger, in)
v.logger.Info("adding path to search paths", "path", absin)
- if !stringInSlice(absin, v.configPaths) {
+ if !slices.Contains(v.configPaths, absin) {
v.configPaths = append(v.configPaths, absin)
}
}
}
-// AddRemoteProvider adds a remote configuration source.
-// Remote Providers are searched in the order they are added.
-// provider is a string value: "etcd", "etcd3", "consul", "firestore" or "nats" are currently supported.
-// endpoint is the url. etcd requires http://ip:port, consul requires ip:port, nats requires nats://ip:port
-// path is the path in the k/v store to retrieve configuration
-// To retrieve a config file called myapp.json from /configs/myapp.json
-// you should set path to /configs and set config name (SetConfigName()) to
-// "myapp".
-func AddRemoteProvider(provider, endpoint, path string) error {
- return v.AddRemoteProvider(provider, endpoint, path)
-}
-
-func (v *Viper) AddRemoteProvider(provider, endpoint, path string) error {
- if !stringInSlice(provider, SupportedRemoteProviders) {
- return UnsupportedRemoteProviderError(provider)
- }
- if provider != "" && endpoint != "" {
- v.logger.Info("adding remote provider", "provider", provider, "endpoint", endpoint)
-
- rp := &defaultRemoteProvider{
- endpoint: endpoint,
- provider: provider,
- path: path,
- }
- if !v.providerPathExists(rp) {
- v.remoteProviders = append(v.remoteProviders, rp)
- }
- }
- return nil
-}
-
-// AddSecureRemoteProvider adds a remote configuration source.
-// Secure Remote Providers are searched in the order they are added.
-// provider is a string value: "etcd", "etcd3", "consul", "firestore" or "nats" are currently supported.
-// endpoint is the url. etcd requires http://ip:port consul requires ip:port
-// secretkeyring is the filepath to your openpgp secret keyring. e.g. /etc/secrets/myring.gpg
-// path is the path in the k/v store to retrieve configuration
-// To retrieve a config file called myapp.json from /configs/myapp.json
-// you should set path to /configs and set config name (SetConfigName()) to
-// "myapp".
-// Secure Remote Providers are implemented with github.com/sagikazarmark/crypt.
-func AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error {
- return v.AddSecureRemoteProvider(provider, endpoint, path, secretkeyring)
-}
-
-func (v *Viper) AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error {
- if !stringInSlice(provider, SupportedRemoteProviders) {
- return UnsupportedRemoteProviderError(provider)
- }
- if provider != "" && endpoint != "" {
- v.logger.Info("adding remote provider", "provider", provider, "endpoint", endpoint)
-
- rp := &defaultRemoteProvider{
- endpoint: endpoint,
- provider: provider,
- path: path,
- secretKeyring: secretkeyring,
- }
- if !v.providerPathExists(rp) {
- v.remoteProviders = append(v.remoteProviders, rp)
- }
- }
- return nil
-}
-
-func (v *Viper) providerPathExists(p *defaultRemoteProvider) bool {
- for _, y := range v.remoteProviders {
- if reflect.DeepEqual(y, p) {
- return true
- }
- }
- return false
-}
-
// searchMap recursively searches for a value for path in source map.
// Returns nil if not found.
// Note: This assumes that the path entries and map keys are lower cased.
@@ -965,6 +774,7 @@ func (v *Viper) Sub(key string) *Viper {
subv.automaticEnvApplied = v.automaticEnvApplied
subv.envPrefix = v.envPrefix
subv.envKeyReplacer = v.envKeyReplacer
+ subv.keyDelim = v.keyDelim
subv.config = cast.ToStringMap(data)
return subv
}
@@ -1006,6 +816,13 @@ func (v *Viper) GetInt64(key string) int64 {
return cast.ToInt64(v.Get(key))
}
+// GetUint8 returns the value associated with the key as an unsigned integer.
+func GetUint8(key string) uint8 { return v.GetUint8(key) }
+
+func (v *Viper) GetUint8(key string) uint8 {
+ return cast.ToUint8(v.Get(key))
+}
+
// GetUint returns the value associated with the key as an unsigned integer.
func GetUint(key string) uint { return v.GetUint(key) }
@@ -1105,7 +922,7 @@ func UnmarshalKey(key string, rawVal any, 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), v.defaultDecoderConfig(rawVal, opts...))
}
// Unmarshal unmarshals the config into a Struct. Make sure that the tags
@@ -1117,7 +934,7 @@ func Unmarshal(rawVal any, opts ...DecoderConfigOption) error {
func (v *Viper) Unmarshal(rawVal any, opts ...DecoderConfigOption) error {
keys := v.AllKeys()
- if features.BindStruct {
+ if v.experimentalBindStruct {
// TODO: make this optional?
structKeys, err := v.decodeStructKeys(rawVal, opts...)
if err != nil {
@@ -1128,13 +945,13 @@ func (v *Viper) Unmarshal(rawVal any, opts ...DecoderConfigOption) error {
}
// TODO: struct keys should be enough?
- return decode(v.getSettings(keys), defaultDecoderConfig(rawVal, opts...))
+ return decode(v.getSettings(keys), v.defaultDecoderConfig(rawVal, opts...))
}
func (v *Viper) decodeStructKeys(input any, opts ...DecoderConfigOption) ([]string, error) {
var structKeyMap map[string]any
- err := decode(input, defaultDecoderConfig(&structKeyMap, opts...))
+ err := decode(input, v.defaultDecoderConfig(&structKeyMap, opts...))
if err != nil {
return nil, err
}
@@ -1151,22 +968,54 @@ func (v *Viper) decodeStructKeys(input any, opts ...DecoderConfigOption) ([]stri
// defaultDecoderConfig returns default mapstructure.DecoderConfig with support
// of time.Duration values & string slices.
-func defaultDecoderConfig(output any, opts ...DecoderConfigOption) *mapstructure.DecoderConfig {
+func (v *Viper) defaultDecoderConfig(output any, opts ...DecoderConfigOption) *mapstructure.DecoderConfig {
+ decodeHook := v.decodeHook
+ if decodeHook == nil {
+ decodeHook = mapstructure.ComposeDecodeHookFunc(
+ mapstructure.StringToTimeDurationHookFunc(),
+ // mapstructure.StringToSliceHookFunc(","),
+ stringToWeakSliceHookFunc(","),
+ )
+ }
+
c := &mapstructure.DecoderConfig{
Metadata: nil,
- Result: output,
WeaklyTypedInput: true,
- DecodeHook: mapstructure.ComposeDecodeHookFunc(
- mapstructure.StringToTimeDurationHookFunc(),
- mapstructure.StringToSliceHookFunc(","),
- ),
+ DecodeHook: decodeHook,
}
+
for _, opt := range opts {
opt(c)
}
+
+ // Do not allow overwriting the output
+ c.Result = output
+
return c
}
+// As of mapstructure v2.0.0 StringToSliceHookFunc checks if the return type is a string slice.
+// This function removes that check.
+// TODO: implement a function that checks if the value can be converted to the return type and use it instead.
+func stringToWeakSliceHookFunc(sep string) mapstructure.DecodeHookFunc {
+ return func(
+ f reflect.Type,
+ t reflect.Type,
+ data interface{},
+ ) (interface{}, error) {
+ if f.Kind() != reflect.String || t.Kind() != reflect.Slice {
+ return data, nil
+ }
+
+ raw := data.(string)
+ if raw == "" {
+ return []string{}, nil
+ }
+
+ return strings.Split(raw, sep), nil
+ }
+}
+
// decode is a wrapper around mapstructure.Decode that mimics the WeakDecode functionality.
func decode(input any, config *mapstructure.DecoderConfig) error {
decoder, err := mapstructure.NewDecoder(config)
@@ -1183,12 +1032,12 @@ func UnmarshalExact(rawVal any, opts ...DecoderConfigOption) error {
}
func (v *Viper) UnmarshalExact(rawVal any, opts ...DecoderConfigOption) error {
- config := defaultDecoderConfig(rawVal, opts...)
+ config := v.defaultDecoderConfig(rawVal, opts...)
config.ErrorUnused = true
keys := v.AllKeys()
- if features.BindStruct {
+ if v.experimentalBindStruct {
// TODO: make this optional?
structKeys, err := v.decodeStructKeys(rawVal, opts...)
if err != nil {
@@ -1638,7 +1487,7 @@ func (v *Viper) ReadInConfig() error {
return err
}
- if !stringInSlice(v.getConfigType(), SupportedExts) {
+ if !slices.Contains(SupportedExts, v.getConfigType()) {
return UnsupportedConfigError(v.getConfigType())
}
@@ -1669,7 +1518,7 @@ func (v *Viper) MergeInConfig() error {
return err
}
- if !stringInSlice(v.getConfigType(), SupportedExts) {
+ if !slices.Contains(SupportedExts, v.getConfigType()) {
return UnsupportedConfigError(v.getConfigType())
}
@@ -1686,6 +1535,10 @@ func (v *Viper) MergeInConfig() error {
func ReadConfig(in io.Reader) error { return v.ReadConfig(in) }
func (v *Viper) ReadConfig(in io.Reader) error {
+ if v.configType == "" {
+ return errors.New("cannot decode configuration: config type is not set")
+ }
+
v.config = make(map[string]any)
return v.unmarshalReader(in, v.config)
}
@@ -1694,6 +1547,10 @@ func (v *Viper) ReadConfig(in io.Reader) error {
func MergeConfig(in io.Reader) error { return v.MergeConfig(in) }
func (v *Viper) MergeConfig(in io.Reader) error {
+ if v.configType == "" {
+ return errors.New("cannot decode configuration: config type is not set")
+ }
+
cfg := make(map[string]any)
if err := v.unmarshalReader(in, cfg); err != nil {
return err
@@ -1742,6 +1599,19 @@ func (v *Viper) WriteConfigAs(filename string) error {
return v.writeConfig(filename, true)
}
+// WriteConfigTo writes current configuration to an [io.Writer].
+func WriteConfigTo(w io.Writer) error { return v.WriteConfigTo(w) }
+
+func (v *Viper) WriteConfigTo(w io.Writer) error {
+ format := strings.ToLower(v.getConfigType())
+
+ if !slices.Contains(SupportedExts, format) {
+ return UnsupportedConfigError(format)
+ }
+
+ return v.marshalWriter(w, format)
+}
+
// SafeWriteConfigAs writes current configuration to a given filename if it does not exist.
func SafeWriteConfigAs(filename string) error { return v.SafeWriteConfigAs(filename) }
@@ -1768,7 +1638,7 @@ func (v *Viper) writeConfig(filename string, force bool) error {
return fmt.Errorf("config type could not be determined for %s", filename)
}
- if !stringInSlice(configType, SupportedExts) {
+ if !slices.Contains(SupportedExts, configType) {
return UnsupportedConfigError(configType)
}
if v.config == nil {
@@ -1795,12 +1665,20 @@ func (v *Viper) unmarshalReader(in io.Reader, c map[string]any) error {
buf := new(bytes.Buffer)
buf.ReadFrom(in)
- switch format := strings.ToLower(v.getConfigType()); format {
- case "yaml", "yml", "json", "toml", "hcl", "tfvars", "ini", "properties", "props", "prop", "dotenv", "env":
- err := v.decoderRegistry.Decode(format, buf.Bytes(), c)
- if err != nil {
- return ConfigParseError{err}
- }
+ format := strings.ToLower(v.getConfigType())
+
+ if !slices.Contains(SupportedExts, format) {
+ return UnsupportedConfigError(format)
+ }
+
+ decoder, err := v.decoderRegistry.Decoder(format)
+ if err != nil {
+ return ConfigParseError{err}
+ }
+
+ err = decoder.Decode(buf.Bytes(), c)
+ if err != nil {
+ return ConfigParseError{err}
}
insensitiviseMap(c)
@@ -1808,20 +1686,24 @@ func (v *Viper) unmarshalReader(in io.Reader, c map[string]any) error {
}
// Marshal a map into Writer.
-func (v *Viper) marshalWriter(f afero.File, configType string) error {
+func (v *Viper) marshalWriter(w io.Writer, configType string) error {
c := v.AllSettings()
- switch configType {
- case "yaml", "yml", "json", "toml", "hcl", "tfvars", "ini", "prop", "props", "properties", "dotenv", "env":
- b, err := v.encoderRegistry.Encode(configType, c)
- if err != nil {
- return ConfigMarshalError{err}
- }
- _, err = f.WriteString(string(b))
- if err != nil {
- return ConfigMarshalError{err}
- }
+ encoder, err := v.encoderRegistry.Encoder(configType)
+ if err != nil {
+ return ConfigMarshalError{err}
}
+
+ b, err := encoder.Encode(c)
+ if err != nil {
+ return ConfigMarshalError{err}
+ }
+
+ _, err = w.Write(b)
+ if err != nil {
+ return ConfigMarshalError{err}
+ }
+
return nil
}
@@ -1953,106 +1835,6 @@ func mergeMaps(src, tgt map[string]any, itgt map[any]any) {
}
}
-// ReadRemoteConfig attempts to get configuration from a remote source
-// and read it in the remote configuration registry.
-func ReadRemoteConfig() error { return v.ReadRemoteConfig() }
-
-func (v *Viper) ReadRemoteConfig() error {
- return v.getKeyValueConfig()
-}
-
-func WatchRemoteConfig() error { return v.WatchRemoteConfig() }
-func (v *Viper) WatchRemoteConfig() error {
- return v.watchKeyValueConfig()
-}
-
-func (v *Viper) WatchRemoteConfigOnChannel() error {
- return v.watchKeyValueConfigOnChannel()
-}
-
-// Retrieve the first found remote configuration.
-func (v *Viper) getKeyValueConfig() error {
- if RemoteConfig == nil {
- return RemoteConfigError("Enable the remote features by doing a blank import of the viper/remote package: '_ github.com/spf13/viper/remote'")
- }
-
- if len(v.remoteProviders) == 0 {
- return RemoteConfigError("No Remote Providers")
- }
-
- for _, rp := range v.remoteProviders {
- val, err := v.getRemoteConfig(rp)
- if err != nil {
- v.logger.Error(fmt.Errorf("get remote config: %w", err).Error())
-
- continue
- }
-
- v.kvstore = val
-
- return nil
- }
- return RemoteConfigError("No Files Found")
-}
-
-func (v *Viper) getRemoteConfig(provider RemoteProvider) (map[string]any, error) {
- reader, err := RemoteConfig.Get(provider)
- if err != nil {
- return nil, err
- }
- err = v.unmarshalReader(reader, v.kvstore)
- return v.kvstore, err
-}
-
-// Retrieve the first found remote configuration.
-func (v *Viper) watchKeyValueConfigOnChannel() error {
- if len(v.remoteProviders) == 0 {
- return RemoteConfigError("No Remote Providers")
- }
-
- for _, rp := range v.remoteProviders {
- respc, _ := RemoteConfig.WatchChannel(rp)
- // Todo: Add quit channel
- go func(rc <-chan *RemoteResponse) {
- for {
- b := <-rc
- reader := bytes.NewReader(b.Value)
- v.unmarshalReader(reader, v.kvstore)
- }
- }(respc)
- return nil
- }
- return RemoteConfigError("No Files Found")
-}
-
-// Retrieve the first found remote configuration.
-func (v *Viper) watchKeyValueConfig() error {
- if len(v.remoteProviders) == 0 {
- return RemoteConfigError("No Remote Providers")
- }
-
- for _, rp := range v.remoteProviders {
- val, err := v.watchRemoteConfig(rp)
- if err != nil {
- v.logger.Error(fmt.Errorf("watch remote config: %w", err).Error())
-
- continue
- }
- v.kvstore = val
- return nil
- }
- return RemoteConfigError("No Files Found")
-}
-
-func (v *Viper) watchRemoteConfig(provider RemoteProvider) (map[string]any, error) {
- reader, err := RemoteConfig.Watch(provider)
- if err != nil {
- return nil, err
- }
- err = v.unmarshalReader(reader, v.kvstore)
- return v.kvstore, err
-}
-
// AllKeys returns all keys holding a value, regardless of where they are set.
// Nested keys are returned with a v.keyDelim separator.
func AllKeys() []string { return v.AllKeys() }
@@ -2174,6 +1956,10 @@ func (v *Viper) SetFs(fs afero.Fs) {
func SetConfigName(in string) { v.SetConfigName(in) }
func (v *Viper) SetConfigName(in string) {
+ if v.finder != nil {
+ v.logger.Warn("ineffective call to function: custom finder takes precedence", slog.String("function", "SetConfigName"))
+ }
+
if in != "" {
v.configName = in
v.configFile = ""
@@ -2197,13 +1983,6 @@ func (v *Viper) SetConfigPermissions(perm os.FileMode) {
v.configPermissions = perm.Perm()
}
-// IniLoadOptions sets the load options for ini parsing.
-func IniLoadOptions(in ini.LoadOptions) Option {
- return optionFunc(func(v *Viper) {
- v.iniLoadOptions = in
- })
-}
-
func (v *Viper) getConfigType() string {
if v.configType != "" {
return v.configType