Add support for environment variables

This commit is contained in:
brettlangdon 2016-01-18 13:42:04 -05:00
parent c9155bb0c3
commit 8dd29d34bf
4 changed files with 107 additions and 2 deletions

View File

@ -54,6 +54,41 @@ Input: src.txt
Output: [x.out y.out z.out] Output: [x.out y.out z.out]
``` ```
### Environment variables
```go
var args struct {
Workers int `arg:"env"`
}
arg.MustParse(&args)
fmt.Println("Workers:", args.Workers)
```
```
$ WORKERS=4 ./example
Workers: 4
```
```
$ WORKERS=4 ./example --workers=6
Workers: 6
```
You can also override the name of the environment variable:
```go
var args struct {
Workers int `arg:"env:NUM_WORKERS"`
}
arg.MustParse(&args)
fmt.Println("Workers:", args.Workers)
```
```
$ NUM_WORKERS=4 ./example
Workers: 4
```
### Usage strings ### Usage strings
```go ```go
var args struct { var args struct {

View File

@ -18,6 +18,7 @@ type spec struct {
required bool required bool
positional bool positional bool
help string help string
env string
wasPresent bool wasPresent bool
isBool bool isBool bool
} }
@ -130,6 +131,13 @@ func NewParser(dests ...interface{}) (*Parser, error) {
spec.positional = true spec.positional = true
case key == "help": case key == "help":
spec.help = value spec.help = value
case key == "env":
// Use override name if provided
if value != "" {
spec.env = value
} else {
spec.env = strings.ToUpper(field.Name)
}
default: default:
return nil, fmt.Errorf("unrecognized tag '%s' on field %s", key, tag) return nil, fmt.Errorf("unrecognized tag '%s' on field %s", key, tag)
} }
@ -179,6 +187,15 @@ func process(specs []*spec, args []string) error {
if spec.short != "" { if spec.short != "" {
optionMap[spec.short] = spec optionMap[spec.short] = spec
} }
if spec.env != "" {
if value, found := os.LookupEnv(spec.env); found {
err := setScalar(spec.dest, value)
if err != nil {
return fmt.Errorf("error processing environment variable %s: %v", spec.env, err)
}
spec.wasPresent = true
}
}
} }
// process each string from the command line // process each string from the command line

View File

@ -357,3 +357,53 @@ func TestMustParse(t *testing.T) {
assert.Equal(t, "bar", args.Foo) assert.Equal(t, "bar", args.Foo)
assert.NotNil(t, parser) assert.NotNil(t, parser)
} }
func TestEnvironmentVariable(t *testing.T) {
var args struct {
Foo string `arg:"env"`
}
os.Setenv("FOO", "bar")
os.Args = []string{"example"}
MustParse(&args)
assert.Equal(t, "bar", args.Foo)
}
func TestEnvironmentVariableOverrideName(t *testing.T) {
var args struct {
Foo string `arg:"env:BAZ"`
}
os.Setenv("BAZ", "bar")
os.Args = []string{"example"}
MustParse(&args)
assert.Equal(t, "bar", args.Foo)
}
func TestEnvironmentVariableOverrideArgument(t *testing.T) {
var args struct {
Foo string `arg:"env"`
}
os.Setenv("FOO", "bar")
os.Args = []string{"example", "--foo", "baz"}
MustParse(&args)
assert.Equal(t, "baz", args.Foo)
}
func TestEnvironmentVariableError(t *testing.T) {
var args struct {
Foo int `arg:"env"`
}
os.Setenv("FOO", "bar")
os.Args = []string{"example"}
err := Parse(&args)
assert.Error(t, err)
}
func TestEnvironmentVariableRequired(t *testing.T) {
var args struct {
Foo string `arg:"env,required"`
}
os.Setenv("FOO", "bar")
os.Args = []string{"example"}
MustParse(&args)
assert.Equal(t, "bar", args.Foo)
}

View File

@ -10,9 +10,9 @@ import (
) )
func TestWriteUsage(t *testing.T) { func TestWriteUsage(t *testing.T) {
expectedUsage := "usage: example [--name NAME] [--value VALUE] [--verbose] [--dataset DATASET] [--optimize OPTIMIZE] [--ids IDS] INPUT [OUTPUT [OUTPUT ...]]\n" expectedUsage := "usage: example [--name NAME] [--value VALUE] [--verbose] [--dataset DATASET] [--optimize OPTIMIZE] [--ids IDS] [--workers WORKERS] INPUT [OUTPUT [OUTPUT ...]]\n"
expectedHelp := `usage: example [--name NAME] [--value VALUE] [--verbose] [--dataset DATASET] [--optimize OPTIMIZE] [--ids IDS] INPUT [OUTPUT [OUTPUT ...]] expectedHelp := `usage: example [--name NAME] [--value VALUE] [--verbose] [--dataset DATASET] [--optimize OPTIMIZE] [--ids IDS] [--workers WORKERS] INPUT [OUTPUT [OUTPUT ...]]
positional arguments: positional arguments:
input input
@ -26,6 +26,8 @@ options:
--optimize OPTIMIZE, -O OPTIMIZE --optimize OPTIMIZE, -O OPTIMIZE
optimization level optimization level
--ids IDS Ids --ids IDS Ids
--workers WORKERS, -w WORKERS
number of workers to start
--help, -h display this help and exit --help, -h display this help and exit
` `
var args struct { var args struct {
@ -37,6 +39,7 @@ options:
Dataset string `arg:"help:dataset to use"` Dataset string `arg:"help:dataset to use"`
Optimize int `arg:"-O,help:optimization level"` Optimize int `arg:"-O,help:optimization level"`
Ids []int64 `arg:"help:Ids"` Ids []int64 `arg:"help:Ids"`
Workers int `arg:"-w,env:WORKERS,help:number of workers to start"`
} }
args.Name = "Foo Bar" args.Name = "Foo Bar"
args.Value = 42 args.Value = 42