Skip to content

Commit

Permalink
Merge pull request #65 from illia-v/env_multiple_values
Browse files Browse the repository at this point in the history
Fix providing multiple values via environment variables
  • Loading branch information
alexflint authored May 16, 2018
2 parents 074ee5f + 89714b6 commit f7c0423
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 3 deletions.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,21 @@ $ NUM_WORKERS=4 ./example
Workers: 4
```

You can provide multiple values using the CSV (RFC 4180) format:

```go
var args struct {
Workers []int `arg:"env"`
}
arg.MustParse(&args)
fmt.Println("Workers:", args.Workers)
```

```
$ WORKERS='1,99' ./example
Workers: [1 99]
```

### Usage strings
```go
var args struct {
Expand Down
26 changes: 23 additions & 3 deletions parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package arg

import (
"encoding"
"encoding/csv"
"errors"
"fmt"
"os"
Expand Down Expand Up @@ -275,9 +276,28 @@ func process(specs []*spec, args []string) error {
}
if spec.env != "" {
if value, found := os.LookupEnv(spec.env); found {
err := scalar.ParseValue(spec.dest, value)
if err != nil {
return fmt.Errorf("error processing environment variable %s: %v", spec.env, err)
if spec.multiple {
// expect a CSV string in an environment
// variable in the case of multiple values
values, err := csv.NewReader(strings.NewReader(value)).Read()
if err != nil {
return fmt.Errorf(
"error reading a CSV string from environment variable %s with multiple values: %v",
spec.env,
err,
)
}
if err = setSlice(spec.dest, values, !spec.separate); err != nil {
return fmt.Errorf(
"error processing environment variable %s with multiple values: %v",
spec.env,
err,
)
}
} else {
if err := scalar.ParseValue(spec.dest, value); err != nil {
return fmt.Errorf("error processing environment variable %s: %v", spec.env, err)
}
}
spec.wasPresent = true
}
Expand Down
54 changes: 54 additions & 0 deletions parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,60 @@ func TestEnvironmentVariableRequired(t *testing.T) {
assert.Equal(t, "bar", args.Foo)
}

func TestEnvironmentVariableSliceArgumentString(t *testing.T) {
var args struct {
Foo []string `arg:"env"`
}
setenv(t, "FOO", "bar,\"baz, qux\"")
MustParse(&args)
assert.Equal(t, []string{"bar", "baz, qux"}, args.Foo)
}

func TestEnvironmentVariableSliceArgumentInteger(t *testing.T) {
var args struct {
Foo []int `arg:"env"`
}
setenv(t, "FOO", "1,99")
MustParse(&args)
assert.Equal(t, []int{1, 99}, args.Foo)
}

func TestEnvironmentVariableSliceArgumentFloat(t *testing.T) {
var args struct {
Foo []float32 `arg:"env"`
}
setenv(t, "FOO", "1.1,99.9")
MustParse(&args)
assert.Equal(t, []float32{1.1, 99.9}, args.Foo)
}

func TestEnvironmentVariableSliceArgumentBool(t *testing.T) {
var args struct {
Foo []bool `arg:"env"`
}
setenv(t, "FOO", "true,false,0,1")
MustParse(&args)
assert.Equal(t, []bool{true, false, false, true}, args.Foo)
}

func TestEnvironmentVariableSliceArgumentWrongCsv(t *testing.T) {
var args struct {
Foo []int `arg:"env"`
}
setenv(t, "FOO", "1,99\"")
err := Parse(&args)
assert.Error(t, err)
}

func TestEnvironmentVariableSliceArgumentWrongType(t *testing.T) {
var args struct {
Foo []bool `arg:"env"`
}
setenv(t, "FOO", "one,two")
err := Parse(&args)
assert.Error(t, err)
}

type textUnmarshaler struct {
val int
}
Expand Down

0 comments on commit f7c0423

Please sign in to comment.