package mcfg import ( "fmt" "os" "strings" ) // 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. // // cfg := mcfg.New().Child("foo").Child("bar") // addr := cfg.ParamString("srv-addr", "", "Some address") // // the Env option to fill addr will be "FOO_BAR_SRV_ADDR" // type SourceEnv struct { Env []string // in the format key=value // 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 } 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(cfg *Cfg) ([]ParamValue, error) { kvs := env.Env if kvs == nil { kvs = os.Environ() } pvM := map[string]ParamValue{} for _, pv := range cfg.allParamValues() { name := env.expectedName(pv.Path, pv.Name) pvM[name] = pv } pvs := make([]ParamValue, 0, len(kvs)) for _, kv := range kvs { split := strings.SplitN(kv, "=", 2) if len(split) != 2 { return nil, fmt.Errorf("malformed environment kv %q", kv) } k, v := split[0], split[1] if pv, ok := pvM[k]; ok { pv.Value = fuzzyParse(pv.Param, v) pvs = append(pvs, pv) } } return pvs, nil }