package envconf import ("strings" "unicode" "strconv" "time" "errors" "fmt" "os") type cEntry struct { value string parsed cValue dtype DataType unset bool empty bool } type cValue struct { intval int64 durval time.Duration strval string err error } type Config struct { parsed bool env map[string]cEntry } func NewConfig()(*Config) { config := new(Config) config.parsed = false config.env = make(map[string]cEntry) for _,v := range os.Environ() { splitted := strings.SplitN(v, "=", 2) if len(splitted) == 2 { key := strings.TrimSpace(strings.ToLower(splitted[0])) if unicode.IsLetter(getFirstRune(key)) { var entry cEntry entry.value = splitted[1] entry.dtype = TypeNone entry.unset = false entry.empty = false config.env[key] = entry } } } return config } func (c *Config) Define(key string, dtype DataType) { entry, ok := c.env[key] if ok { entry.dtype = dtype } else { var entry cEntry entry.dtype = dtype entry.unset = true entry.empty = true c.env[key] = entry } } func (c *Config) DefineDefault(key string, val string, dtype DataType) { entry, ok := c.env[key] if ok { if entry.unset { entry.empty = false entry.value = val entry.dtype = dtype } } else { var entry cEntry entry.dtype = dtype entry.unset = true entry.empty = false c.env[key] = entry } } func (c *Config) Parse() { parsers := make(map[DataType](func(string)(cValue))) parsers[TypeInt] = parseInt parsers[TypeDuration] = parseDuration for k,v := range c.env { parser, ok := parsers[v.dtype] if ok { if v.empty { if v.unset { v.parsed.err = errors.New(fmt.Sprintf("Environment variable %s not found. It should have been of type %s", k, v.dtype)) } } else { v.parsed = parser(v.value) } } } } func parseInt(str string)(ret cValue) { ret.intval, ret.err = strconv.ParseInt(str, 10, 64) return } func parseDuration(str string)(ret cValue) { ret.durval, ret.err = time.ParseDuration(str) return } func getFirstRune(str string)(rune) { for _,v := range str { return v } return rune(0) }