diff options
author | Ahmad Sherif <me@ahmadsherif.com> | 2016-12-22 17:54:55 +0300 |
---|---|---|
committer | Ahmad Sherif <me@ahmadsherif.com> | 2016-12-23 22:14:07 +0300 |
commit | e32c0ad734100057234a2f9e2b255fc8ac3162d5 (patch) | |
tree | 61fe09e2664c7667c3f0d5a27e147c2834ecc3f0 | |
parent | fce0a9c1edcd950a815e3f0fd764ce7efb16b395 (diff) |
Use envconfig package for configurations setting
-rw-r--r-- | cmd/gitaly/main.go | 20 | ||||
-rw-r--r-- | vendor/github.com/kelseyhightower/envconfig/LICENSE | 19 | ||||
-rw-r--r-- | vendor/github.com/kelseyhightower/envconfig/MAINTAINERS | 2 | ||||
-rw-r--r-- | vendor/github.com/kelseyhightower/envconfig/README.md | 175 | ||||
-rw-r--r-- | vendor/github.com/kelseyhightower/envconfig/doc.go | 8 | ||||
-rw-r--r-- | vendor/github.com/kelseyhightower/envconfig/env_os.go | 7 | ||||
-rw-r--r-- | vendor/github.com/kelseyhightower/envconfig/env_syscall.go | 7 | ||||
-rw-r--r-- | vendor/github.com/kelseyhightower/envconfig/envconfig.go | 273 | ||||
-rw-r--r-- | vendor/vendor.json | 6 |
9 files changed, 510 insertions, 7 deletions
diff --git a/cmd/gitaly/main.go b/cmd/gitaly/main.go index 675f4492e..3c6df166d 100644 --- a/cmd/gitaly/main.go +++ b/cmd/gitaly/main.go @@ -1,35 +1,41 @@ package main import ( - "flag" + "log" "net/http" "os" "os/signal" "syscall" + "github.com/kelseyhightower/envconfig" "github.com/prometheus/client_golang/prometheus/promhttp" serv "gitlab.com/gitlab-org/gitaly/server" ) -var ( - prometheusListenAddr = flag.String("prometheusListenAddr", "", "Prometheus listening address, e.g. ':9100'") -) +type Config struct { + PrometheusListenAddr string `split_words:"true"` +} func main() { ch := make(chan os.Signal) signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM) - server := serv.NewServer() + config := Config{} + err := envconfig.Process("gitaly", &config) + if err != nil { + log.Fatal(err) + } + go func() { server.Serve("0.0.0.0:6666", serv.CommandExecutor) }() - if *prometheusListenAddr != "" { + if config.PrometheusListenAddr != "" { promMux := http.NewServeMux() promMux.Handle("/metrics", promhttp.Handler()) go func() { - http.ListenAndServe(*prometheusListenAddr, promMux) + http.ListenAndServe(config.PrometheusListenAddr, promMux) }() } diff --git a/vendor/github.com/kelseyhightower/envconfig/LICENSE b/vendor/github.com/kelseyhightower/envconfig/LICENSE new file mode 100644 index 000000000..4bfa7a84d --- /dev/null +++ b/vendor/github.com/kelseyhightower/envconfig/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2013 Kelsey Hightower + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/kelseyhightower/envconfig/MAINTAINERS b/vendor/github.com/kelseyhightower/envconfig/MAINTAINERS new file mode 100644 index 000000000..6527a9f2c --- /dev/null +++ b/vendor/github.com/kelseyhightower/envconfig/MAINTAINERS @@ -0,0 +1,2 @@ +Kelsey Hightower kelsey.hightower@gmail.com github.com/kelseyhightower +Travis Parker travis.parker@gmail.com github.com/teepark diff --git a/vendor/github.com/kelseyhightower/envconfig/README.md b/vendor/github.com/kelseyhightower/envconfig/README.md new file mode 100644 index 000000000..09de74b42 --- /dev/null +++ b/vendor/github.com/kelseyhightower/envconfig/README.md @@ -0,0 +1,175 @@ +# envconfig + +[![Build Status](https://travis-ci.org/kelseyhightower/envconfig.png)](https://travis-ci.org/kelseyhightower/envconfig) + +```Go +import "github.com/kelseyhightower/envconfig" +``` + +## Documentation + +See [godoc](http://godoc.org/github.com/kelseyhightower/envconfig) + +## Usage + +Set some environment variables: + +```Bash +export MYAPP_DEBUG=false +export MYAPP_PORT=8080 +export MYAPP_USER=Kelsey +export MYAPP_RATE="0.5" +export MYAPP_TIMEOUT="3m" +export MYAPP_USERS="rob,ken,robert" +``` + +Write some code: + +```Go +package main + +import ( + "fmt" + "log" + "time" + + "github.com/kelseyhightower/envconfig" +) + +type Specification struct { + Debug bool + Port int + User string + Users []string + Rate float32 + Timeout time.Duration +} + +func main() { + var s Specification + err := envconfig.Process("myapp", &s) + if err != nil { + log.Fatal(err.Error()) + } + format := "Debug: %v\nPort: %d\nUser: %s\nRate: %f\nTimeout: %s\n" + _, err = fmt.Printf(format, s.Debug, s.Port, s.User, s.Rate) + if err != nil { + log.Fatal(err.Error()) + } + + fmt.Println("Users:") + for _, u := range s.Users { + fmt.Printf(" %s\n", u) + } +} +``` + +Results: + +```Bash +Debug: false +Port: 8080 +User: Kelsey +Rate: 0.500000 +Timeout: 3m0s +Users: + rob + ken + robert +``` + +## Struct Tag Support + +Envconfig supports the use of struct tags to specify alternate, default, and required +environment variables. + +For example, consider the following struct: + +```Go +type Specification struct { + ManualOverride1 string `envconfig:"manual_override_1"` + DefaultVar string `default:"foobar"` + RequiredVar string `required:"true"` + IgnoredVar string `ignored:"true"` + AutoSplitVar string `split_words:"true"` +} +``` + +Envconfig has automatic support for CamelCased struct elements when the +`split_words:"true"` tag is supplied. Without this tag, `AutoSplitVar` above +would look for an environment variable called `MYAPP_AUTOSPLITVAR`. With the +setting applied it will look for `MYAPP_AUTO_SPLIT_VAR`. Note that numbers +will get globbed into the previous word. If the setting does not do the +right thing, you may use a manual override. + +Envconfig will process value for `ManualOverride1` by populating it with the +value for `MYAPP_MANUAL_OVERRIDE_1`. Without this struct tag, it would have +instead looked up `MYAPP_MANUALOVERRIDE1`. With the `split_words:"true"` tag +it would have looked up `MYAPP_MANUAL_OVERRIDE1`. + +```Bash +export MYAPP_MANUAL_OVERRIDE_1="this will be the value" + +# export MYAPP_MANUALOVERRIDE1="and this will not" +``` + +If envconfig can't find an environment variable value for `MYAPP_DEFAULTVAR`, +it will populate it with "foobar" as a default value. + +If envconfig can't find an environment variable value for `MYAPP_REQUIREDVAR`, +it will return an error when asked to process the struct. + +If envconfig can't find an environment variable in the form `PREFIX_MYVAR`, and there +is a struct tag defined, it will try to populate your variable with an environment +variable that directly matches the envconfig tag in your struct definition: + +```shell +export SERVICE_HOST=127.0.0.1 +export MYAPP_DEBUG=true +``` +```Go +type Specification struct { + ServiceHost string `envconfig:"SERVICE_HOST"` + Debug bool +} +``` + +Envconfig won't process a field with the "ignored" tag set to "true", even if a corresponding +environment variable is set. + +## Supported Struct Field Types + +envconfig supports supports these struct field types: + + * string + * int8, int16, int32, int64 + * bool + * float32, float64 + * [encoding.TextUnmarshaler](https://golang.org/pkg/encoding/#TextUnmarshaler) + +Embedded structs using these fields are also supported. + +## Custom Decoders + +Any field whose type (or pointer-to-type) implements `envconfig.Decoder` can +control its own deserialization: + +```Bash +export DNS_SERVER=8.8.8.8 +``` + +```Go +type IPDecoder net.IP + +func (ipd *IPDecoder) Decode(value string) error { + *ipd = IPDecoder(net.ParseIP(value)) + return nil +} + +type DNSConfig struct { + Address IPDecoder `envconfig:"DNS_SERVER"` +} +``` + +Also, envconfig will use a `Set(string) error` method like from the +[flag.Value](https://godoc.org/flag#Value) interface if implemented. diff --git a/vendor/github.com/kelseyhightower/envconfig/doc.go b/vendor/github.com/kelseyhightower/envconfig/doc.go new file mode 100644 index 000000000..f28561cd1 --- /dev/null +++ b/vendor/github.com/kelseyhightower/envconfig/doc.go @@ -0,0 +1,8 @@ +// Copyright (c) 2013 Kelsey Hightower. All rights reserved. +// Use of this source code is governed by the MIT License that can be found in +// the LICENSE file. + +// Package envconfig implements decoding of environment variables based on a user +// defined specification. A typical use is using environment variables for +// configuration settings. +package envconfig diff --git a/vendor/github.com/kelseyhightower/envconfig/env_os.go b/vendor/github.com/kelseyhightower/envconfig/env_os.go new file mode 100644 index 000000000..a6a014a2b --- /dev/null +++ b/vendor/github.com/kelseyhightower/envconfig/env_os.go @@ -0,0 +1,7 @@ +// +build appengine + +package envconfig + +import "os" + +var lookupEnv = os.LookupEnv diff --git a/vendor/github.com/kelseyhightower/envconfig/env_syscall.go b/vendor/github.com/kelseyhightower/envconfig/env_syscall.go new file mode 100644 index 000000000..9d98085b9 --- /dev/null +++ b/vendor/github.com/kelseyhightower/envconfig/env_syscall.go @@ -0,0 +1,7 @@ +// +build !appengine + +package envconfig + +import "syscall" + +var lookupEnv = syscall.Getenv diff --git a/vendor/github.com/kelseyhightower/envconfig/envconfig.go b/vendor/github.com/kelseyhightower/envconfig/envconfig.go new file mode 100644 index 000000000..38e449ebb --- /dev/null +++ b/vendor/github.com/kelseyhightower/envconfig/envconfig.go @@ -0,0 +1,273 @@ +// Copyright (c) 2013 Kelsey Hightower. All rights reserved. +// Use of this source code is governed by the MIT License that can be found in +// the LICENSE file. + +package envconfig + +import ( + "encoding" + "errors" + "fmt" + "reflect" + "regexp" + "strconv" + "strings" + "time" +) + +// ErrInvalidSpecification indicates that a specification is of the wrong type. +var ErrInvalidSpecification = errors.New("specification must be a struct pointer") + +// A ParseError occurs when an environment variable cannot be converted to +// the type required by a struct field during assignment. +type ParseError struct { + KeyName string + FieldName string + TypeName string + Value string + Err error +} + +// Decoder has the same semantics as Setter, but takes higher precedence. +// It is provided for historical compatibility. +type Decoder interface { + Decode(value string) error +} + +// Setter is implemented by types can self-deserialize values. +// Any type that implements flag.Value also implements Setter. +type Setter interface { + Set(value string) error +} + +func (e *ParseError) Error() string { + return fmt.Sprintf("envconfig.Process: assigning %[1]s to %[2]s: converting '%[3]s' to type %[4]s. details: %[5]s", e.KeyName, e.FieldName, e.Value, e.TypeName, e.Err) +} + +// Process populates the specified struct based on environment variables +func Process(prefix string, spec interface{}) error { + // For splitting camelCased words + expr := regexp.MustCompile("([^A-Z]+|[A-Z][^A-Z]+|[A-Z]+)") + + s := reflect.ValueOf(spec) + + if s.Kind() != reflect.Ptr { + return ErrInvalidSpecification + } + s = s.Elem() + if s.Kind() != reflect.Struct { + return ErrInvalidSpecification + } + typeOfSpec := s.Type() + for i := 0; i < s.NumField(); i++ { + f := s.Field(i) + ftype := typeOfSpec.Field(i) + if !f.CanSet() || ftype.Tag.Get("ignored") == "true" { + continue + } + + for f.Kind() == reflect.Ptr { + if f.IsNil() { + if f.Type().Elem().Kind() != reflect.Struct { + // nil pointer to a non-struct: leave it alone + break + } + // nil pointer to struct: create a zero instance + f.Set(reflect.New(f.Type().Elem())) + } + f = f.Elem() + } + + // Default to the field name as the env var name (will be upcased) + key := ftype.Name + + // Best effort to un-pick camel casing as separate words + if ftype.Tag.Get("split_words") == "true" { + words := expr.FindAllStringSubmatch(ftype.Name, -1) + if len(words) > 0 { + var name []string + for _, words := range words { + name = append(name, words[0]) + } + + key = strings.Join(name, "_") + } + } + + alt := ftype.Tag.Get("envconfig") + if alt != "" { + key = alt + } + + if prefix != "" { + key = fmt.Sprintf("%s_%s", prefix, key) + } + + key = strings.ToUpper(key) + + if f.Kind() == reflect.Struct { + // honor Decode if present + if decoderFrom(f) == nil && setterFrom(f) == nil && textUnmarshaler(f) == nil { + innerPrefix := prefix + if !ftype.Anonymous { + innerPrefix = key + } + + embeddedPtr := f.Addr().Interface() + if err := Process(innerPrefix, embeddedPtr); err != nil { + return err + } + f.Set(reflect.ValueOf(embeddedPtr).Elem()) + + continue + } + } + + // `os.Getenv` cannot differentiate between an explicitly set empty value + // and an unset value. `os.LookupEnv` is preferred to `syscall.Getenv`, + // but it is only available in go1.5 or newer. We're using Go build tags + // here to use os.LookupEnv for >=go1.5 + value, ok := lookupEnv(key) + if !ok && alt != "" { + key := strings.ToUpper(alt) + value, ok = lookupEnv(key) + } + + def := ftype.Tag.Get("default") + if def != "" && !ok { + value = def + } + + req := ftype.Tag.Get("required") + if !ok && def == "" { + if req == "true" { + return fmt.Errorf("required key %s missing value", key) + } + continue + } + + err := processField(value, f) + if err != nil { + return &ParseError{ + KeyName: key, + FieldName: ftype.Name, + TypeName: f.Type().String(), + Value: value, + Err: err, + } + } + } + return nil +} + +// MustProcess is the same as Process but panics if an error occurs +func MustProcess(prefix string, spec interface{}) { + if err := Process(prefix, spec); err != nil { + panic(err) + } +} + +func processField(value string, field reflect.Value) error { + typ := field.Type() + + decoder := decoderFrom(field) + if decoder != nil { + return decoder.Decode(value) + } + // look for Set method if Decode not defined + setter := setterFrom(field) + if setter != nil { + return setter.Set(value) + } + + if t := textUnmarshaler(field); t != nil { + return t.UnmarshalText([]byte(value)) + } + + if typ.Kind() == reflect.Ptr { + typ = typ.Elem() + if field.IsNil() { + field.Set(reflect.New(typ)) + } + field = field.Elem() + } + + switch typ.Kind() { + case reflect.String: + field.SetString(value) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + var ( + val int64 + err error + ) + if field.Kind() == reflect.Int64 && typ.PkgPath() == "time" && typ.Name() == "Duration" { + var d time.Duration + d, err = time.ParseDuration(value) + val = int64(d) + } else { + val, err = strconv.ParseInt(value, 0, typ.Bits()) + } + if err != nil { + return err + } + + field.SetInt(val) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + val, err := strconv.ParseUint(value, 0, typ.Bits()) + if err != nil { + return err + } + field.SetUint(val) + case reflect.Bool: + val, err := strconv.ParseBool(value) + if err != nil { + return err + } + field.SetBool(val) + case reflect.Float32, reflect.Float64: + val, err := strconv.ParseFloat(value, typ.Bits()) + if err != nil { + return err + } + field.SetFloat(val) + case reflect.Slice: + vals := strings.Split(value, ",") + sl := reflect.MakeSlice(typ, len(vals), len(vals)) + for i, val := range vals { + err := processField(val, sl.Index(i)) + if err != nil { + return err + } + } + field.Set(sl) + } + + return nil +} + +func interfaceFrom(field reflect.Value, fn func(interface{}, *bool)) { + // it may be impossible for a struct field to fail this check + if !field.CanInterface() { + return + } + var ok bool + fn(field.Interface(), &ok) + if !ok && field.CanAddr() { + fn(field.Addr().Interface(), &ok) + } +} + +func decoderFrom(field reflect.Value) (d Decoder) { + interfaceFrom(field, func(v interface{}, ok *bool) { d, *ok = v.(Decoder) }) + return d +} + +func setterFrom(field reflect.Value) (s Setter) { + interfaceFrom(field, func(v interface{}, ok *bool) { s, *ok = v.(Setter) }) + return s +} + +func textUnmarshaler(field reflect.Value) (t encoding.TextUnmarshaler) { + interfaceFrom(field, func(v interface{}, ok *bool) { t, *ok = v.(encoding.TextUnmarshaler) }) + return t +} diff --git a/vendor/vendor.json b/vendor/vendor.json index 8e256632a..33fdb527a 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -15,6 +15,12 @@ "revisionTime": "2016-11-17T03:31:26Z" }, { + "checksumSHA1": "ngWgR7cRhH340bOHEpLTJCY1jTs=", + "path": "github.com/kelseyhightower/envconfig", + "revision": "5c008110b20b657eb7e005b83d0a5f6aa6bb5f4b", + "revisionTime": "2016-12-05T22:33:43Z" + }, + { "checksumSHA1": "bKMZjd2wPw13VwoE7mBeSv5djFA=", "path": "github.com/matttproud/golang_protobuf_extensions/pbutil", "revision": "c12348ce28de40eed0136aa2b644d0ee0650e56c", |