OSDN Git Service

Added env dir.
authorgguoss <1536310027@qq.com>
Wed, 23 Aug 2017 06:24:57 +0000 (14:24 +0800)
committergguoss <1536310027@qq.com>
Wed, 23 Aug 2017 06:24:57 +0000 (14:24 +0800)
env/Readme [new file with mode: 0644]
env/env.go [new file with mode: 0644]
env/env_test.go [new file with mode: 0644]

diff --git a/env/Readme b/env/Readme
new file mode 100644 (file)
index 0000000..8dabb5c
--- /dev/null
@@ -0,0 +1,2 @@
+Package env provides a convenient way to initialize
+variables from the environment.
diff --git a/env/env.go b/env/env.go
new file mode 100644 (file)
index 0000000..784423c
--- /dev/null
@@ -0,0 +1,212 @@
+// Package env provides a convenient way to convert environment
+// variables into Go data. It is similar in design to package
+// flag.
+package env
+
+import (
+       "log"
+       "net/url"
+       "os"
+       "strconv"
+       "strings"
+       "time"
+)
+
+var funcs []func() bool
+
+// Int returns a new int pointer.
+// When Parse is called,
+// env var name will be parsed
+// and the resulting value
+// will be assigned to the returned location.
+func Int(name string, value int) *int {
+       p := new(int)
+       IntVar(p, name, value)
+       return p
+}
+
+// IntVar defines an int var with the specified
+// name and default value. The argument p points
+// to an int variable in which to store the
+// value of the environment var.
+func IntVar(p *int, name string, value int) {
+       *p = value
+       funcs = append(funcs, func() bool {
+               if s := os.Getenv(name); s != "" {
+                       v, err := strconv.Atoi(s)
+                       if err != nil {
+                               log.Println(name, err)
+                               return false
+                       }
+                       *p = v
+               }
+               return true
+       })
+}
+
+// Bool returns a new bool pointer.
+// When Parse is called,
+// env var name will be parsed
+// and the resulting value
+// will be assigned to the returned location.
+// Parsing uses strconv.ParseBool.
+func Bool(name string, value bool) *bool {
+       p := new(bool)
+       BoolVar(p, name, value)
+       return p
+}
+
+// BoolVar defines a bool var with the specified
+// name and default value. The argument p points
+// to a bool variable in which to store the value
+// of the environment variable.
+func BoolVar(p *bool, name string, value bool) {
+       *p = value
+       funcs = append(funcs, func() bool {
+               if s := os.Getenv(name); s != "" {
+                       v, err := strconv.ParseBool(s)
+                       if err != nil {
+                               log.Println(name, err)
+                               return false
+                       }
+                       *p = v
+               }
+               return true
+       })
+}
+
+// Duration returns a new time.Duration pointer.
+// When Parse is called,
+// env var name will be parsed
+// and the resulting value
+// will be assigned to the returned location.
+func Duration(name string, value time.Duration) *time.Duration {
+       p := new(time.Duration)
+       DurationVar(p, name, value)
+       return p
+}
+
+// DurationVar defines a time.Duration var with
+// the specified name and default value. The
+// argument p points to a time.Duration variable
+// in which to store the value of the environment
+// variable.
+func DurationVar(p *time.Duration, name string, value time.Duration) {
+       *p = value
+       funcs = append(funcs, func() bool {
+               if s := os.Getenv(name); s != "" {
+                       v, err := time.ParseDuration(s)
+                       if err != nil {
+                               log.Println(name, err)
+                               return false
+                       }
+                       *p = v
+               }
+               return true
+       })
+}
+
+// URL returns a new url.URL pointer.
+// When Parse is called,
+// env var name will be parsed
+// and the resulting value
+// will be assigned to the returned location.
+// URL panics if there is an error parsing
+// the given default value.
+func URL(name string, value string) *url.URL {
+       p := new(url.URL)
+       URLVar(p, name, value)
+       return p
+}
+
+// URLVar defines a url.URL variable with
+// the specified name ande default value.
+// The argument p points to a url.URL variable
+// in which to store the value of the environment
+// variable.
+func URLVar(p *url.URL, name string, value string) {
+       v, err := url.Parse(value)
+       if err != nil {
+               panic(err)
+       }
+       *p = *v
+       funcs = append(funcs, func() bool {
+               if s := os.Getenv(name); s != "" {
+                       v, err := url.Parse(s)
+                       if err != nil {
+                               log.Println(name, err)
+                               return false
+                       }
+                       *p = *v
+               }
+               return true
+       })
+}
+
+// String returns a new string pointer.
+// When Parse is called,
+// env var name will be assigned
+// to the returned location.
+func String(name string, value string) *string {
+       p := new(string)
+       StringVar(p, name, value)
+       return p
+}
+
+// StringVar defines a string with the
+// specified name and default value. The
+// argument p points to a string variable in
+// which to store the value of the environment
+// var.
+func StringVar(p *string, name string, value string) {
+       *p = value
+       funcs = append(funcs, func() bool {
+               if s := os.Getenv(name); s != "" {
+                       *p = s
+               }
+               return true
+       })
+}
+
+// StringSlice returns a pointer to a slice
+// of strings. It expects env var name to
+// be a list of items delimited by commas.
+// If env var name is missing, StringSlice
+// returns a pointer to a slice of the value
+// strings.
+func StringSlice(name string, value ...string) *[]string {
+       p := new([]string)
+       StringSliceVar(p, name, value...)
+       return p
+}
+
+// StringSliceVar defines a new string slice
+// with the specified name. The argument p
+// points to a string slice variable in which
+// to store the value of the environment var.
+func StringSliceVar(p *[]string, name string, value ...string) {
+       *p = value
+       funcs = append(funcs, func() bool {
+               if s := os.Getenv(name); s != "" {
+                       a := strings.Split(s, ",")
+                       *p = a
+               }
+               return true
+       })
+}
+
+// Parse parses known env vars
+// and assigns the values to the variables
+// that were previously registered.
+// If any values cannot be parsed,
+// Parse prints an error message for each one
+// and exits the process with status 1.
+func Parse() {
+       ok := true
+       for _, f := range funcs {
+               ok = f() && ok
+       }
+       if !ok {
+               os.Exit(1)
+       }
+}
diff --git a/env/env_test.go b/env/env_test.go
new file mode 100644 (file)
index 0000000..06ff72c
--- /dev/null
@@ -0,0 +1,275 @@
+package env
+
+import (
+       "net/url"
+       "os"
+       "reflect"
+       "testing"
+       "time"
+)
+
+func TestInt(t *testing.T) {
+       result := Int("nonexistent", 15)
+       Parse()
+
+       if *result != 15 {
+               t.Fatalf("expected result=15, got result=%d", *result)
+       }
+
+       err := os.Setenv("int-key", "25")
+       if err != nil {
+               t.Fatal("unexpected error", err)
+       }
+
+       result = Int("int-key", 15)
+       Parse()
+
+       if *result != 25 {
+               t.Fatalf("expected result=25, got result=%d", *result)
+       }
+}
+
+func TestIntVar(t *testing.T) {
+       var result int
+       IntVar(&result, "nonexistent", 15)
+       Parse()
+
+       if result != 15 {
+               t.Fatalf("expected result=15, got result=%d", result)
+       }
+
+       err := os.Setenv("int-key", "25")
+       if err != nil {
+               t.Fatal("unexpected error", err)
+       }
+
+       IntVar(&result, "int-key", 15)
+       Parse()
+
+       if result != 25 {
+               t.Fatalf("expected result=25, got result=%d", result)
+       }
+}
+
+func TestBool(t *testing.T) {
+       result := Bool("nonexistent", true)
+       Parse()
+
+       if *result != true {
+               t.Fatalf("expected result=true, got result=%t", *result)
+       }
+
+       err := os.Setenv("bool-key", "true")
+       if err != nil {
+               t.Fatal("unexpected error", err)
+       }
+
+       result = Bool("bool-key", false)
+       Parse()
+
+       if *result != true {
+               t.Fatalf("expected result=true, got result=%t", *result)
+       }
+}
+
+func TestBoolVar(t *testing.T) {
+       var result bool
+       BoolVar(&result, "nonexistent", true)
+       Parse()
+
+       if result != true {
+               t.Fatalf("expected result=true, got result=%t", result)
+       }
+
+       err := os.Setenv("bool-key", "true")
+       if err != nil {
+               t.Fatal("unexpected error", err)
+       }
+
+       BoolVar(&result, "bool-key", false)
+       Parse()
+
+       if result != true {
+               t.Fatalf("expected result=true, got result=%t", true)
+       }
+}
+
+func TestDuration(t *testing.T) {
+       result := Duration("nonexistent", 15*time.Second)
+       Parse()
+
+       if *result != 15*time.Second {
+               t.Fatalf("expected result=15s, got result=%v", *result)
+       }
+
+       err := os.Setenv("duration-key", "25s")
+       if err != nil {
+               t.Fatal("unexpected error", err)
+       }
+
+       result = Duration("duration-key", 15*time.Second)
+       Parse()
+
+       if *result != 25*time.Second {
+               t.Fatalf("expected result=25s, got result=%v", *result)
+       }
+}
+
+func TestDurationVar(t *testing.T) {
+       var result time.Duration
+       DurationVar(&result, "nonexistent", 15*time.Second)
+       Parse()
+
+       if result != 15*time.Second {
+               t.Fatalf("expected result=15s, got result=%v", result)
+       }
+
+       err := os.Setenv("duration-key", "25s")
+       if err != nil {
+               t.Fatal("unexpected error", err)
+       }
+
+       DurationVar(&result, "duration-key", 15*time.Second)
+       Parse()
+
+       if result != 25*time.Second {
+               t.Fatalf("expected result=25s, got result=%v", result)
+       }
+}
+
+func TestURL(t *testing.T) {
+       example := "http://example.com"
+       newExample := "http://something-new.com"
+       result := URL("nonexistent", example)
+       Parse()
+
+       if result.String() != example {
+               t.Fatalf("expected result=%s, got result=%v", example, result)
+       }
+
+       err := os.Setenv("url-key", newExample)
+       if err != nil {
+               t.Fatal("unexpected error", err)
+       }
+
+       result = URL("url-key", example)
+       Parse()
+
+       if result.String() != newExample {
+               t.Fatalf("expected result=%v, got result=%v", newExample, result)
+       }
+}
+
+func TestURLVar(t *testing.T) {
+       example := "http://example.com"
+       newExample := "http://something-new.com"
+       var result url.URL
+       URLVar(&result, "nonexistent", example)
+       Parse()
+
+       if result.String() != example {
+               t.Fatalf("expected result=%s, got result=%v", example, result)
+       }
+
+       err := os.Setenv("url-key", newExample)
+       if err != nil {
+               t.Fatal("unexpected error", err)
+       }
+
+       URLVar(&result, "url-key", example)
+       Parse()
+
+       if result.String() != newExample {
+               t.Fatalf("expected result=%v, got result=%v", newExample, result)
+       }
+}
+
+func TestString(t *testing.T) {
+       result := String("nonexistent", "default")
+       Parse()
+
+       if *result != "default" {
+               t.Fatalf("expected result=default, got result=%s", *result)
+       }
+
+       err := os.Setenv("string-key", "something-new")
+       if err != nil {
+               t.Fatal("unexpected error", err)
+       }
+
+       result = String("string-key", "default")
+       Parse()
+
+       if *result != "something-new" {
+               t.Fatalf("expected result=something-new, got result=%s", *result)
+       }
+}
+
+func TestStringVar(t *testing.T) {
+       var result string
+       StringVar(&result, "nonexistent", "default")
+       Parse()
+
+       if result != "default" {
+               t.Fatalf("expected result=default, got result=%s", result)
+       }
+
+       err := os.Setenv("string-key", "something-new")
+       if err != nil {
+               t.Fatal("unexpected error", err)
+       }
+
+       StringVar(&result, "string-key", "default")
+       Parse()
+
+       if result != "something-new" {
+               t.Fatalf("expected result=something-new, got result=%s", result)
+       }
+}
+
+func TestStringSlice(t *testing.T) {
+       result := StringSlice("empty", "hi")
+       Parse()
+
+       exp := []string{"hi"}
+       if !reflect.DeepEqual(exp, *result) {
+               t.Fatalf("expected %v, got %v", exp, *result)
+       }
+
+       err := os.Setenv("string-slice-key", "hello,world")
+       if err != nil {
+               t.Fatal("unexpected error", err)
+       }
+
+       result = StringSlice("string-slice-key", "hi")
+       Parse()
+
+       exp = []string{"hello", "world"}
+       if !reflect.DeepEqual(exp, *result) {
+               t.Fatalf("expected %v, got %v", exp, *result)
+       }
+}
+
+func TestStringSliceVar(t *testing.T) {
+       var result []string
+       StringSliceVar(&result, "empty", "hi")
+       Parse()
+
+       exp := []string{"hi"}
+       if !reflect.DeepEqual(exp, result) {
+               t.Fatalf("expected %v, got %v", exp, result)
+       }
+
+       err := os.Setenv("string-slice-key", "hello,world")
+       if err != nil {
+               t.Fatal("unexpected error", err)
+       }
+
+       StringSliceVar(&result, "string-slice-key", "hi", "there")
+       Parse()
+
+       exp = []string{"hello", "world"}
+       if !reflect.DeepEqual(exp, result) {
+               t.Fatalf("expected %v, got %v", exp, result)
+       }
+}