Merge branch 'master' into master

This commit is contained in:
K3A 2017-03-09 18:25:56 +01:00 committed by GitHub
commit b413f8dfb0
4 changed files with 95 additions and 4 deletions

View File

@ -148,6 +148,22 @@ fmt.Printf("Fetching the following IDs from %s: %q", args.Database, args.IDs)
Fetching the following IDs from foo: [1 2 3]
```
### Arguments that can be specified multiple times, mixed with positionals
```go
var args struct {
Commands []string `arg:"-c,separate"`
Files []string `arg:"-f,separate"`
Databases []string `arg:"positional"`
}
```
```shell
./example -c cmd1 db1 -f file1 db2 -c cmd2 -f file2 -f file3 db3 -c cmd3
Commands: [cmd1 cmd2 cmd3]
Files [file1 file2 file3]
Databases [db1 db2 db3]
```
### Custom validation
```go
var args struct {

View File

@ -71,6 +71,21 @@ func Example_multipleValues() {
fmt.Printf("Fetching the following IDs from %s: %q", args.Database, args.IDs)
}
// This eample demonstrates multiple value arguments that can be mixed with
// other arguments.
func Example_multipleMixed() {
os.Args = []string{"./example", "-c", "cmd1", "db1", "-f", "file1", "db2", "-c", "cmd2", "-f", "file2", "-f", "file3", "db3", "-c", "cmd3"}
var args struct {
Commands []string `arg:"-c,separate"`
Files []string `arg:"-f,separate"`
Databases []string `arg:"positional"`
}
MustParse(&args)
fmt.Println("Commands:", args.Commands)
fmt.Println("Files", args.Files)
fmt.Println("Databases", args.Databases)
}
// This example shows the usage string generated by go-arg
func Example_usageString() {
// These are the args you would pass in on the command line

View File

@ -20,6 +20,7 @@ type spec struct {
multiple bool
required bool
positional bool
separate bool
help string
env string
wasPresent bool
@ -189,6 +190,8 @@ func NewParser(config Config, dests ...interface{}) (*Parser, error) {
spec.required = true
case key == "positional":
spec.positional = true
case key == "separate":
spec.separate = true
case key == "help":
spec.help = value
case key == "env":
@ -314,11 +317,14 @@ func process(specs []*spec, args []string) error {
for i+1 < len(args) && !isFlag(args[i+1]) {
values = append(values, args[i+1])
i++
if spec.separate {
break
}
}
} else {
values = append(values, value)
}
err := setSlice(spec.dest, values)
err := setSlice(spec.dest, values, !spec.separate)
if err != nil {
return fmt.Errorf("error processing %s: %v", arg, err)
}
@ -350,7 +356,7 @@ func process(specs []*spec, args []string) error {
for _, spec := range specs {
if spec.positional {
if spec.multiple {
err := setSlice(spec.dest, positionals)
err := setSlice(spec.dest, positionals, true)
if err != nil {
return fmt.Errorf("error processing %s: %v", spec.long, err)
}
@ -388,7 +394,7 @@ func validate(spec []*spec) error {
}
// parse a value as the appropriate type and store it in the struct
func setSlice(dest reflect.Value, values []string) error {
func setSlice(dest reflect.Value, values []string, trunc bool) error {
if !dest.CanSet() {
return fmt.Errorf("field is not writable")
}
@ -401,7 +407,7 @@ func setSlice(dest reflect.Value, values []string) error {
}
// Truncate the dest slice in case default values exist
if !dest.IsNil() {
if trunc && !dest.IsNil() {
dest.SetLen(0)
}

View File

@ -739,3 +739,57 @@ func TestHyphenInMultiPositional(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, []string{"---", "x", "-", "y"}, args.Foo)
}
func TestSeparate(t *testing.T) {
for _, val := range []string{"-f one", "-f=one", "--foo one", "--foo=one"} {
var args struct {
Foo []string `arg:"--foo,-f,separate"`
}
err := parse(val, &args)
require.NoError(t, err)
assert.Equal(t, []string{"one"}, args.Foo)
}
}
func TestSeparateWithDefault(t *testing.T) {
args := struct {
Foo []string `arg:"--foo,-f,separate"`
}{
Foo: []string{"default"},
}
err := parse("-f one -f=two", &args)
require.NoError(t, err)
assert.Equal(t, []string{"default", "one", "two"}, args.Foo)
}
func TestSeparateWithPositional(t *testing.T) {
var args struct {
Foo []string `arg:"--foo,-f,separate"`
Bar string `arg:"positional"`
Moo string `arg:"positional"`
}
err := parse("zzz --foo one -f=two --foo=three -f four aaa", &args)
require.NoError(t, err)
assert.Equal(t, []string{"one", "two", "three", "four"}, args.Foo)
assert.Equal(t, "zzz", args.Bar)
assert.Equal(t, "aaa", args.Moo)
}
func TestSeparatePositionalInterweaved(t *testing.T) {
var args struct {
Foo []string `arg:"--foo,-f,separate"`
Bar []string `arg:"--bar,-b,separate"`
Pre string `arg:"positional"`
Post []string `arg:"positional"`
}
err := parse("zzz -f foo1 -b=bar1 --foo=foo2 -b bar2 post1 -b bar3 post2 post3", &args)
require.NoError(t, err)
assert.Equal(t, []string{"foo1", "foo2"}, args.Foo)
assert.Equal(t, []string{"bar1", "bar2", "bar3"}, args.Bar)
assert.Equal(t, "zzz", args.Pre)
assert.Equal(t, []string{"post1", "post2", "post3"}, args.Post)
}