1
0
mirror of https://github.com/go-kratos/kratos.git synced 2025-02-11 13:38:46 +02:00
kratos/config/options.go
Kagaya e19730e4b6
feat(config): support Resolver for config variable placeholders (#1135)
* test: add yaml test case for reader

test: init test case for fillTemplate

* add env placeholder resolver

fix ci test fail

* fix ci test fail

* feat(config): add config resolver

* test(config): add test cases

* move defaultDecoder & defaultResolver to options.go
2021-07-11 00:03:43 +08:00

106 lines
2.3 KiB
Go

package config
import (
"fmt"
"os"
"strings"
"github.com/go-kratos/kratos/v2/encoding"
"github.com/go-kratos/kratos/v2/log"
)
// Decoder is config decoder.
type Decoder func(*KeyValue, map[string]interface{}) error
// Resolver resolve placeholder in config.
type Resolver func(map[string]interface{}) error
// Option is config option.
type Option func(*options)
type options struct {
sources []Source
decoder Decoder
resolver Resolver
logger log.Logger
}
// WithSource with config source.
func WithSource(s ...Source) Option {
return func(o *options) {
o.sources = s
}
}
// WithDecoder with config decoder.
func WithDecoder(d Decoder) Option {
return func(o *options) {
o.decoder = d
}
}
// WithResolver with config resolver.
func WithResolver(r Resolver) Option {
return func(o *options) {
o.resolver = r
}
}
// WithLogger with config logger.
func WithLogger(l log.Logger) Option {
return func(o *options) {
o.logger = l
}
}
// defaultDecoder decode config from source KeyValue
// to target map[string]interface{} using src.Format codec.
func defaultDecoder(src *KeyValue, target map[string]interface{}) error {
if src.Format == "" {
target[src.Key] = src.Value
return nil
}
if codec := encoding.GetCodec(src.Format); codec != nil {
return codec.Unmarshal(src.Value, &target)
}
return fmt.Errorf("unsupported key: %s format: %s", src.Key, src.Format)
}
// defaultResolver resolve placeholder in map value,
// placeholder format in ${key:default} or $key.
func defaultResolver(input map[string]interface{}) error {
mapper := func(name string) string {
args := strings.Split(strings.TrimSpace(name), ":")
if v, has := readValue(input, args[0]); has {
s, _ := v.String()
return s
} else if len(args) > 1 { // default value
return args[1]
}
return ""
}
var resolve func(map[string]interface{}) error
resolve = func(sub map[string]interface{}) error {
for k, v := range sub {
switch vt := v.(type) {
case string:
sub[k] = os.Expand(vt, mapper)
case map[string]interface{}:
if err := resolve(vt); err != nil {
return err
}
case []interface{}:
for i, iface := range vt {
if s, ok := iface.(string); ok {
vt[i] = os.Expand(s, mapper)
}
}
sub[k] = vt
}
}
return nil
}
return resolve(input)
}