diff --git a/.hooks/pre-commit b/.hooks/pre-commit new file mode 100755 index 0000000..24df17c --- /dev/null +++ b/.hooks/pre-commit @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +go fmt *.go +git add *.go diff --git a/datatype.go b/datatype.go index 2b5373e..687d235 100644 --- a/datatype.go +++ b/datatype.go @@ -1,37 +1,41 @@ package envconf -import ("time") + +import ( + "time" +) type DataType int + const ( - TypeNone DataType = iota - TypeInt DataType = iota - TypeMetric DataType = iota - TypeDuration DataType = iota - TypeString DataType = iota - TypeDirectory DataType = iota - TypeBool DataType = iota + TypeNone DataType = iota + TypeInt DataType = iota + TypeMetric DataType = iota + TypeDuration DataType = iota + TypeString DataType = iota + TypeDirectory DataType = iota + TypeBool DataType = iota ) type cValue struct { - dtype DataType - intval int64 - durval time.Duration - boolval bool - strval string - err error + dtype DataType + intval int64 + durval time.Duration + boolval bool + strval string + err error } -func (dtype DataType) parse(key string, str string)(ret cValue) { - info, ok := tInfo[dtype] - if ok { - return info.parser(key, str) - } - return +func (dtype DataType) parse(key string, str string) (ret cValue) { + info, ok := tInfo[dtype] + if ok { + return info.parser(key, str) + } + return } -func (dtype DataType) String()(string) { - info, ok := tInfo[dtype] - if ok { - return info.name - } - return "invalid" +func (dtype DataType) String() string { + info, ok := tInfo[dtype] + if ok { + return info.name + } + return "invalid" } diff --git a/envconf.go b/envconf.go index c15d049..70657ee 100644 --- a/envconf.go +++ b/envconf.go @@ -1,186 +1,188 @@ package envconf -import ("strings" - "unicode" - "errors" - "time" - "fmt" - "os") +import ( + "errors" + "fmt" + "os" + "strings" + "time" + "unicode" +) type cEntry struct { - value string - parsed cValue - dtype DataType - unset bool - empty bool + value string + parsed cValue + dtype DataType + unset bool + empty bool } type Config struct { - parsed bool - env map[string]cEntry + parsed bool + env map[string]cEntry } // NewConfig returns an envconf.Config that is used to read configuration from environment variables. // The environment variables are stored in envconf.Config, so changes to the environment after NewConfig has been called // will not be taken into account. -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.ToUpper(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 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.ToUpper(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 } // Define defines the type of an environment variable. // Variables without a defined type will be ignored by Parse. func (c *Config) Define(key string, dtype DataType) { - upper := strings.ToUpper(key) - entry, ok := c.env[upper] - if ok { - entry.dtype = dtype - c.env[upper] = entry - } else { - var entry cEntry - entry.dtype = dtype - entry.unset = true - entry.empty = true - c.env[upper] = entry - } + upper := strings.ToUpper(key) + entry, ok := c.env[upper] + if ok { + entry.dtype = dtype + c.env[upper] = entry + } else { + var entry cEntry + entry.dtype = dtype + entry.unset = true + entry.empty = true + c.env[upper] = entry + } } // DefineDefault defines the type and default value of an environment variable. // Variables without a defined type will be ignored by Parse. func (c *Config) DefineDefault(key string, val string, dtype DataType) { - upper := strings.ToUpper(key) - entry, ok := c.env[upper] - if ok { - if entry.unset { - entry.value = val - } - entry.dtype = dtype - entry.empty = false - c.env[upper] = entry - } else { - var entry cEntry - entry.dtype = dtype - entry.unset = true - entry.empty = false - entry.value = val - c.env[upper] = entry - } + upper := strings.ToUpper(key) + entry, ok := c.env[upper] + if ok { + if entry.unset { + entry.value = val + } + entry.dtype = dtype + entry.empty = false + c.env[upper] = entry + } else { + var entry cEntry + entry.dtype = dtype + entry.unset = true + entry.empty = false + entry.value = val + c.env[upper] = entry + } } // Parse parses the environment variables previously defined by Define and DefineDefault. // Parse should only be called once for a given envconf.Config. func (c *Config) Parse() { - if c.parsed { - return - } - c.parsed = true - for k,v := range c.env { - 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)) - c.env[k] = v - } - } else { - v.parsed = v.dtype.parse(k, v.value) - c.env[k] = v - } - } + if c.parsed { + return + } + c.parsed = true + for k, v := range c.env { + 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)) + c.env[k] = v + } + } else { + v.parsed = v.dtype.parse(k, v.value) + c.env[k] = v + } + } } // Status prints out failures that occured while parsing the environment to os.Stderr. // Variables that have been defined without a default value and are // missing from the environment will be considered a failure. // If parsing of any of the variables has failed Status will return false. -func (c *Config) Status()(ok bool) { - ok = c.parsed - if ok { - for _,v := range c.env { - err := v.parsed.err - if err != nil { - ok = false - fmt.Fprintln(os.Stderr, err) - } - } - } - return +func (c *Config) Status() (ok bool) { + ok = c.parsed + if ok { + for _, v := range c.env { + err := v.parsed.err + if err != nil { + ok = false + fmt.Fprintln(os.Stderr, err) + } + } + } + return } -func (c *Config) getRaw(key string, dtype DataType)(val cValue) { - val.dtype = TypeNone - if c.parsed { - upper := strings.ToUpper(key) - entry, ok := c.env[upper] - if ok && (entry.dtype == dtype) { - return entry.parsed - } - } - return +func (c *Config) getRaw(key string, dtype DataType) (val cValue) { + val.dtype = TypeNone + if c.parsed { + upper := strings.ToUpper(key) + entry, ok := c.env[upper] + if ok && (entry.dtype == dtype) { + return entry.parsed + } + } + return } // GetInt returns the value of an environment variable. // If the variable is not defined as envconf.TypeInt the function will return 0. -func (c *Config) GetInt(key string)(int64) { - val := c.getRaw(key, TypeInt) - return val.intval +func (c *Config) GetInt(key string) int64 { + val := c.getRaw(key, TypeInt) + return val.intval } // GetMetric returns the value of an environment variable. // If the variable is not defined as envconf.TypeMetric the function will return 0. -func (c *Config) GetMetric(key string)(int64) { - val := c.getRaw(key, TypeMetric) - return val.intval +func (c *Config) GetMetric(key string) int64 { + val := c.getRaw(key, TypeMetric) + return val.intval } // GetDirectory returns the value of an environment variable. // If the variable is not defined as envconf.TypeDirectory the // function will return the empty string. -func (c *Config) GetDirectory(key string)(string) { - val := c.getRaw(key, TypeDirectory) - return val.strval +func (c *Config) GetDirectory(key string) string { + val := c.getRaw(key, TypeDirectory) + return val.strval } // GetString returns the value of an environment variable. // If the variable is not defined as envconf.TypeString the // function will return the empty string. -func (c *Config) GetString(key string)(string) { - val := c.getRaw(key, TypeString) - return val.strval +func (c *Config) GetString(key string) string { + val := c.getRaw(key, TypeString) + return val.strval } // GetDuration returns the value of an environment variable. // If the variable is not defined as envconf.TypeDuration the // function will return time.Duration(0). -func (c *Config) GetDuration(key string)(time.Duration) { - val := c.getRaw(key, TypeDuration) - return val.durval +func (c *Config) GetDuration(key string) time.Duration { + val := c.getRaw(key, TypeDuration) + return val.durval } // GetBool returns the value of an environment variable. // If the variable is not defined as envconf.TypeBool the // function will return false. -func (c *Config) GetBool(key string)(bool) { - val := c.getRaw(key, TypeBool) - return val.boolval +func (c *Config) GetBool(key string) bool { + val := c.getRaw(key, TypeBool) + return val.boolval } -func getFirstRune(str string)(rune) { - for _,v := range str { - return v - } - return rune(0) +func getFirstRune(str string) rune { + for _, v := range str { + return v + } + return rune(0) } diff --git a/parsers.go b/parsers.go index f3b8eda..5fcff78 100644 --- a/parsers.go +++ b/parsers.go @@ -1,84 +1,85 @@ package envconf -import ("strconv" - "strings" - "fmt" - "errors" - "os" - "path" - "time") -func parseInt(key string, str string)(ret cValue) { - val, err := strconv.ParseInt(str, 10, 64) - if err == nil { - ret.intval = val - } else { - ret.err = errors.New(fmt.Sprintf(`Environment variable "%s" is not of type int.`, key)) - } - return +import ( + "errors" + "fmt" + "os" + "path" + "strconv" + "strings" + "time" +) + +func parseInt(key string, str string) (ret cValue) { + val, err := strconv.ParseInt(str, 10, 64) + if err == nil { + ret.intval = val + } else { + ret.err = errors.New(fmt.Sprintf(`Environment variable "%s" is not of type int.`, key)) + } + return } -func parseMetric(key string, str string)(ret cValue) { - mod := int64(1) - str = strings.ToUpper(str) - if strings.HasSuffix(str, "K") { - mod = 1024 - str = strings.TrimSuffix(str, "K") - } else if strings.HasSuffix(str, "M") { - mod = 1024 * 1024 - str = strings.TrimSuffix(str, "M") - } else if strings.HasSuffix(str, "G") { - mod = 1024 * 1024 * 1024 - str = strings.TrimSuffix(str, "G") - } else if strings.HasSuffix(str, "T") { - mod = 1024 * 1024 * 1024 * 1024 - str = strings.TrimSuffix(str, "T") - } - val, err := strconv.ParseInt(str, 10, 64) - if err == nil { - ret.intval = mod * val - } else { - ret.err = errors.New(fmt.Sprintf(`Environment variable "%s" is not of type int.`, key)) - } - return +func parseMetric(key string, str string) (ret cValue) { + mod := int64(1) + str = strings.ToUpper(str) + if strings.HasSuffix(str, "K") { + mod = 1024 + str = strings.TrimSuffix(str, "K") + } else if strings.HasSuffix(str, "M") { + mod = 1024 * 1024 + str = strings.TrimSuffix(str, "M") + } else if strings.HasSuffix(str, "G") { + mod = 1024 * 1024 * 1024 + str = strings.TrimSuffix(str, "G") + } else if strings.HasSuffix(str, "T") { + mod = 1024 * 1024 * 1024 * 1024 + str = strings.TrimSuffix(str, "T") + } + val, err := strconv.ParseInt(str, 10, 64) + if err == nil { + ret.intval = mod * val + } else { + ret.err = errors.New(fmt.Sprintf(`Environment variable "%s" is not of type int.`, key)) + } + return } -func parseDuration(key string, str string)(ret cValue) { - val, err := time.ParseDuration(str) - if err == nil { - ret.durval = val - } else { - ret.err = errors.New(fmt.Sprintf(`Environment variable "%s" is not of type duration.`, key)) - } - return +func parseDuration(key string, str string) (ret cValue) { + val, err := time.ParseDuration(str) + if err == nil { + ret.durval = val + } else { + ret.err = errors.New(fmt.Sprintf(`Environment variable "%s" is not of type duration.`, key)) + } + return } -func parseBool(key string, str string)(ret cValue) { - val, err := strconv.ParseBool(str) - if err == nil { - ret.boolval = val - } else { - ret.err = errors.New(fmt.Sprintf(`Environment variable "%s" is not of type bool.`, key)) - } - return +func parseBool(key string, str string) (ret cValue) { + val, err := strconv.ParseBool(str) + if err == nil { + ret.boolval = val + } else { + ret.err = errors.New(fmt.Sprintf(`Environment variable "%s" is not of type bool.`, key)) + } + return } -func parseDirectory(_ string, str string)(ret cValue) { - wd, err := os.Getwd() - if err == nil { - if path.IsAbs(str) { - ret.strval = path.Clean(str) - } else { - ret.strval = path.Join(wd, str) - } - } else { - ret.strval = path.Clean(str) - } - return +func parseDirectory(_ string, str string) (ret cValue) { + wd, err := os.Getwd() + if err == nil { + if path.IsAbs(str) { + ret.strval = path.Clean(str) + } else { + ret.strval = path.Join(wd, str) + } + } else { + ret.strval = path.Clean(str) + } + return } - -func parseString(_ string, str string)(ret cValue) { - ret.strval = str - return +func parseString(_ string, str string) (ret cValue) { + ret.strval = str + return } - diff --git a/typeinfo.go b/typeinfo.go index fde453a..c321654 100644 --- a/typeinfo.go +++ b/typeinfo.go @@ -1,36 +1,39 @@ package envconf + type dataTypeInfo struct { - parser func(string,string)(cValue) - name string + parser func(string, string) cValue + name string } + var tInfo map[DataType]dataTypeInfo + func init() { - tInfo = make(map[DataType]dataTypeInfo) - var intInfo dataTypeInfo - var metricInfo dataTypeInfo - var durInfo dataTypeInfo - var strInfo dataTypeInfo - var dirInfo dataTypeInfo - var boolInfo dataTypeInfo + tInfo = make(map[DataType]dataTypeInfo) + var intInfo dataTypeInfo + var metricInfo dataTypeInfo + var durInfo dataTypeInfo + var strInfo dataTypeInfo + var dirInfo dataTypeInfo + var boolInfo dataTypeInfo - intInfo.name = "int" - metricInfo.name = "metric" - durInfo.name = "duration" - dirInfo.name = "directory" - strInfo.name = "string" - boolInfo.name = "bool" + intInfo.name = "int" + metricInfo.name = "metric" + durInfo.name = "duration" + dirInfo.name = "directory" + strInfo.name = "string" + boolInfo.name = "bool" - intInfo.parser = parseInt - metricInfo.parser = parseMetric - durInfo.parser = parseDuration - dirInfo.parser = parseDirectory - strInfo.parser = parseString - boolInfo.parser = parseBool + intInfo.parser = parseInt + metricInfo.parser = parseMetric + durInfo.parser = parseDuration + dirInfo.parser = parseDirectory + strInfo.parser = parseString + boolInfo.parser = parseBool - tInfo[TypeInt] = intInfo - tInfo[TypeMetric] = metricInfo - tInfo[TypeDuration] = durInfo - tInfo[TypeString] = strInfo - tInfo[TypeDirectory] = dirInfo - tInfo[TypeBool] = boolInfo + tInfo[TypeInt] = intInfo + tInfo[TypeMetric] = metricInfo + tInfo[TypeDuration] = durInfo + tInfo[TypeString] = strInfo + tInfo[TypeDirectory] = dirInfo + tInfo[TypeBool] = boolInfo }