Altered help tag parsing to reduce the constraints on help text content; old behaviour is retained for backward compatibility

This commit is contained in:
Rick 2017-10-02 14:18:41 +01:00
parent 398a01ebab
commit d7961941f0
5 changed files with 58 additions and 23 deletions

View File

@ -99,9 +99,9 @@ Workers: 4
var args struct {
Input string `arg:"positional"`
Output []string `arg:"positional"`
Verbose bool `arg:"-v,help:verbosity level"`
Dataset string `arg:"help:dataset to use"`
Optimize int `arg:"-O,help:optimization level"`
Verbose bool `arg:"-v" help:"verbosity level"`
Dataset string `help:"dataset to use"`
Optimize int `arg:"-O" help:"optimization level"`
}
arg.MustParse(&args)
```
@ -306,7 +306,7 @@ Options:
--help, -h display this help and exit
```
### Documentation
### API Documentation
https://godoc.org/github.com/alexflint/go-arg
@ -319,3 +319,7 @@ The shortcomings of the `flag` library that ships in the standard library are we
Many third-party argument parsing libraries are geared for writing sophisticated command line interfaces. The excellent `codegangsta/cli` is perfect for working with multiple sub-commands and nested flags, but is probably overkill for a simple script with a handful of flags.
The main idea behind `go-arg` is that Go already has an excellent way to describe data structures using Go structs, so there is no need to develop more levels of abstraction on top of this. Instead of one API to specify which arguments your program accepts, and then another API to get the values of those arguments, why not replace both with a single struct?
### Backward Compatibility Notes
The tags have changed recently. Earlier versions required the help text to be part of the `arg` tag. This is still supported but is now deprecated. Instead, you should use a separate `help` tag, described above, which removes most of the limits on the text you can write.

15
doc.go
View File

@ -19,18 +19,21 @@
// Fields can be bool, string, any float type, or any signed or unsigned integer type.
// They can also be slices of any of the above, or slices of pointers to any of the above.
//
// Tags can be specified using the `arg` package name:
// Tags can be specified using the `arg` and `help` tag names:
//
// var args struct {
// Input string `arg:"positional"`
// Log string `arg:"positional,required"`
// Debug bool `arg:"-d,help:turn on debug mode"`
// Debug bool `arg:"-d" help:"turn on debug mode"`
// RealMode bool `arg:"--real"
// Wr io.Writer `arg:"-"`
// }
//
// The valid tag strings are `positional`, `required`, and `help`. Further, any tag string
// that starts with a single hyphen is the short form for an argument (e.g. `./example -d`),
// and any tag string that starts with two hyphens is the long form for the argument
// (instead of the field name). Fields can be excluded from processing with `arg:"-"`.
// Any tag string that starts with a single hyphen is the short form for an argument
// (e.g. `./example -d`), and any tag string that starts with two hyphens is the long
// form for the argument (instead of the field name).
//
// Other valid tag strings are `positional` and `required`.
//
// Fields can be excluded from processing with `arg:"-"`.
package arg

View File

@ -153,6 +153,11 @@ func NewParser(config Config, dests ...interface{}) (*Parser, error) {
dest: val,
}
help, exists := field.Tag.Lookup("help")
if exists {
spec.help = help
}
// Check whether this field is supported. It's good to do this here rather than
// wait until setScalar because it means that a program with invalid argument
// fields will always fail regardless of whether the arguments it received
@ -193,7 +198,7 @@ func NewParser(config Config, dests ...interface{}) (*Parser, error) {
spec.positional = true
case key == "separate":
spec.separate = true
case key == "help":
case key == "help": // deprecated
spec.help = value
case key == "env":
// Use override name if provided

View File

@ -131,7 +131,7 @@ func TestMixed(t *testing.T) {
var args struct {
Foo string `arg:"-f"`
Bar int
Baz uint `arg:"positional"`
Baz uint `arg:"positional"`
Ham bool
Spam float32
}

View File

@ -33,15 +33,15 @@ Options:
`
var args struct {
Input string `arg:"positional"`
Output []string `arg:"positional,help:list of outputs"`
Name string `arg:"help:name to use"`
Value int `arg:"help:secret value"`
Verbose bool `arg:"-v,help:verbosity level"`
Dataset string `arg:"help:dataset to use"`
Optimize int `arg:"-O,help:optimization level"`
Ids []int64 `arg:"help:Ids"`
Values []float64 `arg:"help:Values"`
Workers int `arg:"-w,env:WORKERS,help:number of workers to start"`
Output []string `arg:"positional" help:"list of outputs"`
Name string `help:"name to use"`
Value int `help:"secret value"`
Verbose bool `arg:"-v" help:"verbosity level"`
Dataset string `help:"dataset to use"`
Optimize int `arg:"-O" help:"optimization level"`
Ids []int64 `help:"Ids"`
Values []float64 `help:"Values"`
Workers int `arg:"-w,env:WORKERS" help:"number of workers to start"`
}
args.Name = "Foo Bar"
args.Value = 42
@ -60,7 +60,7 @@ Options:
assert.Equal(t, expectedHelp, help.String())
}
func TestUsageLongPositionalWithHelp(t *testing.T) {
func TestUsageLongPositionalWithHelp_legacyForm(t *testing.T) {
expectedHelp := `Usage: example VERYLONGPOSITIONALWITHHELP
Positional arguments:
@ -83,6 +83,29 @@ Options:
assert.Equal(t, expectedHelp, help.String())
}
func TestUsageLongPositionalWithHelp_newForm(t *testing.T) {
expectedHelp := `Usage: example VERYLONGPOSITIONALWITHHELP
Positional arguments:
VERYLONGPOSITIONALWITHHELP
this positional argument is very long
Options:
--help, -h display this help and exit
`
var args struct {
VeryLongPositionalWithHelp string `arg:"positional" help:"this positional argument is very long"`
}
p, err := NewParser(Config{}, &args)
require.NoError(t, err)
os.Args[0] = "example"
var help bytes.Buffer
p.WriteHelp(&help)
assert.Equal(t, expectedHelp, help.String())
}
func TestUsageWithProgramName(t *testing.T) {
expectedHelp := `Usage: myprogram
@ -168,7 +191,7 @@ Options:
--help, -h display this help and exit
`
var args struct {
RequiredMultiple []string `arg:"positional,required,help:required multiple positional"`
RequiredMultiple []string `arg:"positional,required" help:"required multiple positional"`
}
p, err := NewParser(Config{}, &args)