mirror of
https://github.com/spf13/viper
synced 2025-05-07 20:57:18 +00:00
115 lines
3 KiB
Go
115 lines
3 KiB
Go
package encoding
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"github.com/spf13/viper/internal/encoding/codec"
|
|
"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"
|
|
)
|
|
|
|
const (
|
|
// ErrCodecNotFound is returned when there is no codec registered for a format.
|
|
ErrCodecNotFound = encodingError("codec not found for this format")
|
|
|
|
// ErrCodecFormatAlreadyRegistered is returned when a codec is already registered for a format.
|
|
ErrCodecFormatAlreadyRegistered = encodingError("codec already registered for this format")
|
|
)
|
|
|
|
// supportedCodecFormats stores all supported codec, the empty pointers are used to construct a corresponding
|
|
// codec object without reflection.
|
|
var supportedCodecFormats = map[string]func(args ...interface{}) codec.Codec{
|
|
"yaml": yaml.New,
|
|
"yml": yaml.New,
|
|
"json": json.New,
|
|
"toml": toml.New,
|
|
"hcl": hcl.New,
|
|
"tfvars": hcl.New,
|
|
"ini": ini.New,
|
|
"properties": javaproperties.New,
|
|
"props": javaproperties.New,
|
|
"prop": javaproperties.New,
|
|
"dotenv": dotenv.New,
|
|
"env": dotenv.New,
|
|
}
|
|
|
|
type CodecRegistry struct {
|
|
codecs map[string]codec.Codec
|
|
mu sync.RWMutex
|
|
|
|
keyDelim string
|
|
iniLoadOptions ini.LoadOptions
|
|
}
|
|
|
|
// NewCodecRegistry returns a new, initialized CodecRegistry.
|
|
func NewCodecRegistry(keyDelim string, iniLoadOptions ini.LoadOptions) *CodecRegistry {
|
|
return &CodecRegistry{
|
|
codecs: make(map[string]codec.Codec),
|
|
keyDelim: keyDelim,
|
|
iniLoadOptions: iniLoadOptions,
|
|
}
|
|
}
|
|
|
|
func (e *CodecRegistry) getCodecLazily(format string) (codec.Codec, error) {
|
|
e.mu.RLock()
|
|
c, ok := e.codecs[format]
|
|
e.mu.RUnlock()
|
|
if ok {
|
|
return c, nil
|
|
}
|
|
|
|
newCodecFn, ok := supportedCodecFormats[format]
|
|
if !ok {
|
|
return nil, ErrCodecNotFound
|
|
}
|
|
|
|
switch format {
|
|
case "ini":
|
|
c = newCodecFn(e.keyDelim, e.iniLoadOptions)
|
|
case "properties", "props", "prop":
|
|
c = newCodecFn(e.keyDelim)
|
|
default:
|
|
c = newCodecFn()
|
|
}
|
|
|
|
e.mu.Lock()
|
|
defer e.mu.Unlock()
|
|
e.codecs[format] = c
|
|
return c, nil
|
|
}
|
|
|
|
func (e *CodecRegistry) Decode(format string, b []byte, v map[string]interface{}) error {
|
|
decoder, err := e.getCodecLazily(format)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return decoder.Decode(b, v)
|
|
}
|
|
|
|
func (e *CodecRegistry) Encode(format string, v map[string]interface{}) ([]byte, error) {
|
|
decoder, err := e.getCodecLazily(format)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return decoder.Encode(v)
|
|
}
|
|
|
|
// RegisterCodec registers a Codec for a format.
|
|
// Registering a Codec for an already existing format is not supported.
|
|
func (e *CodecRegistry) RegisterCodec(format string, codec codec.Codec) error {
|
|
e.mu.Lock()
|
|
defer e.mu.Unlock()
|
|
|
|
if _, ok := e.codecs[format]; ok {
|
|
return ErrCodecFormatAlreadyRegistered
|
|
}
|
|
|
|
e.codecs[format] = codec
|
|
|
|
return nil
|
|
}
|