in loader/config.go [65:139]
func NewConfigFrom(from interface{}, opts ...interface{}) (*Config, error) {
if len(opts) == 0 {
opts = DefaultOptions
}
var ucfgOpts []ucfg.Option
var localOpts []Option
for _, o := range opts {
switch ot := o.(type) {
case ucfg.Option:
ucfgOpts = append(ucfgOpts, ot)
case Option:
localOpts = append(localOpts, ot)
default:
return nil, fmt.Errorf("unknown option type %T", o)
}
}
local := &options{}
for _, o := range localOpts {
o(local)
}
var data map[string]interface{}
var err error
if bytes, ok := from.([]byte); ok {
err = yaml.Unmarshal(bytes, &data)
if err != nil {
return nil, err
}
} else if str, ok := from.(string); ok {
err = yaml.Unmarshal([]byte(str), &data)
if err != nil {
return nil, err
}
} else if in, ok := from.(io.Reader); ok {
if closer, ok := from.(io.Closer); ok {
defer closer.Close()
}
fData, err := io.ReadAll(in)
if err != nil {
return nil, err
}
err = yaml.Unmarshal(fData, &data)
if err != nil {
return nil, err
}
} else if contents, ok := from.(map[string]interface{}); ok {
data = contents
} else {
c, err := ucfg.NewFrom(from, ucfgOpts...)
return newConfigFrom(c), err
}
skippedKeys := map[string]interface{}{}
for _, skip := range local.skipKeys {
val, ok := data[skip]
if ok {
skippedKeys[skip] = val
delete(data, skip)
}
}
cfg, err := ucfg.NewFrom(data, ucfgOpts...)
if err != nil {
return nil, err
}
if len(skippedKeys) > 0 {
err = cfg.Merge(skippedKeys, ucfg.ResolveNOOP)
// we modified incoming object
// cleanup so skipped keys are not missing
for k, v := range skippedKeys {
data[k] = v
}
}
return newConfigFrom(cfg), err
}