Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Define a struct with `env` struct tags:
```go
type Config struct {
Hostname string `env:"SERVER_HOSTNAME,default=localhost"`
Port uint16 `env:"SERVER_PORT,default=8080"`
Port uint16 `env:"HTTP_PORT;SERVER_PORT,default=8080"`

AWS struct {
ID string `env:"AWS_ACCESS_KEY_ID"`
Expand All @@ -30,8 +30,8 @@ type Config struct {
}
```

Fields *must be exported* (i.e. begin with a capital letter) in order
for `envdecode` to work with them. An error will be returned if a
Fields _must be exported_ (i.e. begin with a capital letter) in order
for `envdecode` to work with them. An error will be returned if a
struct with no exported fields is decoded (including one that contains
no `env` tags at all).
Default values may be provided by appending ",default=value" to the
Expand All @@ -57,16 +57,16 @@ All parse errors will fail fast and return an error in this mode.

## Supported types

* Structs (and pointer to structs)
* Slices of below defined types, separated by semicolon
* `bool`
* `float32`, `float64`
* `int`, `int8`, `int16`, `int32`, `int64`
* `uint`, `uint8`, `uint16`, `uint32`, `uint64`
* `string`
* `time.Duration`, using the [`time.ParseDuration()` format](http://golang.org/pkg/time/#ParseDuration)
* `*url.URL`, using [`url.Parse()`](https://godoc.org/net/url#Parse)
* Types those implement a `Decoder` interface
- Structs (and pointer to structs)
- Slices of below defined types, separated by semicolon
- `bool`
- `float32`, `float64`
- `int`, `int8`, `int16`, `int32`, `int64`
- `uint`, `uint8`, `uint16`, `uint32`, `uint64`
- `string`
- `time.Duration`, using the [`time.ParseDuration()` format](http://golang.org/pkg/time/#ParseDuration)
- `*url.URL`, using [`url.Parse()`](https://godoc.org/net/url#Parse)
- Types those implement a `Decoder` interface

## Custom `Decoder`

Expand Down
10 changes: 9 additions & 1 deletion envdecode.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,15 @@ func decode(target interface{}, strict bool) (int, error) {
}

parts := strings.Split(tag, ",")
env := os.Getenv(parts[0])
overrides := strings.Split(parts[0], `;`)

var env string
for _, override := range overrides {
v := os.Getenv(override)
if v != "" {
env = v
}
}

required := false
hasDefault := false
Expand Down
38 changes: 38 additions & 0 deletions envdecode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ type testConfigRequiredDefault struct {
RequiredDefault string `env:"TEST_REQUIRED_DEFAULT,required,default=test"`
}

type testConfigOverride struct {
OverrideString string `env:"TEST_OVERRIDE_A;TEST_OVERRIDE_B,default=override_default"`
}

type testNoExportedFields struct {
aString string `env:"TEST_STRING"`
anInt64 int64 `env:"TEST_INT64"`
Expand Down Expand Up @@ -318,6 +322,40 @@ func TestDecode(t *testing.T) {
if err != nil {
t.Fatal(err)
}

var tco testConfigOverride
err = Decode(&tco)
if err != nil {
t.Fatal(err)
}

if tco.OverrideString != "override_default" {
t.Fatalf(`Expected "override_default" but got %s`, tco.OverrideString)
}

os.Setenv("TEST_OVERRIDE_A", "override_a")

tco = testConfigOverride{}
err = Decode(&tco)
if err != nil {
t.Fatal(err)
}

if tco.OverrideString != "override_a" {
t.Fatalf(`Expected "override_a" but got %s`, tco.OverrideString)
}

os.Setenv("TEST_OVERRIDE_B", "override_b")

tco = testConfigOverride{}
err = Decode(&tco)
if err != nil {
t.Fatal(err)
}

if tco.OverrideString != "override_b" {
t.Fatalf(`Expected "override_b" but got %s`, tco.OverrideString)
}
}

func TestDecodeErrors(t *testing.T) {
Expand Down