Fix providing multiple values via environment variables

This commit is contained in:
Illia Volochii 2018-04-26 21:10:44 +03:00
parent 074ee5f759
commit 75bf1a1525
3 changed files with 70 additions and 1 deletions

View File

@ -94,6 +94,22 @@ $ NUM_WORKERS=4 ./example
Workers: 4
```
You should use a JSON array of strings (value will be converted if
necessary) in the case of multiple values:
```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 {

View File

@ -2,6 +2,7 @@ package arg
import (
"encoding"
"encoding/json"
"errors"
"fmt"
"os"
@ -275,7 +276,23 @@ func process(specs []*spec, args []string) error {
}
if spec.env != "" {
if value, found := os.LookupEnv(spec.env); found {
err := scalar.ParseValue(spec.dest, value)
var err error
if spec.multiple {
// expect a JSON array of strings in an environment
// variable in the case of multiple values
var values []string
err = json.Unmarshal([]byte(value), &values)
if err != nil {
return fmt.Errorf(
"error processing environment variable %s (it should be a JSON array of strings):\n%v",
spec.env,
err,
)
}
err = setSlice(spec.dest, values, !spec.separate)
} else {
err = scalar.ParseValue(spec.dest, value)
}
if err != nil {
return fmt.Errorf("error processing environment variable %s: %v", spec.env, err)
}

View File

@ -580,6 +580,42 @@ 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\"]")
MustParse(&args)
assert.Equal(t, []string{"bar", "baz"}, 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)
}
type textUnmarshaler struct {
val int
}