mediocre-go-lib/mcfg/env.go

80 lines
2.0 KiB
Go

package mcfg
import (
"os"
"strings"
"github.com/mediocregopher/mediocre-go-lib/mcmp"
"github.com/mediocregopher/mediocre-go-lib/mctx"
"github.com/mediocregopher/mediocre-go-lib/merr"
)
// SourceEnv is a Source which will parse configuration from the process
// environment.
//
// Possible Env options are generated by joining a Param's Path and Name with
// underscores and making all characters uppercase, as well as changing all
// dashes to underscores.
//
// cmp := new(mcmp.Component)
// cmpFoo := cmp.Child("foo")
// cmpFooBar := cmp.Child("bar")
// addr := mcfg.String(cmpFooBar, "srv-addr", "", "Some address")
// // the Env option to fill addr will be "FOO_BAR_SRV_ADDR"
//
type SourceEnv struct {
// In the format key=value. Defaults to os.Environ() if nil.
Env []string
// If set then all expected Env options must be prefixed with this string,
// which will be uppercased and have dashes replaced with underscores like
// all the other parts of the option names.
Prefix string
}
var _ Source = new(SourceEnv)
func (env *SourceEnv) expectedName(path []string, name string) string {
out := strings.Join(append(path, name), "_")
if env.Prefix != "" {
out = env.Prefix + "_" + out
}
out = strings.Replace(out, "-", "_", -1)
out = strings.ToUpper(out)
return out
}
// Parse implements the method for the Source interface.
func (env *SourceEnv) Parse(cmp *mcmp.Component) ([]ParamValue, error) {
kvs := env.Env
if kvs == nil {
kvs = os.Environ()
}
params := CollectParams(cmp)
pM := map[string]Param{}
for _, p := range params {
name := env.expectedName(p.Component.Path(), p.Name)
pM[name] = p
}
pvs := make([]ParamValue, 0, len(kvs))
for _, kv := range kvs {
split := strings.SplitN(kv, "=", 2)
if len(split) != 2 {
return nil, merr.New("malformed environment key/value pair",
mctx.Annotated("kv", kv))
}
k, v := split[0], split[1]
if p, ok := pM[k]; ok {
pvs = append(pvs, ParamValue{
Name: p.Name,
Path: p.Component.Path(),
Value: p.fuzzyParse(v),
})
}
}
return pvs, nil
}