--- a/vendor/github.com/spf13/viper/viper.go Tue Aug 23 22:33:28 2022 +0200
+++ b/vendor/github.com/spf13/viper/viper.go Tue Aug 23 22:39:43 2022 +0200
@@ -22,7 +22,6 @@
import (
"bytes"
"encoding/csv"
- "encoding/json"
"errors"
"fmt"
"io"
@@ -36,18 +35,19 @@
"time"
"github.com/fsnotify/fsnotify"
- "github.com/hashicorp/hcl"
- "github.com/hashicorp/hcl/hcl/printer"
- "github.com/magiconair/properties"
"github.com/mitchellh/mapstructure"
- "github.com/pelletier/go-toml"
"github.com/spf13/afero"
"github.com/spf13/cast"
- jww "github.com/spf13/jwalterweatherman"
"github.com/spf13/pflag"
- "github.com/subosito/gotenv"
- "gopkg.in/ini.v1"
- "gopkg.in/yaml.v2"
+
+ "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"
)
// ConfigMarshalError happens when failing to marshal the configuration.
@@ -215,11 +215,13 @@
aliases map[string]string
typeByDefValue bool
- // 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.
- properties *properties.Properties
+ onConfigChange func(fsnotify.Event)
+
+ logger Logger
- onConfigChange func(fsnotify.Event)
+ // TODO: should probably be protected with a mutex
+ encoderRegistry *encoding.EncoderRegistry
+ decoderRegistry *encoding.DecoderRegistry
}
// New returns an initialized Viper instance.
@@ -227,7 +229,7 @@
v := new(Viper)
v.keyDelim = "."
v.configName = "config"
- v.configPermissions = os.FileMode(0644)
+ v.configPermissions = os.FileMode(0o644)
v.fs = afero.NewOsFs()
v.config = make(map[string]interface{})
v.override = make(map[string]interface{})
@@ -237,6 +239,9 @@
v.env = make(map[string][]string)
v.aliases = make(map[string]string)
v.typeByDefValue = false
+ v.logger = jwwLogger{}
+
+ v.resetEncoding()
return v
}
@@ -284,6 +289,8 @@
opt.apply(v)
}
+ v.resetEncoding()
+
return v
}
@@ -292,10 +299,88 @@
// can use it in their testing as well.
func Reset() {
v = New()
- SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "dotenv", "env", "ini"}
+ SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "tfvars", "dotenv", "env", "ini"}
SupportedRemoteProviders = []string{"etcd", "consul", "firestore"}
}
+// 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
@@ -331,7 +416,7 @@
}
// SupportedExts are universally supported extensions.
-var SupportedExts = []string{"json", "toml", "yaml", "yml", "properties", "props", "prop", "hcl", "dotenv", "env", "ini"}
+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", "consul", "firestore"}
@@ -391,7 +476,7 @@
v.onConfigChange(event)
}
} else if filepath.Clean(event.Name) == configFile &&
- event.Op&fsnotify.Remove&fsnotify.Remove != 0 {
+ event.Op&fsnotify.Remove != 0 {
eventsWG.Done()
return
}
@@ -477,8 +562,9 @@
func (v *Viper) AddConfigPath(in string) {
if in != "" {
- absin := absPathify(in)
- jww.INFO.Println("adding", absin, "to paths to search")
+ absin := absPathify(v.logger, in)
+
+ v.logger.Info("adding path to search paths", "path", absin)
if !stringInSlice(absin, v.configPaths) {
v.configPaths = append(v.configPaths, absin)
}
@@ -502,7 +588,8 @@
return UnsupportedRemoteProviderError(provider)
}
if provider != "" && endpoint != "" {
- jww.INFO.Printf("adding %s:%s to remote provider list", provider, endpoint)
+ v.logger.Info("adding remote provider", "provider", provider, "endpoint", endpoint)
+
rp := &defaultRemoteProvider{
endpoint: endpoint,
provider: provider,
@@ -534,7 +621,8 @@
return UnsupportedRemoteProviderError(provider)
}
if provider != "" && endpoint != "" {
- jww.INFO.Printf("adding %s:%s to remote provider list", provider, endpoint)
+ v.logger.Info("adding remote provider", "provider", provider, "endpoint", endpoint)
+
rp := &defaultRemoteProvider{
endpoint: endpoint,
provider: provider,
@@ -1109,6 +1197,17 @@
return nil
}
+// MustBindEnv wraps BindEnv in a panic.
+// If there is an error binding an environment variable, MustBindEnv will
+// panic.
+func MustBindEnv(input ...string) { v.MustBindEnv(input...) }
+
+func (v *Viper) MustBindEnv(input ...string) {
+ if err := v.BindEnv(input...); err != nil {
+ panic(fmt.Sprintf("error while binding environment variable: %v", err))
+ }
+}
+
// Given a key, find the value.
//
// Viper will check to see if an alias exists first.
@@ -1350,14 +1449,15 @@
v.aliases[alias] = key
}
} else {
- jww.WARN.Println("Creating circular reference alias", alias, key, v.realKey(key))
+ v.logger.Warn("creating circular reference alias", "alias", alias, "key", key, "real_key", v.realKey(key))
}
}
func (v *Viper) realKey(key string) string {
newkey, exists := v.aliases[key]
if exists {
- jww.DEBUG.Println("Alias", key, "to", newkey)
+ v.logger.Debug("key is an alias", "alias", key, "to", newkey)
+
return v.realKey(newkey)
}
return key
@@ -1367,11 +1467,13 @@
func InConfig(key string) bool { return v.InConfig(key) }
func (v *Viper) InConfig(key string) bool {
- // if the requested key is an alias, then return the proper key
- key = v.realKey(key)
+ lcaseKey := strings.ToLower(key)
- _, exists := v.config[key]
- return exists
+ // if the requested key is an alias, then return the proper key
+ lcaseKey = v.realKey(lcaseKey)
+ path := strings.Split(lcaseKey, v.keyDelim)
+
+ return v.searchIndexableWithPathPrefixes(v.config, path) != nil
}
// SetDefault sets the default value for this key.
@@ -1416,7 +1518,7 @@
func ReadInConfig() error { return v.ReadInConfig() }
func (v *Viper) ReadInConfig() error {
- jww.INFO.Println("Attempting to read in config file")
+ v.logger.Info("attempting to read in config file")
filename, err := v.getConfigFile()
if err != nil {
return err
@@ -1426,7 +1528,7 @@
return UnsupportedConfigError(v.getConfigType())
}
- jww.DEBUG.Println("Reading file: ", filename)
+ v.logger.Debug("reading file", "file", filename)
file, err := afero.ReadFile(v.fs, filename)
if err != nil {
return err
@@ -1447,7 +1549,7 @@
func MergeInConfig() error { return v.MergeInConfig() }
func (v *Viper) MergeInConfig() error {
- jww.INFO.Println("Attempting to merge in config file")
+ v.logger.Info("attempting to merge in config file")
filename, err := v.getConfigFile()
if err != nil {
return err
@@ -1538,11 +1640,12 @@
}
func (v *Viper) writeConfig(filename string, force bool) error {
- jww.INFO.Println("Attempting to write configuration to file.")
+ v.logger.Info("attempting to write configuration to file")
+
var configType string
ext := filepath.Ext(filename)
- if ext != "" {
+ if ext != "" && ext != filepath.Base(filename) {
configType = ext[1:]
} else {
configType = v.configType
@@ -1584,77 +1687,12 @@
buf := new(bytes.Buffer)
buf.ReadFrom(in)
- switch strings.ToLower(v.getConfigType()) {
- case "yaml", "yml":
- if err := yaml.Unmarshal(buf.Bytes(), &c); err != nil {
- return ConfigParseError{err}
- }
-
- case "json":
- if err := json.Unmarshal(buf.Bytes(), &c); err != nil {
- return ConfigParseError{err}
- }
-
- case "hcl":
- obj, err := hcl.Parse(buf.String())
- if err != nil {
- return ConfigParseError{err}
- }
- if err = hcl.DecodeObject(&c, obj); err != nil {
- return ConfigParseError{err}
- }
-
- case "toml":
- tree, err := toml.LoadReader(buf)
- if err != nil {
- return ConfigParseError{err}
- }
- tmap := tree.ToMap()
- for k, v := range tmap {
- c[k] = v
- }
-
- case "dotenv", "env":
- env, err := gotenv.StrictParse(buf)
+ 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}
}
- for k, v := range env {
- c[k] = v
- }
-
- case "properties", "props", "prop":
- v.properties = properties.NewProperties()
- var err error
- if v.properties, err = properties.Load(buf.Bytes(), properties.UTF8); err != nil {
- return ConfigParseError{err}
- }
- for _, key := range v.properties.Keys() {
- value, _ := v.properties.Get(key)
- // recursively build nested maps
- path := strings.Split(key, ".")
- lastKey := strings.ToLower(path[len(path)-1])
- deepestMap := deepSearch(c, path[0:len(path)-1])
- // set innermost value
- deepestMap[lastKey] = value
- }
-
- case "ini":
- cfg := ini.Empty(v.iniLoadOptions)
- err := cfg.Append(buf.Bytes())
- if err != nil {
- return ConfigParseError{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()
- c[section.Name()+"."+key.Name()] = value
- }
- }
}
insensitiviseMap(c)
@@ -1665,92 +1703,16 @@
func (v *Viper) marshalWriter(f afero.File, configType string) error {
c := v.AllSettings()
switch configType {
- case "json":
- b, err := json.MarshalIndent(c, "", " ")
- if err != nil {
- return ConfigMarshalError{err}
- }
- _, err = f.WriteString(string(b))
- if err != nil {
- return ConfigMarshalError{err}
- }
-
- case "hcl":
- b, err := json.Marshal(c)
- if err != nil {
- return ConfigMarshalError{err}
- }
- ast, err := hcl.Parse(string(b))
- if err != nil {
- return ConfigMarshalError{err}
- }
- err = printer.Fprint(f, ast.Node)
- if err != nil {
- return ConfigMarshalError{err}
- }
-
- case "prop", "props", "properties":
- if v.properties == nil {
- v.properties = properties.NewProperties()
- }
- p := v.properties
- for _, key := range v.AllKeys() {
- _, _, err := p.Set(key, v.GetString(key))
- if err != nil {
- return ConfigMarshalError{err}
- }
- }
- _, err := p.WriteComment(f, "#", properties.UTF8)
+ 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}
}
- case "dotenv", "env":
- lines := []string{}
- for _, key := range v.AllKeys() {
- envName := strings.ToUpper(strings.Replace(key, ".", "_", -1))
- val := v.Get(key)
- lines = append(lines, fmt.Sprintf("%v=%v", envName, val))
- }
- s := strings.Join(lines, "\n")
- if _, err := f.WriteString(s); err != nil {
- return ConfigMarshalError{err}
- }
-
- case "toml":
- t, err := toml.TreeFromMap(c)
+ _, err = f.WriteString(string(b))
if err != nil {
return ConfigMarshalError{err}
}
- s := t.String()
- if _, err := f.WriteString(s); err != nil {
- return ConfigMarshalError{err}
- }
-
- case "yaml", "yml":
- b, err := yaml.Marshal(c)
- if err != nil {
- return ConfigMarshalError{err}
- }
- if _, err = f.WriteString(string(b)); err != nil {
- return ConfigMarshalError{err}
- }
-
- case "ini":
- keys := v.AllKeys()
- cfg := ini.Empty()
- ini.PrettyFormat = false
- for i := 0; i < len(keys); i++ {
- key := keys[i]
- lastSep := strings.LastIndex(key, ".")
- sectionName := key[:(lastSep)]
- keyName := key[(lastSep + 1):]
- if sectionName == "default" {
- sectionName = ""
- }
- cfg.Section(sectionName).Key(keyName).SetValue(v.GetString(key))
- }
- cfg.WriteTo(f)
}
return nil
}
@@ -1767,7 +1729,8 @@
}
func castToMapStringInterface(
- src map[interface{}]interface{}) map[string]interface{} {
+ src map[interface{}]interface{},
+) map[string]interface{} {
tgt := map[string]interface{}{}
for k, v := range src {
tgt[fmt.Sprintf("%v", k)] = v
@@ -1805,11 +1768,12 @@
// deep. Both map types are supported as there is a go-yaml fork that uses
// `map[string]interface{}` instead.
func mergeMaps(
- src, tgt map[string]interface{}, itgt map[interface{}]interface{}) {
+ src, tgt map[string]interface{}, itgt map[interface{}]interface{},
+) {
for sk, sv := range src {
tk := keyExists(sk, tgt)
if tk == "" {
- jww.TRACE.Printf("tk=\"\", tgt[%s]=%v", sk, sv)
+ v.logger.Trace("", "tk", "\"\"", fmt.Sprintf("tgt[%s]", sk), sv)
tgt[sk] = sv
if itgt != nil {
itgt[sk] = sv
@@ -1819,7 +1783,7 @@
tv, ok := tgt[tk]
if !ok {
- jww.TRACE.Printf("tgt[%s] != ok, tgt[%s]=%v", tk, sk, sv)
+ v.logger.Trace("", fmt.Sprintf("ok[%s]", tk), false, fmt.Sprintf("tgt[%s]", sk), sv)
tgt[sk] = sv
if itgt != nil {
itgt[sk] = sv
@@ -1829,28 +1793,52 @@
svType := reflect.TypeOf(sv)
tvType := reflect.TypeOf(tv)
- if tvType != nil && svType != tvType { // Allow for the target to be nil
- jww.ERROR.Printf(
- "svType != tvType; key=%s, st=%v, tt=%v, sv=%v, tv=%v",
- sk, svType, tvType, sv, tv)
- continue
- }
- jww.TRACE.Printf("processing key=%s, st=%v, tt=%v, sv=%v, tv=%v",
- sk, svType, tvType, sv, tv)
+ v.logger.Trace(
+ "processing",
+ "key", sk,
+ "st", svType,
+ "tt", tvType,
+ "sv", sv,
+ "tv", tv,
+ )
switch ttv := tv.(type) {
case map[interface{}]interface{}:
- jww.TRACE.Printf("merging maps (must convert)")
- tsv := sv.(map[interface{}]interface{})
+ v.logger.Trace("merging maps (must convert)")
+ tsv, ok := sv.(map[interface{}]interface{})
+ if !ok {
+ v.logger.Error(
+ "Could not cast sv to map[interface{}]interface{}",
+ "key", sk,
+ "st", svType,
+ "tt", tvType,
+ "sv", sv,
+ "tv", tv,
+ )
+ continue
+ }
+
ssv := castToMapStringInterface(tsv)
stv := castToMapStringInterface(ttv)
mergeMaps(ssv, stv, ttv)
case map[string]interface{}:
- jww.TRACE.Printf("merging maps")
- mergeMaps(sv.(map[string]interface{}), ttv, nil)
+ v.logger.Trace("merging maps")
+ tsv, ok := sv.(map[string]interface{})
+ if !ok {
+ v.logger.Error(
+ "Could not cast sv to map[string]interface{}",
+ "key", sk,
+ "st", svType,
+ "tt", tvType,
+ "sv", sv,
+ "tv", tv,
+ )
+ continue
+ }
+ mergeMaps(tsv, ttv, nil)
default:
- jww.TRACE.Printf("setting value")
+ v.logger.Trace("setting value")
tgt[tk] = sv
if itgt != nil {
itgt[tk] = sv
@@ -1885,7 +1873,7 @@
for _, rp := range v.remoteProviders {
val, err := v.getRemoteConfig(rp)
if err != nil {
- jww.ERROR.Printf("get remote config: %s", err)
+ v.logger.Error(fmt.Errorf("get remote config: %w", err).Error())
continue
}
@@ -2121,39 +2109,6 @@
return v.configFile, nil
}
-func (v *Viper) searchInPath(in string) (filename string) {
- jww.DEBUG.Println("Searching for config in ", in)
- for _, ext := range SupportedExts {
- jww.DEBUG.Println("Checking for", filepath.Join(in, v.configName+"."+ext))
- if b, _ := exists(v.fs, filepath.Join(in, v.configName+"."+ext)); b {
- jww.DEBUG.Println("Found: ", filepath.Join(in, v.configName+"."+ext))
- return filepath.Join(in, v.configName+"."+ext)
- }
- }
-
- if v.configType != "" {
- if b, _ := exists(v.fs, filepath.Join(in, v.configName)); b {
- return filepath.Join(in, v.configName)
- }
- }
-
- return ""
-}
-
-// Search all configPaths for any config file.
-// Returns the first path that exists (and is a config file).
-func (v *Viper) findConfigFile() (string, error) {
- jww.INFO.Println("Searching for config in ", v.configPaths)
-
- for _, cp := range v.configPaths {
- file := v.searchInPath(cp)
- if file != "" {
- return file, nil
- }
- }
- return "", ConfigFileNotFoundError{v.configName, fmt.Sprintf("%s", v.configPaths)}
-}
-
// Debug prints all configuration registries for debugging
// purposes.
func Debug() { v.Debug() }