mirror of
https://github.com/spf13/viper.git
synced 2026-09-20 11:18:40 +00:00
Compare commits
35
Commits
remote/v1.21.0
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
528f7416c4 | ||
|
|
bdc880d2f5 | ||
|
|
937ae2d3e6 | ||
|
|
2959599d7d | ||
|
|
15fb405454 | ||
|
|
c0965a201e | ||
|
|
cd5c582cff | ||
|
|
c2b66799cc | ||
|
|
6f44d6965b | ||
|
|
196113234f | ||
|
|
b3621ce3dd | ||
|
|
da507cf456 | ||
|
|
3504ce391d | ||
|
|
3c673554b5 | ||
|
|
315c2137bb | ||
|
|
7312e0f009 | ||
|
|
00a9d5df73 | ||
|
|
29eb8d3fc7 | ||
|
|
e8ab22ef25 | ||
|
|
5ae04a8bbf | ||
|
|
b9dfcc5b9e | ||
|
|
2d525ac880 | ||
|
|
ec92e64332 | ||
|
|
d8387f662f | ||
|
|
93dc9f6a62 | ||
|
|
0afb0456be | ||
|
|
2da50fe98c | ||
|
|
0525738e5e | ||
|
|
b5b5970f98 | ||
|
|
2220648d15 | ||
|
|
e66ee1a10e | ||
|
|
b127084a3e | ||
|
|
eadfaeec3f | ||
|
|
c4eab501d4 | ||
|
|
7a5ad96afc |
@@ -0,0 +1,5 @@
|
||||
permit(
|
||||
principal in Role::"Collaborator",
|
||||
action,
|
||||
resource
|
||||
);
|
||||
@@ -0,0 +1,5 @@
|
||||
permit(
|
||||
principal in Role::"Triager",
|
||||
action in [Action::"close", Action::"add-label", Action::"remove-label", Action::"self-assign", Action::"self-unassign"],
|
||||
resource
|
||||
);
|
||||
@@ -0,0 +1,12 @@
|
||||
[
|
||||
{
|
||||
"uid": { "type": "User", "id": "1226384" },
|
||||
"attrs": { "login": "sagikazarmark" },
|
||||
"parents": [{ "type": "Role", "id": "Collaborator" }]
|
||||
},
|
||||
{
|
||||
"uid": { "type": "User", "id": "805695" },
|
||||
"attrs": { "login": "spacez320" },
|
||||
"parents": [{ "type": "Role", "id": "Triager" }]
|
||||
}
|
||||
]
|
||||
@@ -4,6 +4,9 @@ on:
|
||||
pull_request:
|
||||
types: [opened, labeled, unlabeled, synchronize]
|
||||
|
||||
permissions:
|
||||
pull-requests: read
|
||||
|
||||
jobs:
|
||||
release-label:
|
||||
name: Release note label
|
||||
|
||||
@@ -5,6 +5,9 @@ on:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
|
||||
@@ -1,72 +0,0 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '22 16 * * 3'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'go' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
# Learn more:
|
||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
name: Octoslash
|
||||
|
||||
on: issue_comment
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
run:
|
||||
name: Run
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Octoslash
|
||||
uses: sagikazarmark/octoslash-action@v0
|
||||
@@ -4,6 +4,12 @@ on:
|
||||
schedule:
|
||||
- cron: "0 3 * * *"
|
||||
|
||||
permissions:
|
||||
actions: write
|
||||
issues: write
|
||||
# contents: write # only for delete-branch option
|
||||
# pull-requests: write
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
name: Stale
|
||||
@@ -17,5 +23,7 @@ jobs:
|
||||
days-before-pr-stale: -1 # Ignore all PRs
|
||||
stale-issue-message: "Issues with no activity for 30 days are marked stale and subject to being closed."
|
||||
close-issue-message: "This issue has been closed for inactivity. Please re-open if this was a mistake."
|
||||
stole-issue-label: "lifecycle/stale"
|
||||
debug-only: true # TODO for testing
|
||||
exempt-issue-labels: "lifecycle/keep"
|
||||
stale-issue-label: "lifecycle/stale"
|
||||
operations-per-run: 500 # Must respect GitHub API limits
|
||||
debug-only: false # Set this to 'true' to disable stale issue management
|
||||
|
||||
+32
-1
@@ -82,10 +82,41 @@ linters:
|
||||
- noctx
|
||||
path: _test.go
|
||||
presets:
|
||||
- comments
|
||||
- std-error-handling
|
||||
|
||||
settings:
|
||||
revive:
|
||||
rules:
|
||||
- name: blank-imports
|
||||
- name: context-as-argument
|
||||
arguments:
|
||||
- allowTypesBefore: "*testing.T"
|
||||
- name: context-keys-type
|
||||
- name: dot-imports
|
||||
- name: empty-block
|
||||
- name: error-naming
|
||||
- name: error-return
|
||||
- name: error-strings
|
||||
- name: errorf
|
||||
- name: exported
|
||||
arguments:
|
||||
- "sayRepetitiveInsteadOfStutters" # make error messages clearer
|
||||
- name: increment-decrement
|
||||
- name: indent-error-flow
|
||||
- name: package-comments
|
||||
disabled: true # disable package comments rule for now
|
||||
- name: range
|
||||
- name: redefines-builtin-id
|
||||
- name: superfluous-else
|
||||
- name: time-naming
|
||||
- name: unexported-return
|
||||
- name: unreachable-code
|
||||
- name: unused-parameter
|
||||
- name: var-declaration
|
||||
- name: var-naming
|
||||
|
||||
# TODO: add more revive rules
|
||||
|
||||
misspell:
|
||||
locale: US
|
||||
nolintlint:
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ type DecoderRegistry interface {
|
||||
Decoder(format string) (Decoder, error)
|
||||
}
|
||||
|
||||
// [CodecRegistry] combines [EncoderRegistry] and [DecoderRegistry] interfaces.
|
||||
// CodecRegistry combines [EncoderRegistry] and [DecoderRegistry] interfaces.
|
||||
type CodecRegistry interface {
|
||||
EncoderRegistry
|
||||
DecoderRegistry
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
package viper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// FileLookupError is returned when Viper cannot resolve a configuration file.
|
||||
//
|
||||
// This is meant to be a common interface for all file look-up errors, occurring either because a
|
||||
// file does not exist or because it cannot find any file matching finder criteria.
|
||||
type FileLookupError interface {
|
||||
error
|
||||
|
||||
fileLookup()
|
||||
}
|
||||
|
||||
// ConfigFileNotFoundError denotes failing to find a configuration file from a search.
|
||||
//
|
||||
// Deprecated: This is error wraps [FileNotFoundFromSearchError], which should be used instead.
|
||||
type ConfigFileNotFoundError struct {
|
||||
locations []string
|
||||
name string
|
||||
}
|
||||
|
||||
// Error returns the formatted error.
|
||||
func (e ConfigFileNotFoundError) Error() string {
|
||||
return e.Unwrap().Error()
|
||||
}
|
||||
|
||||
// Unwraps to FileNotFoundFromSearchError.
|
||||
func (e ConfigFileNotFoundError) Unwrap() error {
|
||||
return FileNotFoundFromSearchError(e)
|
||||
}
|
||||
|
||||
// FileNotFoundFromSearchError denotes failing to find a configuration file from a search.
|
||||
// Wraps ConfigFileNotFoundError.
|
||||
type FileNotFoundFromSearchError struct {
|
||||
locations []string
|
||||
name string
|
||||
}
|
||||
|
||||
func (e FileNotFoundFromSearchError) fileLookup() {}
|
||||
|
||||
// Error returns the formatted error.
|
||||
func (e FileNotFoundFromSearchError) Error() string {
|
||||
message := fmt.Sprintf("File %q not found", e.name)
|
||||
|
||||
if len(e.locations) > 0 {
|
||||
message += fmt.Sprintf(" in %v", e.locations)
|
||||
}
|
||||
|
||||
return message
|
||||
}
|
||||
|
||||
// FileNotFoundError denotes failing to find a specific configuration file.
|
||||
type FileNotFoundError struct {
|
||||
err error
|
||||
path string
|
||||
}
|
||||
|
||||
func (e FileNotFoundError) fileLookup() {}
|
||||
|
||||
// Error returns the formatted error.
|
||||
func (e FileNotFoundError) Error() string {
|
||||
return fmt.Sprintf("file not found: %s", e.path)
|
||||
}
|
||||
|
||||
// ConfigFileAlreadyExistsError denotes failure to write new configuration file.
|
||||
type ConfigFileAlreadyExistsError string
|
||||
|
||||
// Error returns the formatted error when configuration already exists.
|
||||
func (e ConfigFileAlreadyExistsError) Error() string {
|
||||
return fmt.Sprintf("Config File %q Already Exists", string(e))
|
||||
}
|
||||
|
||||
// ConfigMarshalError happens when failing to marshal the configuration.
|
||||
type ConfigMarshalError struct {
|
||||
err error
|
||||
}
|
||||
|
||||
// Error returns the formatted configuration error.
|
||||
func (e ConfigMarshalError) Error() string {
|
||||
return fmt.Sprintf("While marshaling config: %s", e.err.Error())
|
||||
}
|
||||
|
||||
// UnsupportedConfigError denotes encountering an unsupported
|
||||
// configuration filetype.
|
||||
type UnsupportedConfigError string
|
||||
|
||||
// Error returns the formatted configuration error.
|
||||
func (str UnsupportedConfigError) Error() string {
|
||||
return fmt.Sprintf("Unsupported Config Type %q", string(str))
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package viper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
@@ -50,7 +49,7 @@ func (v *Viper) findConfigFileWithFinder(finder Finder) (string, error) {
|
||||
}
|
||||
|
||||
if len(results) == 0 {
|
||||
return "", ConfigFileNotFoundError{v.configName, fmt.Sprintf("%s", v.configPaths)}
|
||||
return "", ConfigFileNotFoundError{name: v.configName, locations: v.configPaths}
|
||||
}
|
||||
|
||||
// We call clean on the final result to ensure that the path is in its canonical form.
|
||||
@@ -69,7 +68,7 @@ func (v *Viper) findConfigFileOld() (string, error) {
|
||||
return file, nil
|
||||
}
|
||||
}
|
||||
return "", ConfigFileNotFoundError{v.configName, fmt.Sprintf("%s", v.configPaths)}
|
||||
return "", ConfigFileNotFoundError{name: v.configName, locations: v.configPaths}
|
||||
}
|
||||
|
||||
func (v *Viper) searchInPath(in string) (filename string) {
|
||||
|
||||
@@ -6,7 +6,7 @@ require (
|
||||
github.com/fsnotify/fsnotify v1.9.0
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0
|
||||
github.com/pelletier/go-toml/v2 v2.2.4
|
||||
github.com/sagikazarmark/locafero v0.11.0
|
||||
github.com/sagikazarmark/locafero v0.12.0
|
||||
github.com/spf13/afero v1.15.0
|
||||
github.com/spf13/cast v1.10.0
|
||||
github.com/spf13/pflag v1.0.10
|
||||
@@ -19,8 +19,8 @@ require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
||||
@@ -18,10 +18,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
|
||||
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
|
||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
|
||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
|
||||
github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4=
|
||||
github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI=
|
||||
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
|
||||
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
|
||||
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
||||
|
||||
@@ -15,6 +15,7 @@ const keyDelimiter = "_"
|
||||
// (commonly called as dotenv format).
|
||||
type Codec struct{}
|
||||
|
||||
// Encode encodes a map[string]any into a dotenv byte slice.
|
||||
func (Codec) Encode(v map[string]any) ([]byte, error) {
|
||||
flattened := map[string]any{}
|
||||
|
||||
@@ -40,6 +41,7 @@ func (Codec) Encode(v map[string]any) ([]byte, error) {
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
// Decode decodes a dotenv byte slice into a map[string]any.
|
||||
func (Codec) Decode(b []byte, v map[string]any) error {
|
||||
var buf bytes.Buffer
|
||||
|
||||
|
||||
@@ -7,11 +7,13 @@ import (
|
||||
// Codec implements the encoding.Encoder and encoding.Decoder interfaces for JSON encoding.
|
||||
type Codec struct{}
|
||||
|
||||
// Encode encodes a map[string]any into a JSON byte slice.
|
||||
func (Codec) Encode(v map[string]any) ([]byte, error) {
|
||||
// TODO: expose prefix and indent in the Codec as setting?
|
||||
return json.MarshalIndent(v, "", " ")
|
||||
}
|
||||
|
||||
// Decode decodes a JSON byte slice into a map[string]any.
|
||||
func (Codec) Decode(b []byte, v map[string]any) error {
|
||||
return json.Unmarshal(b, &v)
|
||||
}
|
||||
|
||||
@@ -7,10 +7,12 @@ import (
|
||||
// Codec implements the encoding.Encoder and encoding.Decoder interfaces for TOML encoding.
|
||||
type Codec struct{}
|
||||
|
||||
// Encode encodes a map[string]any into a TOML byte slice.
|
||||
func (Codec) Encode(v map[string]any) ([]byte, error) {
|
||||
return toml.Marshal(v)
|
||||
}
|
||||
|
||||
// Decode decodes a TOML byte slice into a map[string]any.
|
||||
func (Codec) Decode(b []byte, v map[string]any) error {
|
||||
return toml.Unmarshal(b, &v)
|
||||
}
|
||||
|
||||
@@ -5,10 +5,12 @@ import "go.yaml.in/yaml/v3"
|
||||
// Codec implements the encoding.Encoder and encoding.Decoder interfaces for YAML encoding.
|
||||
type Codec struct{}
|
||||
|
||||
// Encode encodes a map[string]any into a YAML byte slice.
|
||||
func (Codec) Encode(v map[string]any) ([]byte, error) {
|
||||
return yaml.Marshal(v)
|
||||
}
|
||||
|
||||
// Decode decodes a YAML byte slice into a map[string]any.
|
||||
func (Codec) Decode(b []byte, v map[string]any) error {
|
||||
return yaml.Unmarshal(b, &v)
|
||||
}
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
|
||||
package features
|
||||
|
||||
// BindStruct is a feature flag for enabling/disabling the config binding to structs.
|
||||
const BindStruct = true
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
|
||||
package features
|
||||
|
||||
// BindStruct is a feature flag for enabling/disabling the config binding to structs.
|
||||
const BindStruct = false
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
|
||||
package features
|
||||
|
||||
// Finder is a feature flag for enabling/disabling the config finder.
|
||||
const Finder = true
|
||||
|
||||
@@ -2,4 +2,5 @@
|
||||
|
||||
package features
|
||||
|
||||
// Finder is a feature flag for enabling/disabling the config finder.
|
||||
const Finder = false
|
||||
|
||||
@@ -21,6 +21,7 @@ type remoteConfigFactory interface {
|
||||
WatchChannel(rp RemoteProvider) (<-chan *RemoteResponse, chan bool)
|
||||
}
|
||||
|
||||
// RemoteResponse represents a response from a remote configuration provider.
|
||||
type RemoteResponse struct {
|
||||
Value []byte
|
||||
Error error
|
||||
@@ -93,6 +94,14 @@ func AddRemoteProvider(provider, endpoint, path string) error {
|
||||
return v.AddRemoteProvider(provider, endpoint, path)
|
||||
}
|
||||
|
||||
// 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 (v *Viper) AddRemoteProvider(provider, endpoint, path string) error {
|
||||
if !slices.Contains(SupportedRemoteProviders, provider) {
|
||||
return UnsupportedRemoteProviderError(provider)
|
||||
@@ -126,6 +135,16 @@ func AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) err
|
||||
return v.AddSecureRemoteProvider(provider, endpoint, path, secretkeyring)
|
||||
}
|
||||
|
||||
// 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 (v *Viper) AddSecureRemoteProvider(provider, endpoint, path, secretkeyring string) error {
|
||||
if !slices.Contains(SupportedRemoteProviders, provider) {
|
||||
return UnsupportedRemoteProviderError(provider)
|
||||
@@ -159,15 +178,21 @@ func (v *Viper) providerPathExists(p *defaultRemoteProvider) bool {
|
||||
// and read it in the remote configuration registry.
|
||||
func ReadRemoteConfig() error { return v.ReadRemoteConfig() }
|
||||
|
||||
// ReadRemoteConfig attempts to get configuration from a remote source
|
||||
// and read it in the remote configuration registry.
|
||||
func (v *Viper) ReadRemoteConfig() error {
|
||||
return v.getKeyValueConfig()
|
||||
}
|
||||
|
||||
// WatchRemoteConfig updates configuration from available remote providers.
|
||||
func WatchRemoteConfig() error { return v.WatchRemoteConfig() }
|
||||
|
||||
// WatchRemoteConfig updates configuration from available remote providers.
|
||||
func (v *Viper) WatchRemoteConfig() error {
|
||||
return v.watchKeyValueConfig()
|
||||
}
|
||||
|
||||
// WatchRemoteConfigOnChannel updates configuration from available remote providers.
|
||||
func (v *Viper) WatchRemoteConfigOnChannel() error {
|
||||
return v.watchKeyValueConfigOnChannel()
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
fs "io/fs"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -44,49 +45,12 @@ import (
|
||||
"github.com/spf13/viper/internal/features"
|
||||
)
|
||||
|
||||
// ConfigMarshalError happens when failing to marshal the configuration.
|
||||
type ConfigMarshalError struct {
|
||||
err error
|
||||
}
|
||||
|
||||
// Error returns the formatted configuration error.
|
||||
func (e ConfigMarshalError) Error() string {
|
||||
return fmt.Sprintf("While marshaling config: %s", e.err.Error())
|
||||
}
|
||||
|
||||
var v *Viper
|
||||
|
||||
func init() {
|
||||
v = New()
|
||||
}
|
||||
|
||||
// UnsupportedConfigError denotes encountering an unsupported
|
||||
// configuration filetype.
|
||||
type UnsupportedConfigError string
|
||||
|
||||
// Error returns the formatted configuration error.
|
||||
func (str UnsupportedConfigError) Error() string {
|
||||
return fmt.Sprintf("Unsupported Config Type %q", string(str))
|
||||
}
|
||||
|
||||
// ConfigFileNotFoundError denotes failing to find configuration file.
|
||||
type ConfigFileNotFoundError struct {
|
||||
name, locations string
|
||||
}
|
||||
|
||||
// Error returns the formatted configuration error.
|
||||
func (fnfe ConfigFileNotFoundError) Error() string {
|
||||
return fmt.Sprintf("Config File %q Not Found in %q", fnfe.name, fnfe.locations)
|
||||
}
|
||||
|
||||
// ConfigFileAlreadyExistsError denotes failure to write new configuration file.
|
||||
type ConfigFileAlreadyExistsError string
|
||||
|
||||
// Error returns the formatted error when configuration already exists.
|
||||
func (faee ConfigFileAlreadyExistsError) Error() string {
|
||||
return fmt.Sprintf("Config File %q Already Exists", string(faee))
|
||||
}
|
||||
|
||||
// A DecoderConfigOption can be passed to viper.Unmarshal to configure
|
||||
// mapstructure.DecoderConfig options.
|
||||
type DecoderConfigOption func(*mapstructure.DecoderConfig)
|
||||
@@ -392,6 +356,8 @@ func (v *Viper) WatchConfig() {
|
||||
// Viper will use this and not check any of the config paths.
|
||||
func SetConfigFile(in string) { v.SetConfigFile(in) }
|
||||
|
||||
// SetConfigFile explicitly defines the path, name and extension of the config file.
|
||||
// Viper will use this and not check any of the config paths.
|
||||
func (v *Viper) SetConfigFile(in string) {
|
||||
if in != "" {
|
||||
v.configFile = in
|
||||
@@ -403,14 +369,19 @@ func (v *Viper) SetConfigFile(in string) {
|
||||
// variables that start with "SPF_".
|
||||
func SetEnvPrefix(in string) { v.SetEnvPrefix(in) }
|
||||
|
||||
// SetEnvPrefix defines a prefix that ENVIRONMENT variables will use.
|
||||
// E.g. if your prefix is "spf", the env registry will look for env
|
||||
// variables that start with "SPF_".
|
||||
func (v *Viper) SetEnvPrefix(in string) {
|
||||
if in != "" {
|
||||
v.envPrefix = in
|
||||
}
|
||||
}
|
||||
|
||||
// GetEnvPrefix returns the environment variable prefix.
|
||||
func GetEnvPrefix() string { return v.GetEnvPrefix() }
|
||||
|
||||
// GetEnvPrefix returns the environment variable prefix.
|
||||
func (v *Viper) GetEnvPrefix() string {
|
||||
return v.envPrefix
|
||||
}
|
||||
@@ -428,6 +399,9 @@ func (v *Viper) mergeWithEnvPrefix(in string) string {
|
||||
// For backward compatibility reasons this is false by default.
|
||||
func AllowEmptyEnv(allowEmptyEnv bool) { v.AllowEmptyEnv(allowEmptyEnv) }
|
||||
|
||||
// AllowEmptyEnv tells Viper to consider set,
|
||||
// but empty environment variables as valid values instead of falling back.
|
||||
// For backward compatibility reasons this is false by default.
|
||||
func (v *Viper) AllowEmptyEnv(allowEmptyEnv bool) {
|
||||
v.allowEmptyEnv = allowEmptyEnv
|
||||
}
|
||||
@@ -450,13 +424,17 @@ func (v *Viper) getEnv(key string) (string, bool) {
|
||||
}
|
||||
|
||||
// ConfigFileUsed returns the file used to populate the config registry.
|
||||
func ConfigFileUsed() string { return v.ConfigFileUsed() }
|
||||
func ConfigFileUsed() string { return v.ConfigFileUsed() }
|
||||
|
||||
// ConfigFileUsed returns the file used to populate the config registry.
|
||||
func (v *Viper) ConfigFileUsed() string { return v.configFile }
|
||||
|
||||
// AddConfigPath adds a path for Viper to search for the config file in.
|
||||
// Can be called multiple times to define multiple search paths.
|
||||
func AddConfigPath(in string) { v.AddConfigPath(in) }
|
||||
|
||||
// AddConfigPath adds a path for Viper to search for the config file in.
|
||||
// Can be called multiple times to define multiple search paths.
|
||||
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"))
|
||||
@@ -695,6 +673,20 @@ func (v *Viper) isPathShadowedInAutoEnv(path []string) string {
|
||||
// "a b c"
|
||||
func SetTypeByDefaultValue(enable bool) { v.SetTypeByDefaultValue(enable) }
|
||||
|
||||
// SetTypeByDefaultValue enables or disables the inference of a key value's
|
||||
// type when the Get function is used based upon a key's default value as
|
||||
// opposed to the value returned based on the normal fetch logic.
|
||||
//
|
||||
// For example, if a key has a default value of []string{} and the same key
|
||||
// is set via an environment variable to "a b c", a call to the Get function
|
||||
// would return a string slice for the key if the key's type is inferred by
|
||||
// the default value and the Get function would return:
|
||||
//
|
||||
// []string {"a", "b", "c"}
|
||||
//
|
||||
// Otherwise the Get function would return:
|
||||
//
|
||||
// "a b c"
|
||||
func (v *Viper) SetTypeByDefaultValue(enable bool) {
|
||||
v.typeByDefValue = enable
|
||||
}
|
||||
@@ -713,6 +705,13 @@ func GetViper() *Viper {
|
||||
// Get returns an interface. For a specific value use one of the Get____ methods.
|
||||
func Get(key string) any { return v.Get(key) }
|
||||
|
||||
// Get retrieves the value associated with the key.
|
||||
// Get is case-insensitive for a key.
|
||||
// Get has the behavior of returning the value associated with the first
|
||||
// place from where it is set. Viper will check in the following order:
|
||||
// override, flag, env, config file, key/value store, default
|
||||
//
|
||||
// Get returns an interface. For a specific value use one of the Get____ methods.
|
||||
func (v *Viper) Get(key string) any {
|
||||
lcaseKey := strings.ToLower(key)
|
||||
val := v.find(lcaseKey, true)
|
||||
@@ -766,6 +765,8 @@ func (v *Viper) Get(key string) any {
|
||||
// Sub is case-insensitive for a key.
|
||||
func Sub(key string) *Viper { return v.Sub(key) }
|
||||
|
||||
// Sub returns a new Viper instance representing a sub tree of this instance.
|
||||
// Sub is case-insensitive for a key.
|
||||
func (v *Viper) Sub(key string) *Viper {
|
||||
subv := New()
|
||||
data := v.Get(key)
|
||||
@@ -789,6 +790,7 @@ func (v *Viper) Sub(key string) *Viper {
|
||||
// GetString returns the value associated with the key as a string.
|
||||
func GetString(key string) string { return v.GetString(key) }
|
||||
|
||||
// GetString returns the value associated with the key as a string.
|
||||
func (v *Viper) GetString(key string) string {
|
||||
return cast.ToString(v.Get(key))
|
||||
}
|
||||
@@ -796,6 +798,7 @@ func (v *Viper) GetString(key string) string {
|
||||
// GetBool returns the value associated with the key as a boolean.
|
||||
func GetBool(key string) bool { return v.GetBool(key) }
|
||||
|
||||
// GetBool returns the value associated with the key as a boolean.
|
||||
func (v *Viper) GetBool(key string) bool {
|
||||
return cast.ToBool(v.Get(key))
|
||||
}
|
||||
@@ -803,6 +806,7 @@ func (v *Viper) GetBool(key string) bool {
|
||||
// GetInt returns the value associated with the key as an integer.
|
||||
func GetInt(key string) int { return v.GetInt(key) }
|
||||
|
||||
// GetInt returns the value associated with the key as an integer.
|
||||
func (v *Viper) GetInt(key string) int {
|
||||
return cast.ToInt(v.Get(key))
|
||||
}
|
||||
@@ -810,6 +814,7 @@ func (v *Viper) GetInt(key string) int {
|
||||
// GetInt32 returns the value associated with the key as an integer.
|
||||
func GetInt32(key string) int32 { return v.GetInt32(key) }
|
||||
|
||||
// GetInt32 returns the value associated with the key as an integer.
|
||||
func (v *Viper) GetInt32(key string) int32 {
|
||||
return cast.ToInt32(v.Get(key))
|
||||
}
|
||||
@@ -817,6 +822,7 @@ func (v *Viper) GetInt32(key string) int32 {
|
||||
// GetInt64 returns the value associated with the key as an integer.
|
||||
func GetInt64(key string) int64 { return v.GetInt64(key) }
|
||||
|
||||
// GetInt64 returns the value associated with the key as an integer.
|
||||
func (v *Viper) GetInt64(key string) int64 {
|
||||
return cast.ToInt64(v.Get(key))
|
||||
}
|
||||
@@ -824,6 +830,7 @@ func (v *Viper) GetInt64(key string) int64 {
|
||||
// GetUint8 returns the value associated with the key as an unsigned integer.
|
||||
func GetUint8(key string) uint8 { return v.GetUint8(key) }
|
||||
|
||||
// GetUint8 returns the value associated with the key as an unsigned integer.
|
||||
func (v *Viper) GetUint8(key string) uint8 {
|
||||
return cast.ToUint8(v.Get(key))
|
||||
}
|
||||
@@ -831,6 +838,7 @@ func (v *Viper) GetUint8(key string) uint8 {
|
||||
// GetUint returns the value associated with the key as an unsigned integer.
|
||||
func GetUint(key string) uint { return v.GetUint(key) }
|
||||
|
||||
// GetUint returns the value associated with the key as an unsigned integer.
|
||||
func (v *Viper) GetUint(key string) uint {
|
||||
return cast.ToUint(v.Get(key))
|
||||
}
|
||||
@@ -838,6 +846,7 @@ func (v *Viper) GetUint(key string) uint {
|
||||
// GetUint16 returns the value associated with the key as an unsigned integer.
|
||||
func GetUint16(key string) uint16 { return v.GetUint16(key) }
|
||||
|
||||
// GetUint16 returns the value associated with the key as an unsigned integer.
|
||||
func (v *Viper) GetUint16(key string) uint16 {
|
||||
return cast.ToUint16(v.Get(key))
|
||||
}
|
||||
@@ -845,6 +854,7 @@ func (v *Viper) GetUint16(key string) uint16 {
|
||||
// GetUint32 returns the value associated with the key as an unsigned integer.
|
||||
func GetUint32(key string) uint32 { return v.GetUint32(key) }
|
||||
|
||||
// GetUint32 returns the value associated with the key as an unsigned integer.
|
||||
func (v *Viper) GetUint32(key string) uint32 {
|
||||
return cast.ToUint32(v.Get(key))
|
||||
}
|
||||
@@ -852,6 +862,7 @@ func (v *Viper) GetUint32(key string) uint32 {
|
||||
// GetUint64 returns the value associated with the key as an unsigned integer.
|
||||
func GetUint64(key string) uint64 { return v.GetUint64(key) }
|
||||
|
||||
// GetUint64 returns the value associated with the key as an unsigned integer.
|
||||
func (v *Viper) GetUint64(key string) uint64 {
|
||||
return cast.ToUint64(v.Get(key))
|
||||
}
|
||||
@@ -859,6 +870,7 @@ func (v *Viper) GetUint64(key string) uint64 {
|
||||
// GetFloat64 returns the value associated with the key as a float64.
|
||||
func GetFloat64(key string) float64 { return v.GetFloat64(key) }
|
||||
|
||||
// GetFloat64 returns the value associated with the key as a float64.
|
||||
func (v *Viper) GetFloat64(key string) float64 {
|
||||
return cast.ToFloat64(v.Get(key))
|
||||
}
|
||||
@@ -866,6 +878,7 @@ func (v *Viper) GetFloat64(key string) float64 {
|
||||
// GetTime returns the value associated with the key as time.
|
||||
func GetTime(key string) time.Time { return v.GetTime(key) }
|
||||
|
||||
// GetTime returns the value associated with the key as time.
|
||||
func (v *Viper) GetTime(key string) time.Time {
|
||||
return cast.ToTime(v.Get(key))
|
||||
}
|
||||
@@ -873,6 +886,7 @@ func (v *Viper) GetTime(key string) time.Time {
|
||||
// GetDuration returns the value associated with the key as a duration.
|
||||
func GetDuration(key string) time.Duration { return v.GetDuration(key) }
|
||||
|
||||
// GetDuration returns the value associated with the key as a duration.
|
||||
func (v *Viper) GetDuration(key string) time.Duration {
|
||||
return cast.ToDuration(v.Get(key))
|
||||
}
|
||||
@@ -880,6 +894,7 @@ func (v *Viper) GetDuration(key string) time.Duration {
|
||||
// GetIntSlice returns the value associated with the key as a slice of int values.
|
||||
func GetIntSlice(key string) []int { return v.GetIntSlice(key) }
|
||||
|
||||
// GetIntSlice returns the value associated with the key as a slice of int values.
|
||||
func (v *Viper) GetIntSlice(key string) []int {
|
||||
return cast.ToIntSlice(v.Get(key))
|
||||
}
|
||||
@@ -887,6 +902,7 @@ func (v *Viper) GetIntSlice(key string) []int {
|
||||
// GetStringSlice returns the value associated with the key as a slice of strings.
|
||||
func GetStringSlice(key string) []string { return v.GetStringSlice(key) }
|
||||
|
||||
// GetStringSlice returns the value associated with the key as a slice of strings.
|
||||
func (v *Viper) GetStringSlice(key string) []string {
|
||||
return cast.ToStringSlice(v.Get(key))
|
||||
}
|
||||
@@ -894,6 +910,7 @@ func (v *Viper) GetStringSlice(key string) []string {
|
||||
// GetStringMap returns the value associated with the key as a map of interfaces.
|
||||
func GetStringMap(key string) map[string]any { return v.GetStringMap(key) }
|
||||
|
||||
// GetStringMap returns the value associated with the key as a map of interfaces.
|
||||
func (v *Viper) GetStringMap(key string) map[string]any {
|
||||
return cast.ToStringMap(v.Get(key))
|
||||
}
|
||||
@@ -901,6 +918,7 @@ func (v *Viper) GetStringMap(key string) map[string]any {
|
||||
// GetStringMapString returns the value associated with the key as a map of strings.
|
||||
func GetStringMapString(key string) map[string]string { return v.GetStringMapString(key) }
|
||||
|
||||
// GetStringMapString returns the value associated with the key as a map of strings.
|
||||
func (v *Viper) GetStringMapString(key string) map[string]string {
|
||||
return cast.ToStringMapString(v.Get(key))
|
||||
}
|
||||
@@ -908,6 +926,7 @@ func (v *Viper) GetStringMapString(key string) map[string]string {
|
||||
// GetStringMapStringSlice returns the value associated with the key as a map to a slice of strings.
|
||||
func GetStringMapStringSlice(key string) map[string][]string { return v.GetStringMapStringSlice(key) }
|
||||
|
||||
// GetStringMapStringSlice returns the value associated with the key as a map to a slice of strings.
|
||||
func (v *Viper) GetStringMapStringSlice(key string) map[string][]string {
|
||||
return cast.ToStringMapStringSlice(v.Get(key))
|
||||
}
|
||||
@@ -916,6 +935,8 @@ func (v *Viper) GetStringMapStringSlice(key string) map[string][]string {
|
||||
// in bytes.
|
||||
func GetSizeInBytes(key string) uint { return v.GetSizeInBytes(key) }
|
||||
|
||||
// GetSizeInBytes returns the size of the value associated with the given key
|
||||
// in bytes.
|
||||
func (v *Viper) GetSizeInBytes(key string) uint {
|
||||
sizeStr := cast.ToString(v.Get(key))
|
||||
return parseSizeInBytes(sizeStr)
|
||||
@@ -926,6 +947,7 @@ func UnmarshalKey(key string, rawVal any, opts ...DecoderConfigOption) error {
|
||||
return v.UnmarshalKey(key, rawVal, opts...)
|
||||
}
|
||||
|
||||
// UnmarshalKey takes a single key and unmarshals it into a Struct.
|
||||
func (v *Viper) UnmarshalKey(key string, rawVal any, opts ...DecoderConfigOption) error {
|
||||
return decode(v.Get(key), v.defaultDecoderConfig(rawVal, opts...))
|
||||
}
|
||||
@@ -936,6 +958,8 @@ func Unmarshal(rawVal any, opts ...DecoderConfigOption) error {
|
||||
return v.Unmarshal(rawVal, opts...)
|
||||
}
|
||||
|
||||
// Unmarshal unmarshals the config into a Struct. Make sure that the tags
|
||||
// on the fields of the structure are properly set.
|
||||
func (v *Viper) Unmarshal(rawVal any, opts ...DecoderConfigOption) error {
|
||||
keys := v.AllKeys()
|
||||
|
||||
@@ -1036,6 +1060,8 @@ func UnmarshalExact(rawVal any, opts ...DecoderConfigOption) error {
|
||||
return v.UnmarshalExact(rawVal, opts...)
|
||||
}
|
||||
|
||||
// UnmarshalExact unmarshals the config into a Struct, erroring if a field is nonexistent
|
||||
// in the destination struct.
|
||||
func (v *Viper) UnmarshalExact(rawVal any, opts ...DecoderConfigOption) error {
|
||||
config := v.defaultDecoderConfig(rawVal, opts...)
|
||||
config.ErrorUnused = true
|
||||
@@ -1060,6 +1086,8 @@ func (v *Viper) UnmarshalExact(rawVal any, opts ...DecoderConfigOption) error {
|
||||
// name as the config key.
|
||||
func BindPFlags(flags *pflag.FlagSet) error { return v.BindPFlags(flags) }
|
||||
|
||||
// BindPFlags binds a full flag set to the configuration, using each flag's long
|
||||
// name as the config key.
|
||||
func (v *Viper) BindPFlags(flags *pflag.FlagSet) error {
|
||||
return v.BindFlagValues(pflagValueSet{flags})
|
||||
}
|
||||
@@ -1071,6 +1099,11 @@ func (v *Viper) BindPFlags(flags *pflag.FlagSet) error {
|
||||
// Viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))
|
||||
func BindPFlag(key string, flag *pflag.Flag) error { return v.BindPFlag(key, flag) }
|
||||
|
||||
// BindPFlag binds a specific key to a pflag (as used by cobra).
|
||||
// Example (where serverCmd is a Cobra instance):
|
||||
//
|
||||
// serverCmd.Flags().Int("port", 1138, "Port to run Application server on")
|
||||
// Viper.BindPFlag("port", serverCmd.Flags().Lookup("port"))
|
||||
func (v *Viper) BindPFlag(key string, flag *pflag.Flag) error {
|
||||
if flag == nil {
|
||||
return fmt.Errorf("flag for %q is nil", key)
|
||||
@@ -1082,6 +1115,8 @@ func (v *Viper) BindPFlag(key string, flag *pflag.Flag) error {
|
||||
// name as the config key.
|
||||
func BindFlagValues(flags FlagValueSet) error { return v.BindFlagValues(flags) }
|
||||
|
||||
// BindFlagValues binds a full FlagValue set to the configuration, using each flag's long
|
||||
// name as the config key.
|
||||
func (v *Viper) BindFlagValues(flags FlagValueSet) (err error) {
|
||||
flags.VisitAll(func(flag FlagValue) {
|
||||
if err = v.BindFlagValue(flag.Name(), flag); err != nil {
|
||||
@@ -1094,6 +1129,7 @@ func (v *Viper) BindFlagValues(flags FlagValueSet) (err error) {
|
||||
// BindFlagValue binds a specific key to a FlagValue.
|
||||
func BindFlagValue(key string, flag FlagValue) error { return v.BindFlagValue(key, flag) }
|
||||
|
||||
// BindFlagValue binds a specific key to a FlagValue.
|
||||
func (v *Viper) BindFlagValue(key string, flag FlagValue) error {
|
||||
if flag == nil {
|
||||
return fmt.Errorf("flag for %q is nil", key)
|
||||
@@ -1110,6 +1146,12 @@ func (v *Viper) BindFlagValue(key string, flag FlagValue) error {
|
||||
// EnvPrefix will be used when set when env name is not provided.
|
||||
func BindEnv(input ...string) error { return v.BindEnv(input...) }
|
||||
|
||||
// BindEnv binds a Viper key to a ENV variable.
|
||||
// ENV variables are case sensitive.
|
||||
// If only a key is provided, it will use the env key matching the key, uppercased.
|
||||
// If more arguments are provided, they will represent the env variable names that
|
||||
// should bind to this key and will be taken in the specified order.
|
||||
// EnvPrefix will be used when set when env name is not provided.
|
||||
func (v *Viper) BindEnv(input ...string) error {
|
||||
if len(input) == 0 {
|
||||
return fmt.Errorf("missing key to bind to")
|
||||
@@ -1131,6 +1173,9 @@ func (v *Viper) BindEnv(input ...string) error {
|
||||
// panic.
|
||||
func MustBindEnv(input ...string) { v.MustBindEnv(input...) }
|
||||
|
||||
// MustBindEnv wraps BindEnv in a panic.
|
||||
// If there is an error binding an environment variable, MustBindEnv will
|
||||
// panic.
|
||||
func (v *Viper) MustBindEnv(input ...string) {
|
||||
if err := v.BindEnv(input...); err != nil {
|
||||
panic(fmt.Sprintf("error while binding environment variable: %v", err))
|
||||
@@ -1388,6 +1433,8 @@ func stringToIntConv(val string) any {
|
||||
// IsSet is case-insensitive for a key.
|
||||
func IsSet(key string) bool { return v.IsSet(key) }
|
||||
|
||||
// IsSet checks to see if the key has been set in any of the data locations.
|
||||
// IsSet is case-insensitive for a key.
|
||||
func (v *Viper) IsSet(key string) bool {
|
||||
lcaseKey := strings.ToLower(key)
|
||||
val := v.find(lcaseKey, false)
|
||||
@@ -1398,6 +1445,8 @@ func (v *Viper) IsSet(key string) bool {
|
||||
// (config, default or flags). If matching env vars are found, they are loaded into Viper.
|
||||
func AutomaticEnv() { v.AutomaticEnv() }
|
||||
|
||||
// AutomaticEnv makes Viper check if environment variables match any of the existing keys
|
||||
// (config, default or flags). If matching env vars are found, they are loaded into Viper.
|
||||
func (v *Viper) AutomaticEnv() {
|
||||
v.automaticEnvApplied = true
|
||||
}
|
||||
@@ -1407,6 +1456,9 @@ func (v *Viper) AutomaticEnv() {
|
||||
// not match it.
|
||||
func SetEnvKeyReplacer(r *strings.Replacer) { v.SetEnvKeyReplacer(r) }
|
||||
|
||||
// SetEnvKeyReplacer sets the strings.Replacer on the viper object
|
||||
// Useful for mapping an environmental variable to a key that does
|
||||
// not match it.
|
||||
func (v *Viper) SetEnvKeyReplacer(r *strings.Replacer) {
|
||||
v.envKeyReplacer = r
|
||||
}
|
||||
@@ -1415,6 +1467,8 @@ func (v *Viper) SetEnvKeyReplacer(r *strings.Replacer) {
|
||||
// This enables one to change a name without breaking the application.
|
||||
func RegisterAlias(alias, key string) { v.RegisterAlias(alias, key) }
|
||||
|
||||
// RegisterAlias creates an alias that provides another accessor for the same key.
|
||||
// This enables one to change a name without breaking the application.
|
||||
func (v *Viper) RegisterAlias(alias, key string) {
|
||||
v.registerAlias(alias, strings.ToLower(key))
|
||||
}
|
||||
@@ -1464,6 +1518,7 @@ func (v *Viper) realKey(key string) string {
|
||||
// InConfig checks to see if the given key (or an alias) is in the config file.
|
||||
func InConfig(key string) bool { return v.InConfig(key) }
|
||||
|
||||
// InConfig checks to see if the given key (or an alias) is in the config file.
|
||||
func (v *Viper) InConfig(key string) bool {
|
||||
lcaseKey := strings.ToLower(key)
|
||||
|
||||
@@ -1479,6 +1534,9 @@ func (v *Viper) InConfig(key string) bool {
|
||||
// Default only used when no value is provided by the user via flag, config or ENV.
|
||||
func SetDefault(key string, value any) { v.SetDefault(key, value) }
|
||||
|
||||
// SetDefault sets the default value for this key.
|
||||
// SetDefault is case-insensitive for a key.
|
||||
// Default only used when no value is provided by the user via flag, config or ENV.
|
||||
func (v *Viper) SetDefault(key string, value any) {
|
||||
// If alias passed in, then set the proper default
|
||||
key = v.realKey(strings.ToLower(key))
|
||||
@@ -1498,6 +1556,10 @@ func (v *Viper) SetDefault(key string, value any) {
|
||||
// flags, config file, ENV, default, or key/value store.
|
||||
func Set(key string, value any) { v.Set(key, value) }
|
||||
|
||||
// Set sets the value for the key in the override register.
|
||||
// Set is case-insensitive for a key.
|
||||
// Will be used instead of values obtained via
|
||||
// flags, config file, ENV, default, or key/value store.
|
||||
func (v *Viper) Set(key string, value any) {
|
||||
// If alias passed in, then set the proper override
|
||||
key = v.realKey(strings.ToLower(key))
|
||||
@@ -1515,6 +1577,8 @@ func (v *Viper) Set(key string, value any) {
|
||||
// and key/value stores, searching in one of the defined paths.
|
||||
func ReadInConfig() error { return v.ReadInConfig() }
|
||||
|
||||
// ReadInConfig will discover and load the configuration file from disk
|
||||
// and key/value stores, searching in one of the defined paths.
|
||||
func (v *Viper) ReadInConfig() error {
|
||||
v.logger.Info("attempting to read in config file")
|
||||
filename, err := v.getConfigFile()
|
||||
@@ -1527,8 +1591,13 @@ func (v *Viper) ReadInConfig() error {
|
||||
}
|
||||
|
||||
v.logger.Debug("reading file", "file", filename)
|
||||
|
||||
file, err := afero.ReadFile(v.fs, filename)
|
||||
if err != nil {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
// The specified config file is missing
|
||||
return FileNotFoundError{err: err, path: filename}
|
||||
} else if err != nil {
|
||||
// We hit some other error from the filesystem that isn't a missing file
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1546,6 +1615,7 @@ func (v *Viper) ReadInConfig() error {
|
||||
// MergeInConfig merges a new configuration with an existing config.
|
||||
func MergeInConfig() error { return v.MergeInConfig() }
|
||||
|
||||
// MergeInConfig merges a new configuration with an existing config.
|
||||
func (v *Viper) MergeInConfig() error {
|
||||
v.logger.Info("attempting to merge in config file")
|
||||
filename, err := v.getConfigFile()
|
||||
@@ -1569,6 +1639,8 @@ func (v *Viper) MergeInConfig() error {
|
||||
// key does not exist in the file.
|
||||
func ReadConfig(in io.Reader) error { return v.ReadConfig(in) }
|
||||
|
||||
// ReadConfig reads a configuration file, setting existing keys to nil if the
|
||||
// key does not exist in the file.
|
||||
func (v *Viper) ReadConfig(in io.Reader) error {
|
||||
config := make(map[string]any)
|
||||
|
||||
@@ -1585,6 +1657,7 @@ func (v *Viper) ReadConfig(in io.Reader) error {
|
||||
// MergeConfig merges a new configuration with an existing config.
|
||||
func MergeConfig(in io.Reader) error { return v.MergeConfig(in) }
|
||||
|
||||
// MergeConfig merges a new configuration with an existing config.
|
||||
func (v *Viper) MergeConfig(in io.Reader) error {
|
||||
config := make(map[string]any)
|
||||
|
||||
@@ -1599,6 +1672,8 @@ func (v *Viper) MergeConfig(in io.Reader) error {
|
||||
// Note that the map given may be modified.
|
||||
func MergeConfigMap(cfg map[string]any) error { return v.MergeConfigMap(cfg) }
|
||||
|
||||
// MergeConfigMap merges the configuration from the map given with an existing config.
|
||||
// Note that the map given may be modified.
|
||||
func (v *Viper) MergeConfigMap(cfg map[string]any) error {
|
||||
if v.config == nil {
|
||||
v.config = make(map[string]any)
|
||||
@@ -1611,6 +1686,7 @@ func (v *Viper) MergeConfigMap(cfg map[string]any) error {
|
||||
// WriteConfig writes the current configuration to a file.
|
||||
func WriteConfig() error { return v.WriteConfig() }
|
||||
|
||||
// WriteConfig writes the current configuration to a file.
|
||||
func (v *Viper) WriteConfig() error {
|
||||
filename, err := v.getConfigFile()
|
||||
if err != nil {
|
||||
@@ -1622,6 +1698,7 @@ func (v *Viper) WriteConfig() error {
|
||||
// SafeWriteConfig writes current configuration to file only if the file does not exist.
|
||||
func SafeWriteConfig() error { return v.SafeWriteConfig() }
|
||||
|
||||
// SafeWriteConfig writes current configuration to file only if the file does not exist.
|
||||
func (v *Viper) SafeWriteConfig() error {
|
||||
if len(v.configPaths) < 1 {
|
||||
return errors.New("missing configuration for 'configPath'")
|
||||
@@ -1632,6 +1709,7 @@ func (v *Viper) SafeWriteConfig() error {
|
||||
// WriteConfigAs writes current configuration to a given filename.
|
||||
func WriteConfigAs(filename string) error { return v.WriteConfigAs(filename) }
|
||||
|
||||
// WriteConfigAs writes current configuration to a given filename.
|
||||
func (v *Viper) WriteConfigAs(filename string) error {
|
||||
return v.writeConfig(filename, true)
|
||||
}
|
||||
@@ -1639,6 +1717,7 @@ func (v *Viper) WriteConfigAs(filename string) error {
|
||||
// WriteConfigTo writes current configuration to an [io.Writer].
|
||||
func WriteConfigTo(w io.Writer) error { return v.WriteConfigTo(w) }
|
||||
|
||||
// WriteConfigTo writes current configuration to an [io.Writer].
|
||||
func (v *Viper) WriteConfigTo(w io.Writer) error {
|
||||
format := strings.ToLower(v.getConfigType())
|
||||
|
||||
@@ -1652,6 +1731,7 @@ func (v *Viper) WriteConfigTo(w io.Writer) error {
|
||||
// SafeWriteConfigAs writes current configuration to a given filename if it does not exist.
|
||||
func SafeWriteConfigAs(filename string) error { return v.SafeWriteConfigAs(filename) }
|
||||
|
||||
// SafeWriteConfigAs writes current configuration to a given filename if it does not exist.
|
||||
func (v *Viper) SafeWriteConfigAs(filename string) error {
|
||||
alreadyExists, err := afero.Exists(v.fs, filename)
|
||||
if alreadyExists && err == nil {
|
||||
@@ -1885,6 +1965,8 @@ func mergeMaps(src, tgt map[string]any, itgt map[any]any) {
|
||||
// Nested keys are returned with a v.keyDelim separator.
|
||||
func AllKeys() []string { return v.AllKeys() }
|
||||
|
||||
// AllKeys returns all keys holding a value, regardless of where they are set.
|
||||
// Nested keys are returned with a v.keyDelim separator.
|
||||
func (v *Viper) AllKeys() []string {
|
||||
m := map[string]bool{}
|
||||
// add all paths, by order of descending priority to ensure correct shadowing
|
||||
@@ -1967,6 +2049,7 @@ outer:
|
||||
// AllSettings merges all settings and returns them as a map[string]any.
|
||||
func AllSettings() map[string]any { return v.AllSettings() }
|
||||
|
||||
// AllSettings merges all settings and returns them as a map[string]any.
|
||||
func (v *Viper) AllSettings() map[string]any {
|
||||
return v.getSettings(v.AllKeys())
|
||||
}
|
||||
@@ -1993,6 +2076,7 @@ func (v *Viper) getSettings(keys []string) map[string]any {
|
||||
// SetFs sets the filesystem to use to read configuration.
|
||||
func SetFs(fs afero.Fs) { v.SetFs(fs) }
|
||||
|
||||
// SetFs sets the filesystem to use to read configuration.
|
||||
func (v *Viper) SetFs(fs afero.Fs) {
|
||||
v.fs = fs
|
||||
}
|
||||
@@ -2001,6 +2085,8 @@ func (v *Viper) SetFs(fs afero.Fs) {
|
||||
// Does not include extension.
|
||||
func SetConfigName(in string) { v.SetConfigName(in) }
|
||||
|
||||
// SetConfigName sets the name for the config file.
|
||||
// Does not include extension.
|
||||
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"))
|
||||
@@ -2016,6 +2102,8 @@ func (v *Viper) SetConfigName(in string) {
|
||||
// remote source, e.g. "json".
|
||||
func SetConfigType(in string) { v.SetConfigType(in) }
|
||||
|
||||
// SetConfigType sets the type of the configuration returned by the
|
||||
// remote source, e.g. "json".
|
||||
func (v *Viper) SetConfigType(in string) {
|
||||
if in != "" {
|
||||
v.configType = in
|
||||
@@ -2025,6 +2113,7 @@ func (v *Viper) SetConfigType(in string) {
|
||||
// SetConfigPermissions sets the permissions for the config file.
|
||||
func SetConfigPermissions(perm os.FileMode) { v.SetConfigPermissions(perm) }
|
||||
|
||||
// SetConfigPermissions sets the permissions for the config file.
|
||||
func (v *Viper) SetConfigPermissions(perm os.FileMode) {
|
||||
v.configPermissions = perm.Perm()
|
||||
}
|
||||
@@ -2061,11 +2150,15 @@ func (v *Viper) getConfigFile() (string, error) {
|
||||
|
||||
// Debug prints all configuration registries for debugging
|
||||
// purposes.
|
||||
func Debug() { v.Debug() }
|
||||
func Debug() { v.Debug() }
|
||||
|
||||
// DebugTo writes all configuration registries to the given [io.Writer].
|
||||
func DebugTo(w io.Writer) { v.DebugTo(w) }
|
||||
|
||||
// Debug prints all configuration registries for debugging purposes.
|
||||
func (v *Viper) Debug() { v.DebugTo(os.Stdout) }
|
||||
|
||||
// DebugTo writes all configuration registries to the given [io.Writer].
|
||||
func (v *Viper) DebugTo(w io.Writer) {
|
||||
fmt.Fprintf(w, "Aliases:\n%#v\n", v.aliases)
|
||||
fmt.Fprintf(w, "Override:\n%#v\n", v.override)
|
||||
|
||||
+37
-3
@@ -359,7 +359,7 @@ func TestReadInConfig(t *testing.T) {
|
||||
t.Run("config file set", func(t *testing.T) {
|
||||
fs := afero.NewMemMapFs()
|
||||
|
||||
err := fs.Mkdir("/etc/viper", 0o777)
|
||||
err := fs.Mkdir(testutil.AbsFilePath(t, "/etc/viper"), 0o777)
|
||||
require.NoError(t, err)
|
||||
|
||||
file, err := fs.Create(testutil.AbsFilePath(t, "/etc/viper/config.yaml"))
|
||||
@@ -1573,6 +1573,28 @@ func TestReadConfigWithSetConfigFile(t *testing.T) {
|
||||
assert.Equal(t, 45000, v.GetInt("hello.pop"))
|
||||
}
|
||||
|
||||
func TestWrongFileNotFound(t *testing.T) {
|
||||
_, config := initDirs(t)
|
||||
|
||||
v := New()
|
||||
v.SetConfigName(config)
|
||||
v.SetDefault(`key`, `default`)
|
||||
|
||||
v.SetConfigFile(`whatareyoutalkingabout.yaml`)
|
||||
|
||||
err := v.ReadInConfig()
|
||||
|
||||
var fileLookupError FileLookupError
|
||||
|
||||
// It matches all error types and the shared error interface.
|
||||
assert.ErrorAs(t, err, &FileNotFoundError{})
|
||||
assert.ErrorAs(t, err, &fileLookupError)
|
||||
|
||||
// Even though config did not load and the error might have
|
||||
// been ignored by the client, the default still loads
|
||||
assert.Equal(t, `default`, v.GetString(`key`))
|
||||
}
|
||||
|
||||
func TestIsSet(t *testing.T) {
|
||||
v := New()
|
||||
v.SetConfigType("yaml")
|
||||
@@ -1652,7 +1674,13 @@ func TestWrongDirsSearchNotFound(t *testing.T) {
|
||||
v.AddConfigPath(`thispathaintthere`)
|
||||
|
||||
err := v.ReadInConfig()
|
||||
assert.IsType(t, ConfigFileNotFoundError{"", ""}, err)
|
||||
|
||||
var fileLookupError FileLookupError
|
||||
|
||||
// It matches all error types and the shared error interface.
|
||||
assert.ErrorAs(t, err, &ConfigFileNotFoundError{})
|
||||
assert.ErrorAs(t, err, &FileNotFoundFromSearchError{})
|
||||
assert.ErrorAs(t, err, &fileLookupError)
|
||||
|
||||
// Even though config did not load and the error might have
|
||||
// been ignored by the client, the default still loads
|
||||
@@ -1670,7 +1698,13 @@ func TestWrongDirsSearchNotFoundForMerge(t *testing.T) {
|
||||
v.AddConfigPath(`thispathaintthere`)
|
||||
|
||||
err := v.MergeInConfig()
|
||||
assert.Equal(t, reflect.TypeOf(ConfigFileNotFoundError{"", ""}), reflect.TypeOf(err))
|
||||
|
||||
var fileLookupError FileLookupError
|
||||
|
||||
// It matches both types of errors.
|
||||
assert.ErrorAs(t, err, &ConfigFileNotFoundError{})
|
||||
assert.ErrorAs(t, err, &FileNotFoundFromSearchError{})
|
||||
assert.ErrorAs(t, err, &fileLookupError)
|
||||
|
||||
// Even though config did not load and the error might have
|
||||
// been ignored by the client, the default still loads
|
||||
|
||||
Reference in New Issue
Block a user