mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-30 23:22:26 -05:00 
			
		
		
		
	[chore] bumps our spf13/viper version (#3943)
* bumps our spf13/viper version * fixes the one breaking change
This commit is contained in:
		
					parent
					
						
							
								1bf40e755c
							
						
					
				
			
			
				commit
				
					
						f46e490c30
					
				
			
		
					 147 changed files with 4637 additions and 18493 deletions
				
			
		
							
								
								
									
										3
									
								
								vendor/github.com/spf13/viper/.golangci.yaml
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/spf13/viper/.golangci.yaml
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -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 | ||||
|  |  | |||
							
								
								
									
										21
									
								
								vendor/github.com/spf13/viper/README.md
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/spf13/viper/README.md
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -3,7 +3,8 @@ | |||
| > | ||||
| > **Thank you!** | ||||
| 
 | ||||
|  | ||||
|  | ||||
| 
 | ||||
| 
 | ||||
| [](https://github.com/avelino/awesome-go#configuration) | ||||
| [](https://repl.it/@sagikazarmark/Viper-example#main.go) | ||||
|  | @ -11,7 +12,7 @@ | |||
| [](https://github.com/spf13/viper/actions?query=workflow%3ACI) | ||||
| [](https://gitter.im/spf13/viper?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) | ||||
| [](https://goreportcard.com/report/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. | ||||
| 
 | ||||
| In all of the examples above, they demonstrate using viper in its singleton | ||||
| style approach. | ||||
| 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. | ||||
| 
 | ||||
| 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 | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										126
									
								
								vendor/github.com/spf13/viper/UPDATES.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								vendor/github.com/spf13/viper/UPDATES.md
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -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), | ||||
| ) | ||||
| ``` | ||||
							
								
								
									
										181
									
								
								vendor/github.com/spf13/viper/encoding.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								vendor/github.com/spf13/viper/encoding.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -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 | ||||
| } | ||||
							
								
								
									
										8
									
								
								vendor/github.com/spf13/viper/experimental.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/spf13/viper/experimental.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -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 | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										54
									
								
								vendor/github.com/spf13/viper/file.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										54
									
								
								vendor/github.com/spf13/viper/file.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -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 { | ||||
|  |  | |||
							
								
								
									
										38
									
								
								vendor/github.com/spf13/viper/file_finder.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										38
									
								
								vendor/github.com/spf13/viper/file_finder.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -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 | ||||
| } | ||||
							
								
								
									
										55
									
								
								vendor/github.com/spf13/viper/finder.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								vendor/github.com/spf13/viper/finder.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -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...) | ||||
| } | ||||
							
								
								
									
										333
									
								
								vendor/github.com/spf13/viper/flake.lock
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										333
									
								
								vendor/github.com/spf13/viper/flake.lock
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,22 +1,84 @@ | |||
| { | ||||
|   "nodes": { | ||||
|     "devenv": { | ||||
|     "cachix": { | ||||
|       "inputs": { | ||||
|         "flake-compat": "flake-compat", | ||||
|         "nix": "nix", | ||||
|         "nixpkgs": "nixpkgs", | ||||
|         "pre-commit-hooks": "pre-commit-hooks" | ||||
|         "devenv": "devenv_2", | ||||
|         "flake-compat": [ | ||||
|           "devenv", | ||||
|           "flake-compat" | ||||
|         ], | ||||
|         "nixpkgs": [ | ||||
|           "devenv", | ||||
|           "nixpkgs" | ||||
|         ], | ||||
|         "pre-commit-hooks": [ | ||||
|           "devenv", | ||||
|           "pre-commit-hooks" | ||||
|         ] | ||||
|       }, | ||||
|       "locked": { | ||||
|         "lastModified": 1707817777, | ||||
|         "narHash": "sha256-vHyIs1OULQ3/91wD6xOiuayfI71JXALGA5KLnDKAcy0=", | ||||
|         "lastModified": 1712055811, | ||||
|         "narHash": "sha256-7FcfMm5A/f02yyzuavJe06zLa9hcMHsagE28ADcmQvk=", | ||||
|         "owner": "cachix", | ||||
|         "repo": "devenv", | ||||
|         "rev": "5a30b9e5ac7c6167e61b1f4193d5130bb9f8defa", | ||||
|         "repo": "cachix", | ||||
|         "rev": "02e38da89851ec7fec3356a5c04bc8349cae0e30", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|         "owner": "cachix", | ||||
|         "repo": "cachix", | ||||
|         "type": "github" | ||||
|       } | ||||
|     }, | ||||
|     "devenv": { | ||||
|       "inputs": { | ||||
|         "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", | ||||
|         "poetry2nix": "poetry2nix", | ||||
|         "pre-commit-hooks": [ | ||||
|           "devenv", | ||||
|           "cachix", | ||||
|           "pre-commit-hooks" | ||||
|         ] | ||||
|       }, | ||||
|       "locked": { | ||||
|         "lastModified": 1708704632, | ||||
|         "narHash": "sha256-w+dOIW60FKMaHI1q5714CSibk99JfYxm0CzTinYWr+Q=", | ||||
|         "owner": "cachix", | ||||
|         "repo": "devenv", | ||||
|         "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": "a1720a10a6cfe8234c0e93907ffe81be440f4cef", | ||||
|         "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": "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, | ||||
|       "locked": { | ||||
|         "lastModified": 1633514407, | ||||
|         "narHash": "sha256-Dw32tiMjdK9t3ETl5fzGrutQTzh2rufgZV4A/BbxuD4=", | ||||
|         "owner": "kristapsdz", | ||||
|         "repo": "lowdown", | ||||
|         "rev": "d2c2b44ff6c27b936ec27358a2653caaef8f73b8", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|         "owner": "kristapsdz", | ||||
|         "repo": "lowdown", | ||||
|         "type": "github" | ||||
|       } | ||||
|     }, | ||||
|     "nix": { | ||||
|       "inputs": { | ||||
|         "lowdown-src": "lowdown-src", | ||||
|         "flake-compat": "flake-compat", | ||||
|         "nixpkgs": [ | ||||
|           "devenv", | ||||
|           "cachix", | ||||
|           "devenv", | ||||
|           "nixpkgs" | ||||
|         ], | ||||
|         "nixpkgs-regression": "nixpkgs-regression" | ||||
|       }, | ||||
|       "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" | ||||
|       } | ||||
|     }, | ||||
|     "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": { | ||||
|         "flake-compat": [ | ||||
|           "devenv", | ||||
|           "flake-compat" | ||||
|         ], | ||||
|         "nixpkgs": [ | ||||
|           "devenv", | ||||
|           "nixpkgs" | ||||
|         ], | ||||
|         "nixpkgs-regression": "nixpkgs-regression_2" | ||||
|       }, | ||||
|       "locked": { | ||||
|         "lastModified": 1712911606, | ||||
|         "narHash": "sha256-BGvBhepCufsjcUkXnEEXhEVjwdJAwPglCC2+bInc794=", | ||||
|         "owner": "domenkozar", | ||||
|         "repo": "nix", | ||||
|         "rev": "b24a9318ea3f3600c1e24b4a00691ee912d4de12", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|         "owner": "domenkozar", | ||||
|         "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,20 +286,14 @@ | |||
|     }, | ||||
|     "nixpkgs-lib": { | ||||
|       "locked": { | ||||
|         "dir": "lib", | ||||
|         "lastModified": 1706550542, | ||||
|         "narHash": "sha256-UcsnCG6wx++23yeER4Hg18CXWbgNpqNXcHIo5/1Y+hc=", | ||||
|         "owner": "NixOS", | ||||
|         "repo": "nixpkgs", | ||||
|         "rev": "97b17f32362e475016f942bbdfda4a4a72a8a652", | ||||
|         "type": "github" | ||||
|         "lastModified": 1722555339, | ||||
|         "narHash": "sha256-uFf2QeW7eAHlYXuDktm9c25OxOyCoUOQmh5SZ9amE5Q=", | ||||
|         "type": "tarball", | ||||
|         "url": "https://github.com/NixOS/nixpkgs/archive/a5d394176e64ab29c852d03346c1fc9b0b7d33eb.tar.gz" | ||||
|       }, | ||||
|       "original": { | ||||
|         "dir": "lib", | ||||
|         "owner": "NixOS", | ||||
|         "ref": "nixos-unstable", | ||||
|         "repo": "nixpkgs", | ||||
|         "type": "github" | ||||
|         "type": "tarball", | ||||
|         "url": "https://github.com/NixOS/nixpkgs/archive/a5d394176e64ab29c852d03346c1fc9b0b7d33eb.tar.gz" | ||||
|       } | ||||
|     }, | ||||
|     "nixpkgs-regression": { | ||||
|  | @ -185,29 +312,61 @@ | |||
|         "type": "github" | ||||
|       } | ||||
|     }, | ||||
|     "nixpkgs-stable": { | ||||
|     "nixpkgs-regression_2": { | ||||
|       "locked": { | ||||
|         "lastModified": 1685801374, | ||||
|         "narHash": "sha256-otaSUoFEMM+LjBI1XL/xGB5ao6IwnZOXc47qhIgJe8U=", | ||||
|         "lastModified": 1643052045, | ||||
|         "narHash": "sha256-uGJ0VXIhWKGXxkeNnq4TvV3CIOkUJ3PAoLZ3HMzNVMw=", | ||||
|         "owner": "NixOS", | ||||
|         "repo": "nixpkgs", | ||||
|         "rev": "c37ca420157f4abc31e26f436c1145f8951ff373", | ||||
|         "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|         "owner": "NixOS", | ||||
|         "ref": "nixos-23.05", | ||||
|         "repo": "nixpkgs", | ||||
|         "rev": "215d4d0fd80ca5163643b03a33fde804a29cc1e2", | ||||
|         "type": "github" | ||||
|       } | ||||
|     }, | ||||
|     "nixpkgs-stable": { | ||||
|       "locked": { | ||||
|         "lastModified": 1710695816, | ||||
|         "narHash": "sha256-3Eh7fhEID17pv9ZxrPwCLfqXnYP006RKzSs0JptsN84=", | ||||
|         "owner": "NixOS", | ||||
|         "repo": "nixpkgs", | ||||
|         "rev": "614b4613980a522ba49f0d194531beddbb7220d3", | ||||
|         "type": "github" | ||||
|       }, | ||||
|       "original": { | ||||
|         "owner": "NixOS", | ||||
|         "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", | ||||
|  |  | |||
							
								
								
									
										2
									
								
								vendor/github.com/spf13/viper/flake.nix
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/spf13/viper/flake.nix
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -20,7 +20,7 @@ | |||
|           default = { | ||||
|             languages = { | ||||
|               go.enable = true; | ||||
|               go.package = pkgs.go_1_22; | ||||
|               go.package = pkgs.go_1_23; | ||||
|             }; | ||||
| 
 | ||||
|             pre-commit.hooks = { | ||||
|  |  | |||
							
								
								
									
										61
									
								
								vendor/github.com/spf13/viper/internal/encoding/decoder.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										61
									
								
								vendor/github.com/spf13/viper/internal/encoding/decoder.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -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) | ||||
| } | ||||
							
								
								
									
										60
									
								
								vendor/github.com/spf13/viper/internal/encoding/encoder.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										60
									
								
								vendor/github.com/spf13/viper/internal/encoding/encoder.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -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) | ||||
| } | ||||
							
								
								
									
										7
									
								
								vendor/github.com/spf13/viper/internal/encoding/error.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								vendor/github.com/spf13/viper/internal/encoding/error.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -1,7 +0,0 @@ | |||
| package encoding | ||||
| 
 | ||||
| type encodingError string | ||||
| 
 | ||||
| func (e encodingError) Error() string { | ||||
| 	return string(e) | ||||
| } | ||||
							
								
								
									
										40
									
								
								vendor/github.com/spf13/viper/internal/encoding/hcl/codec.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										40
									
								
								vendor/github.com/spf13/viper/internal/encoding/hcl/codec.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -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) | ||||
| } | ||||
							
								
								
									
										99
									
								
								vendor/github.com/spf13/viper/internal/encoding/ini/codec.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										99
									
								
								vendor/github.com/spf13/viper/internal/encoding/ini/codec.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -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 | ||||
| } | ||||
							
								
								
									
										74
									
								
								vendor/github.com/spf13/viper/internal/encoding/ini/map_utils.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										74
									
								
								vendor/github.com/spf13/viper/internal/encoding/ini/map_utils.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -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 | ||||
| } | ||||
							
								
								
									
										86
									
								
								vendor/github.com/spf13/viper/internal/encoding/javaproperties/codec.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										86
									
								
								vendor/github.com/spf13/viper/internal/encoding/javaproperties/codec.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -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 | ||||
| } | ||||
							
								
								
									
										74
									
								
								vendor/github.com/spf13/viper/internal/encoding/javaproperties/map_utils.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										74
									
								
								vendor/github.com/spf13/viper/internal/encoding/javaproperties/map_utils.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -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 | ||||
| } | ||||
							
								
								
									
										5
									
								
								vendor/github.com/spf13/viper/internal/features/finder.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/spf13/viper/internal/features/finder.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | |||
| //go:build viper_finder | ||||
| 
 | ||||
| package features | ||||
| 
 | ||||
| const Finder = true | ||||
							
								
								
									
										5
									
								
								vendor/github.com/spf13/viper/internal/features/finder_default.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/spf13/viper/internal/features/finder_default.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,5 @@ | |||
| //go:build !viper_finder | ||||
| 
 | ||||
| package features | ||||
| 
 | ||||
| const Finder = false | ||||
							
								
								
									
										39
									
								
								vendor/github.com/spf13/viper/logger.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/spf13/viper/logger.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -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) { | ||||
|  |  | |||
							
								
								
									
										256
									
								
								vendor/github.com/spf13/viper/remote.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										256
									
								
								vendor/github.com/spf13/viper/remote.go
									
										
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -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 | ||||
| } | ||||
							
								
								
									
										11
									
								
								vendor/github.com/spf13/viper/util.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										11
									
								
								vendor/github.com/spf13/viper/util.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -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") | ||||
|  |  | |||
							
								
								
									
										539
									
								
								vendor/github.com/spf13/viper/viper.go
									
										
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										539
									
								
								vendor/github.com/spf13/viper/viper.go
									
										
									
										generated
									
									
										vendored
									
									
								
							|  | @ -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 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue