feat(encoding): Integrate the new encoding package into Viper

Signed-off-by: Mark Sagi-Kazar <mark.sagikazar@gmail.com>
This commit is contained in:
Mark Sagi-Kazar 2020-09-23 17:46:17 +02:00 committed by Márk Sági-Kazár
parent 699d749768
commit a02f9864fa

114
viper.go
View file

@ -22,7 +22,6 @@ package viper
import ( import (
"bytes" "bytes"
"encoding/csv" "encoding/csv"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -36,18 +35,20 @@ import (
"time" "time"
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
"github.com/hashicorp/hcl"
"github.com/hashicorp/hcl/hcl/printer"
"github.com/magiconair/properties" "github.com/magiconair/properties"
"github.com/mitchellh/mapstructure" "github.com/mitchellh/mapstructure"
"github.com/pelletier/go-toml"
"github.com/spf13/afero" "github.com/spf13/afero"
"github.com/spf13/cast" "github.com/spf13/cast"
jww "github.com/spf13/jwalterweatherman" jww "github.com/spf13/jwalterweatherman"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/subosito/gotenv" "github.com/subosito/gotenv"
"gopkg.in/ini.v1" "gopkg.in/ini.v1"
"gopkg.in/yaml.v2"
"github.com/spf13/viper/internal/encoding"
"github.com/spf13/viper/internal/encoding/hcl"
"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. // ConfigMarshalError happens when failing to marshal the configuration.
@ -67,8 +68,44 @@ type RemoteResponse struct {
Error error Error error
} }
var (
encoderRegistry = encoding.NewEncoderRegistry()
decoderRegistry = encoding.NewDecoderRegistry()
)
func init() { func init() {
v = New() v = New()
{
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)
}
} }
type remoteConfigFactory interface { type remoteConfigFactory interface {
@ -1584,35 +1621,12 @@ func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error {
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
buf.ReadFrom(in) buf.ReadFrom(in)
switch strings.ToLower(v.getConfigType()) { switch format := strings.ToLower(v.getConfigType()); format {
case "yaml", "yml": case "yaml", "yml", "json", "toml", "hcl":
if err := yaml.Unmarshal(buf.Bytes(), &c); err != nil { err := decoderRegistry.Decode(format, buf.Bytes(), &c)
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 { if err != nil {
return ConfigParseError{err} 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": case "dotenv", "env":
env, err := gotenv.StrictParse(buf) env, err := gotenv.StrictParse(buf)
@ -1665,26 +1679,13 @@ func (v *Viper) unmarshalReader(in io.Reader, c map[string]interface{}) error {
func (v *Viper) marshalWriter(f afero.File, configType string) error { func (v *Viper) marshalWriter(f afero.File, configType string) error {
c := v.AllSettings() c := v.AllSettings()
switch configType { switch configType {
case "json": case "yaml", "yml", "json", "toml", "hcl":
b, err := json.MarshalIndent(c, "", " ") b, err := encoderRegistry.Encode(configType, c)
if err != nil {
return ConfigMarshalError{err}
}
_, err = f.WriteString(string(b))
if err != nil { if err != nil {
return ConfigMarshalError{err} return ConfigMarshalError{err}
} }
case "hcl": _, err = f.WriteString(string(b))
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 { if err != nil {
return ConfigMarshalError{err} return ConfigMarshalError{err}
} }
@ -1717,25 +1718,6 @@ func (v *Viper) marshalWriter(f afero.File, configType string) error {
return ConfigMarshalError{err} return ConfigMarshalError{err}
} }
case "toml":
t, err := toml.TreeFromMap(c)
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": case "ini":
keys := v.AllKeys() keys := v.AllKeys()
cfg := ini.Empty() cfg := ini.Empty()