Use env lib, add PROXY_PORT ENV variable
This commit is contained in:
parent
803767b6f7
commit
678a8cc192
8
Gopkg.lock
generated
8
Gopkg.lock
generated
@ -7,6 +7,12 @@
|
||||
packages = ["."]
|
||||
revision = "e75332964ef517daa070d7c38a9466a0d687e0a5"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/caarlos0/env"
|
||||
packages = ["."]
|
||||
revision = "3e0f30cbf50bb82273cf60e7bb70869f4852e9b8"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/net"
|
||||
@ -16,6 +22,6 @@
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "bb1b87ff840d0a559073f327d2c493d6ca2c37ed971b13eef6796925f3980a7a"
|
||||
inputs-digest = "b579eb59bf4c9ca68a34a1b121d49796b87e80c2514576b22c53c4507f129c87"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
|
@ -24,3 +24,7 @@
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/armon/go-socks5"
|
||||
|
||||
[[constraint]]
|
||||
branch = "master"
|
||||
name = "github.com/caarlos0/env"
|
29
server.go
29
server.go
@ -1,34 +1,47 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/armon/go-socks5"
|
||||
"github.com/caarlos0/env"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type params struct {
|
||||
User string `env:"PROXY_USER" envDefault:""`
|
||||
Password string `env:"PROXY_PASSWORD" envDefault:""`
|
||||
Port string `env:"PROXY_PORT" envDefault:"1080"`
|
||||
}
|
||||
|
||||
conf := &socks5.Config{
|
||||
func main() {
|
||||
// Working with app params
|
||||
cfg := params{}
|
||||
err := env.Parse(&cfg)
|
||||
if err != nil {
|
||||
log.Printf("%+v\n", err)
|
||||
}
|
||||
|
||||
//Initialize socks5 config
|
||||
socsk5conf := &socks5.Config{
|
||||
Logger: log.New(os.Stdout, "", log.LstdFlags),
|
||||
}
|
||||
|
||||
if os.Getenv("PROXY_USER")+os.Getenv("PROXY_PASSWORD") != "" {
|
||||
if cfg.User+cfg.Password != "" {
|
||||
creds := socks5.StaticCredentials{
|
||||
os.Getenv("PROXY_USER"): os.Getenv("PROXY_PASSWORD"),
|
||||
}
|
||||
cator := socks5.UserPassAuthenticator{Credentials: creds}
|
||||
conf.AuthMethods = []socks5.Authenticator{cator}
|
||||
socsk5conf.AuthMethods = []socks5.Authenticator{cator}
|
||||
}
|
||||
|
||||
server, err := socks5.New(conf)
|
||||
server, err := socks5.New(socsk5conf)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fmt.Println("Start listening ...")
|
||||
if err := server.ListenAndServe("tcp", ":1080"); err != nil {
|
||||
log.Printf("Start listening proxy service on port %s\n", cfg.Port)
|
||||
if err := server.ListenAndServe("tcp", ":"+cfg.Port); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
1
vendor/github.com/caarlos0/env/.gitignore
generated
vendored
Normal file
1
vendor/github.com/caarlos0/env/.gitignore
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
coverage.out
|
2
vendor/github.com/caarlos0/env/.hound.yml
generated
vendored
Normal file
2
vendor/github.com/caarlos0/env/.hound.yml
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
go:
|
||||
enabled: true
|
16
vendor/github.com/caarlos0/env/.travis.yml
generated
vendored
Normal file
16
vendor/github.com/caarlos0/env/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.5
|
||||
- 1.6
|
||||
- 1.7
|
||||
- 1.8
|
||||
- tip
|
||||
before_install:
|
||||
- go get github.com/axw/gocov/gocov
|
||||
- go get github.com/mattn/goveralls
|
||||
- go get golang.org/x/tools/cmd/cover
|
||||
script:
|
||||
- go test -v -cover -race -coverprofile=coverage.out
|
||||
after_script:
|
||||
- go get github.com/mattn/goveralls
|
||||
- goveralls -coverprofile=coverage.out -service=travis-ci -repotoken='eCcizKmTdSaJCz8Ih33WDppdqb9kioYwi'
|
21
vendor/github.com/caarlos0/env/LICENSE.md
generated
vendored
Normal file
21
vendor/github.com/caarlos0/env/LICENSE.md
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2016 Carlos Alexandro Becker
|
||||
|
||||
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.
|
115
vendor/github.com/caarlos0/env/README.md
generated
vendored
Normal file
115
vendor/github.com/caarlos0/env/README.md
generated
vendored
Normal file
@ -0,0 +1,115 @@
|
||||
# env [![Build Status](https://travis-ci.org/caarlos0/env.svg?branch=master)](https://travis-ci.org/caarlos0/env) [![Coverage Status](https://coveralls.io/repos/caarlos0/env/badge.svg?branch=master&service=github)](https://coveralls.io/github/caarlos0/env?branch=master) [![](https://godoc.org/github.com/caarlos0/env?status.svg)](http://godoc.org/github.com/caarlos0/env) [![](http://goreportcard.com/badge/caarlos0/env)](http://goreportcard.com/report/caarlos0/env) [![SayThanks.io](https://img.shields.io/badge/SayThanks.io-%E2%98%BC-1EAEDB.svg?style=flat-square)](https://saythanks.io/to/caarlos0)
|
||||
|
||||
A KISS way to deal with environment variables in Go.
|
||||
|
||||
## Why
|
||||
|
||||
At first, it was boring for me to write down an entire function just to
|
||||
get some `var` from the environment and default to another in case it's missing.
|
||||
|
||||
For that manner, I wrote a `GetOr` function in the
|
||||
[go-idioms](https://github.com/caarlos0/go-idioms) project.
|
||||
|
||||
Then, I got pissed about writing `os.Getenv`, `os.Setenv`, `os.Unsetenv`...
|
||||
it kind of make more sense to me write it as `env.Get`, `env.Set`, `env.Unset`.
|
||||
So I did.
|
||||
|
||||
Then I got a better idea: to use `struct` tags to do all that work for me.
|
||||
|
||||
## Example
|
||||
|
||||
A very basic example (check the `examples` folder):
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/caarlos0/env"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
Home string `env:"HOME"`
|
||||
Port int `env:"PORT" envDefault:"3000"`
|
||||
IsProduction bool `env:"PRODUCTION"`
|
||||
Hosts []string `env:"HOSTS" envSeparator:":"`
|
||||
Duration time.Duration `env:"DURATION"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg := config{}
|
||||
err := env.Parse(&cfg)
|
||||
if err != nil {
|
||||
fmt.Printf("%+v\n", err)
|
||||
}
|
||||
fmt.Printf("%+v\n", cfg)
|
||||
}
|
||||
```
|
||||
|
||||
You can run it like this:
|
||||
|
||||
```sh
|
||||
$ PRODUCTION=true HOSTS="host1:host2:host3" DURATION=1s go run examples/first.go
|
||||
{Home:/your/home Port:3000 IsProduction:true Hosts:[host1 host2 host3] Duration:1s}
|
||||
```
|
||||
|
||||
## Supported types and defaults
|
||||
|
||||
The library has built-in support for the following types:
|
||||
|
||||
* `string`
|
||||
* `int`
|
||||
* `uint`
|
||||
* `int64`
|
||||
* `bool`
|
||||
* `float32`
|
||||
* `float64`
|
||||
* `time.Duration`
|
||||
* `[]string`
|
||||
* `[]int`
|
||||
* `[]bool`
|
||||
* `[]float32`
|
||||
* `[]float64`
|
||||
* `[]time.Duration`
|
||||
* .. or use/define a [custom parser func](#custom-parser-funcs) for any other type
|
||||
|
||||
If you set the `envDefault` tag for something, this value will be used in the
|
||||
case of absence of it in the environment. If you don't do that AND the
|
||||
environment variable is also not set, the zero-value
|
||||
of the type will be used: empty for `string`s, `false` for `bool`s
|
||||
and `0` for `int`s.
|
||||
|
||||
By default, slice types will split the environment value on `,`; you can change this behavior by setting the `envSeparator` tag.
|
||||
|
||||
## Custom Parser Funcs
|
||||
|
||||
If you have a type that is not supported out of the box by the lib, you are able
|
||||
to use (or define) and pass custom parsers (and their associated `reflect.Type`) to the
|
||||
`env.ParseWithFuncs()` function.
|
||||
|
||||
In addition to accepting a struct pointer (same as `Parse()`), this function also
|
||||
accepts a `env.CustomParsers` arg that under the covers is a `map[reflect.Type]env.ParserFunc`.
|
||||
|
||||
To see what this looks like in practice, take a look at the [commented block in the example](https://github.com/caarlos0/env/blob/master/examples/first.go#L35-L39).
|
||||
|
||||
`env` also ships with some pre-built custom parser funcs for common types. You
|
||||
can check them out [here](parsers/).
|
||||
|
||||
## Required fields
|
||||
|
||||
The `env` tag option `required` (e.g., `env:"tagKey,required"`) can be added
|
||||
to ensure that some environment variable is set. In the example above,
|
||||
an error is returned if the `config` struct is changed to:
|
||||
|
||||
|
||||
```go
|
||||
type config struct {
|
||||
Home string `env:"HOME"`
|
||||
Port int `env:"PORT" envDefault:"3000"`
|
||||
IsProduction bool `env:"PRODUCTION"`
|
||||
Hosts []string `env:"HOSTS" envSeparator:":"`
|
||||
SecretKey string `env:"SECRET_KEY,required"`
|
||||
}
|
||||
```
|
398
vendor/github.com/caarlos0/env/env.go
generated
vendored
Normal file
398
vendor/github.com/caarlos0/env/env.go
generated
vendored
Normal file
@ -0,0 +1,398 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotAStructPtr is returned if you pass something that is not a pointer to a
|
||||
// Struct to Parse
|
||||
ErrNotAStructPtr = errors.New("Expected a pointer to a Struct")
|
||||
// ErrUnsupportedType if the struct field type is not supported by env
|
||||
ErrUnsupportedType = errors.New("Type is not supported")
|
||||
// ErrUnsupportedSliceType if the slice element type is not supported by env
|
||||
ErrUnsupportedSliceType = errors.New("Unsupported slice type")
|
||||
// OnEnvVarSet is an optional convenience callback, such as for logging purposes.
|
||||
// If not nil, it's called after successfully setting the given field from the given value.
|
||||
OnEnvVarSet func(reflect.StructField, string)
|
||||
// Friendly names for reflect types
|
||||
sliceOfInts = reflect.TypeOf([]int(nil))
|
||||
sliceOfInt64s = reflect.TypeOf([]int64(nil))
|
||||
sliceOfUint64s = reflect.TypeOf([]uint64(nil))
|
||||
sliceOfStrings = reflect.TypeOf([]string(nil))
|
||||
sliceOfBools = reflect.TypeOf([]bool(nil))
|
||||
sliceOfFloat32s = reflect.TypeOf([]float32(nil))
|
||||
sliceOfFloat64s = reflect.TypeOf([]float64(nil))
|
||||
sliceOfDurations = reflect.TypeOf([]time.Duration(nil))
|
||||
)
|
||||
|
||||
// CustomParsers is a friendly name for the type that `ParseWithFuncs()` accepts
|
||||
type CustomParsers map[reflect.Type]ParserFunc
|
||||
|
||||
// ParserFunc defines the signature of a function that can be used within `CustomParsers`
|
||||
type ParserFunc func(v string) (interface{}, error)
|
||||
|
||||
// Parse parses a struct containing `env` tags and loads its values from
|
||||
// environment variables.
|
||||
func Parse(v interface{}) error {
|
||||
ptrRef := reflect.ValueOf(v)
|
||||
if ptrRef.Kind() != reflect.Ptr {
|
||||
return ErrNotAStructPtr
|
||||
}
|
||||
ref := ptrRef.Elem()
|
||||
if ref.Kind() != reflect.Struct {
|
||||
return ErrNotAStructPtr
|
||||
}
|
||||
return doParse(ref, make(map[reflect.Type]ParserFunc, 0))
|
||||
}
|
||||
|
||||
// ParseWithFuncs is the same as `Parse` except it also allows the user to pass
|
||||
// in custom parsers.
|
||||
func ParseWithFuncs(v interface{}, funcMap CustomParsers) error {
|
||||
ptrRef := reflect.ValueOf(v)
|
||||
if ptrRef.Kind() != reflect.Ptr {
|
||||
return ErrNotAStructPtr
|
||||
}
|
||||
ref := ptrRef.Elem()
|
||||
if ref.Kind() != reflect.Struct {
|
||||
return ErrNotAStructPtr
|
||||
}
|
||||
return doParse(ref, funcMap)
|
||||
}
|
||||
|
||||
func doParse(ref reflect.Value, funcMap CustomParsers) error {
|
||||
refType := ref.Type()
|
||||
var errorList []string
|
||||
|
||||
for i := 0; i < refType.NumField(); i++ {
|
||||
refField := ref.Field(i)
|
||||
if reflect.Ptr == refField.Kind() && !refField.IsNil() && refField.CanSet() {
|
||||
err := Parse(refField.Interface())
|
||||
if nil != err {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
refTypeField := refType.Field(i)
|
||||
value, err := get(refTypeField)
|
||||
if err != nil {
|
||||
errorList = append(errorList, err.Error())
|
||||
continue
|
||||
}
|
||||
if value == "" {
|
||||
continue
|
||||
}
|
||||
if err := set(refField, refTypeField, value, funcMap); err != nil {
|
||||
errorList = append(errorList, err.Error())
|
||||
continue
|
||||
}
|
||||
if OnEnvVarSet != nil {
|
||||
OnEnvVarSet(refTypeField, value)
|
||||
}
|
||||
}
|
||||
if len(errorList) == 0 {
|
||||
return nil
|
||||
}
|
||||
return errors.New(strings.Join(errorList, ". "))
|
||||
}
|
||||
|
||||
func get(field reflect.StructField) (string, error) {
|
||||
var (
|
||||
val string
|
||||
err error
|
||||
)
|
||||
|
||||
key, opts := parseKeyForOption(field.Tag.Get("env"))
|
||||
|
||||
defaultValue := field.Tag.Get("envDefault")
|
||||
val = getOr(key, defaultValue)
|
||||
|
||||
if len(opts) > 0 {
|
||||
for _, opt := range opts {
|
||||
// The only option supported is "required".
|
||||
switch opt {
|
||||
case "":
|
||||
break
|
||||
case "required":
|
||||
val, err = getRequired(key)
|
||||
default:
|
||||
err = errors.New("Env tag option " + opt + " not supported.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return val, err
|
||||
}
|
||||
|
||||
// split the env tag's key into the expected key and desired option, if any.
|
||||
func parseKeyForOption(key string) (string, []string) {
|
||||
opts := strings.Split(key, ",")
|
||||
return opts[0], opts[1:]
|
||||
}
|
||||
|
||||
func getRequired(key string) (string, error) {
|
||||
if value, ok := os.LookupEnv(key); ok {
|
||||
return value, nil
|
||||
}
|
||||
// We do not use fmt.Errorf to avoid another import.
|
||||
return "", errors.New("Required environment variable " + key + " is not set")
|
||||
}
|
||||
|
||||
func getOr(key, defaultValue string) string {
|
||||
value, ok := os.LookupEnv(key)
|
||||
if ok {
|
||||
return value
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
func set(field reflect.Value, refType reflect.StructField, value string, funcMap CustomParsers) error {
|
||||
switch field.Kind() {
|
||||
case reflect.Slice:
|
||||
separator := refType.Tag.Get("envSeparator")
|
||||
return handleSlice(field, value, separator)
|
||||
case reflect.String:
|
||||
field.SetString(value)
|
||||
case reflect.Bool:
|
||||
bvalue, err := strconv.ParseBool(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetBool(bvalue)
|
||||
case reflect.Int:
|
||||
intValue, err := strconv.ParseInt(value, 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetInt(intValue)
|
||||
case reflect.Uint:
|
||||
uintValue, err := strconv.ParseUint(value, 10, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetUint(uintValue)
|
||||
case reflect.Float32:
|
||||
v, err := strconv.ParseFloat(value, 32)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetFloat(v)
|
||||
case reflect.Float64:
|
||||
v, err := strconv.ParseFloat(value, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.Set(reflect.ValueOf(v))
|
||||
case reflect.Int64:
|
||||
if refType.Type.String() == "time.Duration" {
|
||||
dValue, err := time.ParseDuration(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.Set(reflect.ValueOf(dValue))
|
||||
} else {
|
||||
intValue, err := strconv.ParseInt(value, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetInt(intValue)
|
||||
}
|
||||
case reflect.Uint64:
|
||||
uintValue, err := strconv.ParseUint(value, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.SetUint(uintValue)
|
||||
case reflect.Struct:
|
||||
return handleStruct(field, refType, value, funcMap)
|
||||
default:
|
||||
parserFunc, ok := funcMap[refType.Type]
|
||||
if !ok {
|
||||
return ErrUnsupportedType
|
||||
}
|
||||
val, err := parserFunc(value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.Set(reflect.ValueOf(val))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleStruct(field reflect.Value, refType reflect.StructField, value string, funcMap CustomParsers) error {
|
||||
// Does the custom parser func map contain this type?
|
||||
parserFunc, ok := funcMap[field.Type()]
|
||||
if !ok {
|
||||
// Map does not contain a custom parser for this type
|
||||
return ErrUnsupportedType
|
||||
}
|
||||
|
||||
// Call on the custom parser func
|
||||
data, err := parserFunc(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Custom parser error: %v", err)
|
||||
}
|
||||
|
||||
// Set the field to the data returned by the customer parser func
|
||||
rv := reflect.ValueOf(data)
|
||||
field.Set(rv)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleSlice(field reflect.Value, value, separator string) error {
|
||||
if separator == "" {
|
||||
separator = ","
|
||||
}
|
||||
|
||||
splitData := strings.Split(value, separator)
|
||||
|
||||
switch field.Type() {
|
||||
case sliceOfStrings:
|
||||
field.Set(reflect.ValueOf(splitData))
|
||||
case sliceOfInts:
|
||||
intData, err := parseInts(splitData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.Set(reflect.ValueOf(intData))
|
||||
case sliceOfInt64s:
|
||||
int64Data, err := parseInt64s(splitData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.Set(reflect.ValueOf(int64Data))
|
||||
case sliceOfUint64s:
|
||||
uint64Data, err := parseUint64s(splitData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.Set(reflect.ValueOf(uint64Data))
|
||||
case sliceOfFloat32s:
|
||||
data, err := parseFloat32s(splitData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.Set(reflect.ValueOf(data))
|
||||
case sliceOfFloat64s:
|
||||
data, err := parseFloat64s(splitData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.Set(reflect.ValueOf(data))
|
||||
case sliceOfBools:
|
||||
boolData, err := parseBools(splitData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.Set(reflect.ValueOf(boolData))
|
||||
case sliceOfDurations:
|
||||
durationData, err := parseDurations(splitData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
field.Set(reflect.ValueOf(durationData))
|
||||
default:
|
||||
return ErrUnsupportedSliceType
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseInts(data []string) ([]int, error) {
|
||||
intSlice := make([]int, 0, len(data))
|
||||
|
||||
for _, v := range data {
|
||||
intValue, err := strconv.ParseInt(v, 10, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
intSlice = append(intSlice, int(intValue))
|
||||
}
|
||||
return intSlice, nil
|
||||
}
|
||||
|
||||
func parseInt64s(data []string) ([]int64, error) {
|
||||
intSlice := make([]int64, 0, len(data))
|
||||
|
||||
for _, v := range data {
|
||||
intValue, err := strconv.ParseInt(v, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
intSlice = append(intSlice, int64(intValue))
|
||||
}
|
||||
return intSlice, nil
|
||||
}
|
||||
|
||||
func parseUint64s(data []string) ([]uint64, error) {
|
||||
var uintSlice []uint64
|
||||
|
||||
for _, v := range data {
|
||||
uintValue, err := strconv.ParseUint(v, 10, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uintSlice = append(uintSlice, uint64(uintValue))
|
||||
}
|
||||
return uintSlice, nil
|
||||
}
|
||||
|
||||
func parseFloat32s(data []string) ([]float32, error) {
|
||||
float32Slice := make([]float32, 0, len(data))
|
||||
|
||||
for _, v := range data {
|
||||
data, err := strconv.ParseFloat(v, 32)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
float32Slice = append(float32Slice, float32(data))
|
||||
}
|
||||
return float32Slice, nil
|
||||
}
|
||||
|
||||
func parseFloat64s(data []string) ([]float64, error) {
|
||||
float64Slice := make([]float64, 0, len(data))
|
||||
|
||||
for _, v := range data {
|
||||
data, err := strconv.ParseFloat(v, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
float64Slice = append(float64Slice, float64(data))
|
||||
}
|
||||
return float64Slice, nil
|
||||
}
|
||||
|
||||
func parseBools(data []string) ([]bool, error) {
|
||||
boolSlice := make([]bool, 0, len(data))
|
||||
|
||||
for _, v := range data {
|
||||
bvalue, err := strconv.ParseBool(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
boolSlice = append(boolSlice, bvalue)
|
||||
}
|
||||
return boolSlice, nil
|
||||
}
|
||||
|
||||
func parseDurations(data []string) ([]time.Duration, error) {
|
||||
durationSlice := make([]time.Duration, 0, len(data))
|
||||
|
||||
for _, v := range data {
|
||||
dvalue, err := time.ParseDuration(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
durationSlice = append(durationSlice, dvalue)
|
||||
}
|
||||
return durationSlice, nil
|
||||
}
|
550
vendor/github.com/caarlos0/env/env_test.go
generated
vendored
Normal file
550
vendor/github.com/caarlos0/env/env_test.go
generated
vendored
Normal file
@ -0,0 +1,550 @@
|
||||
package env_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/caarlos0/env"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Some string `env:"somevar"`
|
||||
Other bool `env:"othervar"`
|
||||
Port int `env:"PORT"`
|
||||
Int64Val int64 `env:"INT64VAL"`
|
||||
UintVal uint `env:"UINTVAL"`
|
||||
Uint64Val uint64 `env:"UINT64VAL"`
|
||||
NotAnEnv string
|
||||
DatabaseURL string `env:"DATABASE_URL" envDefault:"postgres://localhost:5432/db"`
|
||||
Strings []string `env:"STRINGS"`
|
||||
SepStrings []string `env:"SEPSTRINGS" envSeparator:":"`
|
||||
Numbers []int `env:"NUMBERS"`
|
||||
Numbers64 []int64 `env:"NUMBERS64"`
|
||||
UNumbers64 []uint64 `env:"UNUMBERS64"`
|
||||
Bools []bool `env:"BOOLS"`
|
||||
Duration time.Duration `env:"DURATION"`
|
||||
Float32 float32 `env:"FLOAT32"`
|
||||
Float64 float64 `env:"FLOAT64"`
|
||||
Float32s []float32 `env:"FLOAT32S"`
|
||||
Float64s []float64 `env:"FLOAT64S"`
|
||||
Durations []time.Duration `env:"DURATIONS"`
|
||||
}
|
||||
|
||||
type ParentStruct struct {
|
||||
InnerStruct *InnerStruct
|
||||
unexported *InnerStruct
|
||||
Ignored *http.Client
|
||||
}
|
||||
|
||||
type InnerStruct struct {
|
||||
Inner string `env:"innervar"`
|
||||
Number uint `env:"innernum"`
|
||||
}
|
||||
|
||||
func TestParsesEnv(t *testing.T) {
|
||||
os.Setenv("somevar", "somevalue")
|
||||
os.Setenv("othervar", "true")
|
||||
os.Setenv("PORT", "8080")
|
||||
os.Setenv("STRINGS", "string1,string2,string3")
|
||||
os.Setenv("SEPSTRINGS", "string1:string2:string3")
|
||||
os.Setenv("NUMBERS", "1,2,3,4")
|
||||
os.Setenv("NUMBERS64", "1,2,2147483640,-2147483640")
|
||||
os.Setenv("UNUMBERS64", "1,2,214748364011,9147483641")
|
||||
os.Setenv("BOOLS", "t,TRUE,0,1")
|
||||
os.Setenv("DURATION", "1s")
|
||||
os.Setenv("FLOAT32", "3.40282346638528859811704183484516925440e+38")
|
||||
os.Setenv("FLOAT64", "1.797693134862315708145274237317043567981e+308")
|
||||
os.Setenv("FLOAT32S", "1.0,2.0,3.0")
|
||||
os.Setenv("FLOAT64S", "1.0,2.0,3.0")
|
||||
os.Setenv("UINTVAL", "44")
|
||||
os.Setenv("UINT64VAL", "6464")
|
||||
os.Setenv("INT64VAL", "-7575")
|
||||
os.Setenv("DURATIONS", "1s,2s,3s")
|
||||
|
||||
defer os.Clearenv()
|
||||
|
||||
cfg := Config{}
|
||||
assert.NoError(t, env.Parse(&cfg))
|
||||
assert.Equal(t, "somevalue", cfg.Some)
|
||||
assert.Equal(t, true, cfg.Other)
|
||||
assert.Equal(t, 8080, cfg.Port)
|
||||
assert.Equal(t, uint(44), cfg.UintVal)
|
||||
assert.Equal(t, int64(-7575), cfg.Int64Val)
|
||||
assert.Equal(t, uint64(6464), cfg.Uint64Val)
|
||||
assert.Equal(t, []string{"string1", "string2", "string3"}, cfg.Strings)
|
||||
assert.Equal(t, []string{"string1", "string2", "string3"}, cfg.SepStrings)
|
||||
assert.Equal(t, []int{1, 2, 3, 4}, cfg.Numbers)
|
||||
assert.Equal(t, []int64{1, 2, 2147483640, -2147483640}, cfg.Numbers64)
|
||||
assert.Equal(t, []uint64{1, 2, 214748364011, 9147483641}, cfg.UNumbers64)
|
||||
assert.Equal(t, []bool{true, true, false, true}, cfg.Bools)
|
||||
d1, _ := time.ParseDuration("1s")
|
||||
assert.Equal(t, d1, cfg.Duration)
|
||||
f32 := float32(3.40282346638528859811704183484516925440e+38)
|
||||
assert.Equal(t, f32, cfg.Float32)
|
||||
f64 := float64(1.797693134862315708145274237317043567981e+308)
|
||||
assert.Equal(t, f64, cfg.Float64)
|
||||
assert.Equal(t, []float32{float32(1.0), float32(2.0), float32(3.0)}, cfg.Float32s)
|
||||
assert.Equal(t, []float64{float64(1.0), float64(2.0), float64(3.0)}, cfg.Float64s)
|
||||
d2, _ := time.ParseDuration("2s")
|
||||
d3, _ := time.ParseDuration("3s")
|
||||
assert.Equal(t, []time.Duration{d1, d2, d3}, cfg.Durations)
|
||||
}
|
||||
|
||||
func TestParsesEnvInner(t *testing.T) {
|
||||
os.Setenv("innervar", "someinnervalue")
|
||||
defer os.Clearenv()
|
||||
cfg := ParentStruct{
|
||||
InnerStruct: &InnerStruct{},
|
||||
unexported: &InnerStruct{},
|
||||
}
|
||||
assert.NoError(t, env.Parse(&cfg))
|
||||
assert.Equal(t, "someinnervalue", cfg.InnerStruct.Inner)
|
||||
}
|
||||
|
||||
func TestParsesEnvInnerNil(t *testing.T) {
|
||||
os.Setenv("innervar", "someinnervalue")
|
||||
defer os.Clearenv()
|
||||
cfg := ParentStruct{}
|
||||
assert.NoError(t, env.Parse(&cfg))
|
||||
}
|
||||
|
||||
func TestParsesEnvInnerInvalid(t *testing.T) {
|
||||
os.Setenv("innernum", "-547")
|
||||
defer os.Clearenv()
|
||||
cfg := ParentStruct{
|
||||
InnerStruct: &InnerStruct{},
|
||||
}
|
||||
assert.Error(t, env.Parse(&cfg))
|
||||
}
|
||||
|
||||
func TestEmptyVars(t *testing.T) {
|
||||
cfg := Config{}
|
||||
assert.NoError(t, env.Parse(&cfg))
|
||||
assert.Equal(t, "", cfg.Some)
|
||||
assert.Equal(t, false, cfg.Other)
|
||||
assert.Equal(t, 0, cfg.Port)
|
||||
assert.Equal(t, uint(0), cfg.UintVal)
|
||||
assert.Equal(t, uint64(0), cfg.Uint64Val)
|
||||
assert.Equal(t, int64(0), cfg.Int64Val)
|
||||
assert.Equal(t, 0, len(cfg.Strings))
|
||||
assert.Equal(t, 0, len(cfg.SepStrings))
|
||||
assert.Equal(t, 0, len(cfg.Numbers))
|
||||
assert.Equal(t, 0, len(cfg.Bools))
|
||||
}
|
||||
|
||||
func TestPassAnInvalidPtr(t *testing.T) {
|
||||
var thisShouldBreak int
|
||||
assert.Error(t, env.Parse(&thisShouldBreak))
|
||||
}
|
||||
|
||||
func TestPassReference(t *testing.T) {
|
||||
cfg := Config{}
|
||||
assert.Error(t, env.Parse(cfg))
|
||||
}
|
||||
|
||||
func TestInvalidBool(t *testing.T) {
|
||||
os.Setenv("othervar", "should-be-a-bool")
|
||||
defer os.Clearenv()
|
||||
|
||||
cfg := Config{}
|
||||
assert.Error(t, env.Parse(&cfg))
|
||||
}
|
||||
|
||||
func TestInvalidInt(t *testing.T) {
|
||||
os.Setenv("PORT", "should-be-an-int")
|
||||
defer os.Clearenv()
|
||||
|
||||
cfg := Config{}
|
||||
assert.Error(t, env.Parse(&cfg))
|
||||
}
|
||||
|
||||
func TestInvalidUint(t *testing.T) {
|
||||
os.Setenv("UINTVAL", "-44")
|
||||
defer os.Clearenv()
|
||||
|
||||
cfg := Config{}
|
||||
assert.Error(t, env.Parse(&cfg))
|
||||
}
|
||||
|
||||
func TestInvalidFloat32(t *testing.T) {
|
||||
os.Setenv("FLOAT32", "AAA")
|
||||
defer os.Clearenv()
|
||||
|
||||
cfg := Config{}
|
||||
assert.Error(t, env.Parse(&cfg))
|
||||
}
|
||||
|
||||
func TestInvalidFloat64(t *testing.T) {
|
||||
os.Setenv("FLOAT64", "AAA")
|
||||
defer os.Clearenv()
|
||||
|
||||
cfg := Config{}
|
||||
assert.Error(t, env.Parse(&cfg))
|
||||
}
|
||||
|
||||
func TestInvalidUint64(t *testing.T) {
|
||||
os.Setenv("UINT64VAL", "AAA")
|
||||
defer os.Clearenv()
|
||||
|
||||
cfg := Config{}
|
||||
assert.Error(t, env.Parse(&cfg))
|
||||
}
|
||||
|
||||
func TestInvalidInt64(t *testing.T) {
|
||||
os.Setenv("INT64VAL", "AAA")
|
||||
defer os.Clearenv()
|
||||
|
||||
cfg := Config{}
|
||||
assert.Error(t, env.Parse(&cfg))
|
||||
}
|
||||
|
||||
func TestInvalidInt64Slice(t *testing.T) {
|
||||
type config struct {
|
||||
BadFloats []int64 `env:"BADINTS"`
|
||||
}
|
||||
|
||||
os.Setenv("BADINTS", "A,2,3")
|
||||
cfg := &config{}
|
||||
assert.Error(t, env.Parse(cfg))
|
||||
}
|
||||
|
||||
func TestInvalidUInt64Slice(t *testing.T) {
|
||||
type config struct {
|
||||
BadFloats []uint64 `env:"BADINTS"`
|
||||
}
|
||||
|
||||
os.Setenv("BADFLOATS", "A,2,3")
|
||||
cfg := &config{}
|
||||
assert.Error(t, env.Parse(cfg))
|
||||
}
|
||||
|
||||
func TestInvalidFloat32Slice(t *testing.T) {
|
||||
type config struct {
|
||||
BadFloats []float32 `env:"BADFLOATS"`
|
||||
}
|
||||
|
||||
os.Setenv("BADFLOATS", "A,2.0,3.0")
|
||||
cfg := &config{}
|
||||
assert.Error(t, env.Parse(cfg))
|
||||
}
|
||||
|
||||
func TestInvalidFloat64Slice(t *testing.T) {
|
||||
type config struct {
|
||||
BadFloats []float64 `env:"BADFLOATS"`
|
||||
}
|
||||
|
||||
os.Setenv("BADFLOATS", "A,2.0,3.0")
|
||||
cfg := &config{}
|
||||
assert.Error(t, env.Parse(cfg))
|
||||
}
|
||||
|
||||
func TestInvalidBoolsSlice(t *testing.T) {
|
||||
type config struct {
|
||||
BadBools []bool `env:"BADBOOLS"`
|
||||
}
|
||||
|
||||
os.Setenv("BADBOOLS", "t,f,TRUE,faaaalse")
|
||||
cfg := &config{}
|
||||
assert.Error(t, env.Parse(cfg))
|
||||
}
|
||||
|
||||
func TestInvalidDuration(t *testing.T) {
|
||||
os.Setenv("DURATION", "should-be-a-valid-duration")
|
||||
defer os.Clearenv()
|
||||
|
||||
cfg := Config{}
|
||||
assert.Error(t, env.Parse(&cfg))
|
||||
}
|
||||
|
||||
func TestInvalidDurations(t *testing.T) {
|
||||
os.Setenv("DURATIONS", "1s,contains-an-invalid-duration,3s")
|
||||
defer os.Clearenv()
|
||||
|
||||
cfg := Config{}
|
||||
assert.Error(t, env.Parse(&cfg))
|
||||
}
|
||||
|
||||
func TestParsesDefaultConfig(t *testing.T) {
|
||||
cfg := Config{}
|
||||
assert.NoError(t, env.Parse(&cfg))
|
||||
assert.Equal(t, "postgres://localhost:5432/db", cfg.DatabaseURL)
|
||||
}
|
||||
|
||||
func TestParseStructWithoutEnvTag(t *testing.T) {
|
||||
cfg := Config{}
|
||||
assert.NoError(t, env.Parse(&cfg))
|
||||
assert.Empty(t, cfg.NotAnEnv)
|
||||
}
|
||||
|
||||
func TestParseStructWithInvalidFieldKind(t *testing.T) {
|
||||
type config struct {
|
||||
WontWorkByte byte `env:"BLAH"`
|
||||
}
|
||||
os.Setenv("BLAH", "a")
|
||||
cfg := config{}
|
||||
assert.Error(t, env.Parse(&cfg))
|
||||
}
|
||||
|
||||
func TestUnsupportedSliceType(t *testing.T) {
|
||||
type config struct {
|
||||
WontWork []map[int]int `env:"WONTWORK"`
|
||||
}
|
||||
|
||||
os.Setenv("WONTWORK", "1,2,3")
|
||||
defer os.Clearenv()
|
||||
|
||||
cfg := &config{}
|
||||
assert.Error(t, env.Parse(cfg))
|
||||
}
|
||||
|
||||
func TestBadSeparator(t *testing.T) {
|
||||
type config struct {
|
||||
WontWork []int `env:"WONTWORK" envSeparator:":"`
|
||||
}
|
||||
|
||||
cfg := &config{}
|
||||
os.Setenv("WONTWORK", "1,2,3,4")
|
||||
defer os.Clearenv()
|
||||
|
||||
assert.Error(t, env.Parse(cfg))
|
||||
}
|
||||
|
||||
func TestNoErrorRequiredSet(t *testing.T) {
|
||||
type config struct {
|
||||
IsRequired string `env:"IS_REQUIRED,required"`
|
||||
}
|
||||
|
||||
cfg := &config{}
|
||||
|
||||
os.Setenv("IS_REQUIRED", "val")
|
||||
defer os.Clearenv()
|
||||
assert.NoError(t, env.Parse(cfg))
|
||||
assert.Equal(t, "val", cfg.IsRequired)
|
||||
}
|
||||
|
||||
func TestErrorRequiredNotSet(t *testing.T) {
|
||||
type config struct {
|
||||
IsRequired string `env:"IS_REQUIRED,required"`
|
||||
}
|
||||
|
||||
cfg := &config{}
|
||||
assert.Error(t, env.Parse(cfg))
|
||||
}
|
||||
|
||||
func TestCustomParser(t *testing.T) {
|
||||
type foo struct {
|
||||
name string
|
||||
}
|
||||
|
||||
type config struct {
|
||||
Var foo `env:"VAR"`
|
||||
}
|
||||
|
||||
os.Setenv("VAR", "test")
|
||||
|
||||
customParserFunc := func(v string) (interface{}, error) {
|
||||
return foo{name: v}, nil
|
||||
}
|
||||
|
||||
cfg := &config{}
|
||||
err := env.ParseWithFuncs(cfg, map[reflect.Type]env.ParserFunc{
|
||||
reflect.TypeOf(foo{}): customParserFunc,
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, cfg.Var.name, "test")
|
||||
}
|
||||
|
||||
func TestParseWithFuncsNoPtr(t *testing.T) {
|
||||
type foo struct{}
|
||||
err := env.ParseWithFuncs(foo{}, nil)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, err, env.ErrNotAStructPtr)
|
||||
}
|
||||
|
||||
func TestParseWithFuncsInvalidType(t *testing.T) {
|
||||
var c int
|
||||
err := env.ParseWithFuncs(&c, nil)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, err, env.ErrNotAStructPtr)
|
||||
}
|
||||
|
||||
func TestCustomParserError(t *testing.T) {
|
||||
type foo struct {
|
||||
name string
|
||||
}
|
||||
|
||||
type config struct {
|
||||
Var foo `env:"VAR"`
|
||||
}
|
||||
|
||||
os.Setenv("VAR", "test")
|
||||
|
||||
customParserFunc := func(v string) (interface{}, error) {
|
||||
return nil, errors.New("something broke")
|
||||
}
|
||||
|
||||
cfg := &config{}
|
||||
err := env.ParseWithFuncs(cfg, map[reflect.Type]env.ParserFunc{
|
||||
reflect.TypeOf(foo{}): customParserFunc,
|
||||
})
|
||||
|
||||
assert.Empty(t, cfg.Var.name, "Var.name should not be filled out when parse errors")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, err.Error(), "Custom parser error: something broke")
|
||||
}
|
||||
|
||||
func TestCustomParserBasicType(t *testing.T) {
|
||||
type ConstT int32
|
||||
|
||||
type config struct {
|
||||
Const ConstT `env:"CONST_VAL"`
|
||||
}
|
||||
|
||||
exp := ConstT(123)
|
||||
os.Setenv("CONST_VAL", fmt.Sprintf("%d", exp))
|
||||
|
||||
customParserFunc := func(v string) (interface{}, error) {
|
||||
i, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r := ConstT(i)
|
||||
return r, nil
|
||||
}
|
||||
|
||||
cfg := &config{}
|
||||
err := env.ParseWithFuncs(cfg, map[reflect.Type]env.ParserFunc{
|
||||
reflect.TypeOf(ConstT(0)): customParserFunc,
|
||||
})
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, exp, cfg.Const)
|
||||
}
|
||||
|
||||
func TypeCustomParserBasicInvalid(t *testing.T) {
|
||||
type ConstT int32
|
||||
|
||||
type config struct {
|
||||
Const ConstT `env:"CONST_VAL"`
|
||||
}
|
||||
|
||||
os.Setenv("CONST_VAL", "foobar")
|
||||
|
||||
expErr := errors.New("Random error")
|
||||
customParserFunc := func(_ string) (interface{}, error) {
|
||||
return nil, expErr
|
||||
}
|
||||
|
||||
cfg := &config{}
|
||||
err := env.ParseWithFuncs(cfg, map[reflect.Type]env.ParserFunc{
|
||||
reflect.TypeOf(ConstT(0)): customParserFunc,
|
||||
})
|
||||
|
||||
assert.Empty(t, cfg.Const)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, expErr, err)
|
||||
}
|
||||
|
||||
func TestCustomParserBasicUnsupported(t *testing.T) {
|
||||
type ConstT int32
|
||||
|
||||
type config struct {
|
||||
Const ConstT `env:"CONST_VAL"`
|
||||
}
|
||||
|
||||
exp := ConstT(123)
|
||||
os.Setenv("CONST_VAL", fmt.Sprintf("%d", exp))
|
||||
|
||||
cfg := &config{}
|
||||
err := env.Parse(cfg)
|
||||
|
||||
assert.Zero(t, cfg.Const)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, env.ErrUnsupportedType, err)
|
||||
}
|
||||
|
||||
func TestUnsupportedStructType(t *testing.T) {
|
||||
type config struct {
|
||||
Foo http.Client `env:"FOO"`
|
||||
}
|
||||
|
||||
os.Setenv("FOO", "foo")
|
||||
|
||||
cfg := &config{}
|
||||
err := env.Parse(cfg)
|
||||
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, env.ErrUnsupportedType, err)
|
||||
}
|
||||
|
||||
func TestEmptyOption(t *testing.T) {
|
||||
type config struct {
|
||||
Var string `env:"VAR,"`
|
||||
}
|
||||
|
||||
cfg := &config{}
|
||||
|
||||
os.Setenv("VAR", "val")
|
||||
defer os.Clearenv()
|
||||
assert.NoError(t, env.Parse(cfg))
|
||||
assert.Equal(t, "val", cfg.Var)
|
||||
}
|
||||
|
||||
func TestErrorOptionNotRecognized(t *testing.T) {
|
||||
type config struct {
|
||||
Var string `env:"VAR,not_supported!"`
|
||||
}
|
||||
|
||||
cfg := &config{}
|
||||
assert.Error(t, env.Parse(cfg))
|
||||
|
||||
}
|
||||
|
||||
func ExampleParse() {
|
||||
type config struct {
|
||||
Home string `env:"HOME"`
|
||||
Port int `env:"PORT" envDefault:"3000"`
|
||||
IsProduction bool `env:"PRODUCTION"`
|
||||
}
|
||||
os.Setenv("HOME", "/tmp/fakehome")
|
||||
cfg := config{}
|
||||
env.Parse(&cfg)
|
||||
fmt.Println(cfg)
|
||||
// Output: {/tmp/fakehome 3000 false}
|
||||
}
|
||||
|
||||
func ExampleParseRequiredField() {
|
||||
type config struct {
|
||||
Home string `env:"HOME"`
|
||||
Port int `env:"PORT" envDefault:"3000"`
|
||||
IsProduction bool `env:"PRODUCTION"`
|
||||
SecretKey string `env:"SECRET_KEY,required"`
|
||||
}
|
||||
os.Setenv("HOME", "/tmp/fakehome")
|
||||
cfg := config{}
|
||||
err := env.Parse(&cfg)
|
||||
fmt.Println(err)
|
||||
// Output: Required environment variable SECRET_KEY is not set
|
||||
}
|
||||
|
||||
func ExampleParseMultipleOptions() {
|
||||
type config struct {
|
||||
Home string `env:"HOME"`
|
||||
Port int `env:"PORT" envDefault:"3000"`
|
||||
IsProduction bool `env:"PRODUCTION"`
|
||||
SecretKey string `env:"SECRET_KEY,required,option1"`
|
||||
}
|
||||
os.Setenv("HOME", "/tmp/fakehome")
|
||||
cfg := config{}
|
||||
err := env.Parse(&cfg)
|
||||
fmt.Println(err)
|
||||
// Output: Env tag option option1 not supported.
|
||||
}
|
48
vendor/github.com/caarlos0/env/examples/first.go
generated
vendored
Normal file
48
vendor/github.com/caarlos0/env/examples/first.go
generated
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/caarlos0/env"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
Home string `env:"HOME"`
|
||||
Port int `env:"PORT" envDefault:"3000"`
|
||||
IsProduction bool `env:"PRODUCTION"`
|
||||
Hosts []string `env:"HOSTS" envSeparator:":"`
|
||||
Duration time.Duration `env:"DURATION"`
|
||||
ExampleFoo Foo `env:"EXAMPLE_FOO"`
|
||||
}
|
||||
|
||||
type Foo struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg := config{}
|
||||
|
||||
// Parse for built-in types
|
||||
if err := env.Parse(&cfg); err != nil {
|
||||
log.Fatal("Unable to parse envs: ", err)
|
||||
}
|
||||
|
||||
// OR w/ a custom parser for `Foo`
|
||||
//
|
||||
// if err := env.ParseWithFuncs(&cfg, env.CustomParsers{
|
||||
// reflect.TypeOf(Foo{}): fooParser,
|
||||
// }); err != nil {
|
||||
// log.Fatal("Unable to parse envs: ", err)
|
||||
// }
|
||||
|
||||
fmt.Printf("%+v\n", cfg)
|
||||
}
|
||||
|
||||
func fooParser(value string) (interface{}, error) {
|
||||
return Foo{
|
||||
Name: strings.ToUpper(value),
|
||||
}, nil
|
||||
}
|
35
vendor/github.com/caarlos0/env/parsers/README.md
generated
vendored
Normal file
35
vendor/github.com/caarlos0/env/parsers/README.md
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
parsers
|
||||
=======
|
||||
This directory contains pre-built, custom parsers that can be used with `env.ParseWithFuncs`
|
||||
to facilitate the parsing of envs that are not basic types.
|
||||
|
||||
Example Usage:
|
||||
|
||||
```golang
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
|
||||
"github.com/caarlos0/env"
|
||||
"github.com/caarlos0/env/parsers"
|
||||
)
|
||||
|
||||
type config struct {
|
||||
ExampleURL url.URL `env:"EXAMPLE_URL" envDefault:"https://google.com"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
cfg := config{}
|
||||
|
||||
if err := env.ParseWithFuncs(&cfg, env.CustomParsers{
|
||||
parsers.URLType: parsers.URLFunc,
|
||||
}); err != nil {
|
||||
log.Fatal("Unable to parse envs: ", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Scheme: %v Host: %v\n", cfg.ExampleURL.Scheme, cfg.ExampleURL.Host)
|
||||
}
|
||||
```
|
23
vendor/github.com/caarlos0/env/parsers/parsers.go
generated
vendored
Normal file
23
vendor/github.com/caarlos0/env/parsers/parsers.go
generated
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
// Package parsers contains custom parser funcs for common, non-built-in types
|
||||
package parsers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var (
|
||||
// URLType is a helper var that represents the `reflect.Type`` of `url.URL`
|
||||
URLType = reflect.TypeOf(url.URL{})
|
||||
)
|
||||
|
||||
// URLFunc is a basic parser for the url.URL type that should be used with `env.ParseWithFuncs()`
|
||||
func URLFunc(v string) (interface{}, error) {
|
||||
u, err := url.Parse(v)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to complete URL parse: %v", err)
|
||||
}
|
||||
|
||||
return *u, nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user