Merge pull request #224 from hhromic/better-version-v2
Fix usage writing when using custom version flag
This commit is contained in:
commit
0cc152dce5
|
@ -301,6 +301,9 @@ $ ./example --version
|
|||
someprogram 4.3.0
|
||||
```
|
||||
|
||||
> **Note**
|
||||
> If a `--version` flag is defined in `args` or any subcommand, it overrides the built-in versioning.
|
||||
|
||||
### Overriding option names
|
||||
|
||||
```go
|
||||
|
|
52
usage.go
52
usage.go
|
@ -48,18 +48,36 @@ func (p *Parser) WriteUsageForSubcommand(w io.Writer, subcommand ...string) erro
|
|||
}
|
||||
|
||||
var positionals, longOptions, shortOptions []*spec
|
||||
var hasVersionOption bool
|
||||
for _, spec := range cmd.specs {
|
||||
switch {
|
||||
case spec.positional:
|
||||
positionals = append(positionals, spec)
|
||||
case spec.long != "":
|
||||
longOptions = append(longOptions, spec)
|
||||
if spec.long == "version" {
|
||||
hasVersionOption = true
|
||||
}
|
||||
case spec.short != "":
|
||||
shortOptions = append(shortOptions, spec)
|
||||
}
|
||||
}
|
||||
|
||||
if p.version != "" {
|
||||
// make a list of ancestor commands so that we print with full context
|
||||
// also determine if any ancestor has a version option spec
|
||||
var ancestors []string
|
||||
ancestor := cmd
|
||||
for ancestor != nil {
|
||||
for _, spec := range ancestor.specs {
|
||||
if spec.long == "version" {
|
||||
hasVersionOption = true
|
||||
}
|
||||
}
|
||||
ancestors = append(ancestors, ancestor.name)
|
||||
ancestor = ancestor.parent
|
||||
}
|
||||
|
||||
if !hasVersionOption && p.version != "" {
|
||||
fmt.Fprintln(w, p.version)
|
||||
}
|
||||
|
||||
|
@ -208,6 +226,9 @@ func (p *Parser) WriteHelpForSubcommand(w io.Writer, subcommand ...string) error
|
|||
positionals = append(positionals, spec)
|
||||
case spec.long != "":
|
||||
longOptions = append(longOptions, spec)
|
||||
if spec.long == "version" {
|
||||
hasVersionOption = true
|
||||
}
|
||||
case spec.short != "":
|
||||
shortOptions = append(shortOptions, spec)
|
||||
case spec.short == "" && spec.long == "":
|
||||
|
@ -215,6 +236,21 @@ func (p *Parser) WriteHelpForSubcommand(w io.Writer, subcommand ...string) error
|
|||
}
|
||||
}
|
||||
|
||||
// obtain a flattened list of options from all ancestors
|
||||
// also determine if any ancestor has a version option spec
|
||||
var globals []*spec
|
||||
ancestor := cmd.parent
|
||||
for ancestor != nil {
|
||||
for _, spec := range ancestor.specs {
|
||||
if spec.long == "version" {
|
||||
hasVersionOption = true
|
||||
break
|
||||
}
|
||||
}
|
||||
globals = append(globals, ancestor.specs...)
|
||||
ancestor = ancestor.parent
|
||||
}
|
||||
|
||||
if p.description != "" {
|
||||
fmt.Fprintln(w, p.description)
|
||||
}
|
||||
|
@ -236,28 +272,14 @@ func (p *Parser) WriteHelpForSubcommand(w io.Writer, subcommand ...string) error
|
|||
}
|
||||
for _, spec := range longOptions {
|
||||
p.printOption(w, spec)
|
||||
if spec.long == "version" {
|
||||
hasVersionOption = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// obtain a flattened list of options from all ancestors
|
||||
var globals []*spec
|
||||
ancestor := cmd.parent
|
||||
for ancestor != nil {
|
||||
globals = append(globals, ancestor.specs...)
|
||||
ancestor = ancestor.parent
|
||||
}
|
||||
|
||||
// write the list of global options
|
||||
if len(globals) > 0 {
|
||||
fmt.Fprint(w, "\nGlobal options:\n")
|
||||
for _, spec := range globals {
|
||||
p.printOption(w, spec)
|
||||
if spec.long == "version" {
|
||||
hasVersionOption = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
218
usage_test.go
218
usage_test.go
|
@ -260,28 +260,23 @@ Options:
|
|||
assert.Equal(t, expectedUsage, strings.TrimSpace(usage.String()))
|
||||
}
|
||||
|
||||
type userDefinedVersionFlag struct {
|
||||
ShowVersion bool `arg:"--version" help:"this is a user-defined version flag"`
|
||||
}
|
||||
|
||||
// Version returns the version for this program
|
||||
func (userDefinedVersionFlag) Version() string {
|
||||
return "example 3.2.1"
|
||||
}
|
||||
|
||||
func TestUsageWithUserDefinedVersionFlag(t *testing.T) {
|
||||
expectedUsage := "example 3.2.1\nUsage: example [--version]"
|
||||
expectedUsage := "Usage: example [--version]"
|
||||
|
||||
expectedHelp := `
|
||||
example 3.2.1
|
||||
Usage: example [--version]
|
||||
|
||||
Options:
|
||||
--version this is a user-defined version flag
|
||||
--help, -h display this help and exit
|
||||
`
|
||||
|
||||
var args struct {
|
||||
ShowVersion bool `arg:"--version" help:"this is a user-defined version flag"`
|
||||
}
|
||||
|
||||
os.Args[0] = "example"
|
||||
p, err := NewParser(Config{}, &userDefinedVersionFlag{})
|
||||
p, err := NewParser(Config{}, &args)
|
||||
require.NoError(t, err)
|
||||
|
||||
var help bytes.Buffer
|
||||
|
@ -293,6 +288,205 @@ Options:
|
|||
assert.Equal(t, expectedUsage, strings.TrimSpace(usage.String()))
|
||||
}
|
||||
|
||||
func TestUsageWithVersionAndUserDefinedVersionFlag(t *testing.T) {
|
||||
expectedUsage := "Usage: example [--version]"
|
||||
|
||||
expectedHelp := `
|
||||
Usage: example [--version]
|
||||
|
||||
Options:
|
||||
--version this is a user-defined version flag
|
||||
--help, -h display this help and exit
|
||||
`
|
||||
|
||||
var args struct {
|
||||
versioned
|
||||
ShowVersion bool `arg:"--version" help:"this is a user-defined version flag"`
|
||||
}
|
||||
|
||||
os.Args[0] = "example"
|
||||
p, err := NewParser(Config{}, &args)
|
||||
require.NoError(t, err)
|
||||
|
||||
var help bytes.Buffer
|
||||
p.WriteHelp(&help)
|
||||
assert.Equal(t, expectedHelp[1:], help.String())
|
||||
|
||||
var usage bytes.Buffer
|
||||
p.WriteUsage(&usage)
|
||||
assert.Equal(t, expectedUsage, strings.TrimSpace(usage.String()))
|
||||
}
|
||||
|
||||
type subcommand struct {
|
||||
Number int `arg:"-n,--number" help:"compute something on the given number"`
|
||||
}
|
||||
|
||||
func TestUsageWithVersionAndSubcommand(t *testing.T) {
|
||||
expectedUsage := "example 3.2.1\nUsage: example <command> [<args>]"
|
||||
|
||||
expectedHelp := `
|
||||
example 3.2.1
|
||||
Usage: example <command> [<args>]
|
||||
|
||||
Options:
|
||||
--help, -h display this help and exit
|
||||
--version display version and exit
|
||||
|
||||
Commands:
|
||||
cmd
|
||||
`
|
||||
|
||||
var args struct {
|
||||
versioned
|
||||
Cmd *subcommand `arg:"subcommand"`
|
||||
}
|
||||
|
||||
os.Args[0] = "example"
|
||||
p, err := NewParser(Config{}, &args)
|
||||
require.NoError(t, err)
|
||||
|
||||
var help bytes.Buffer
|
||||
p.WriteHelp(&help)
|
||||
assert.Equal(t, expectedHelp[1:], help.String())
|
||||
|
||||
var usage bytes.Buffer
|
||||
p.WriteUsage(&usage)
|
||||
assert.Equal(t, expectedUsage, strings.TrimSpace(usage.String()))
|
||||
|
||||
expectedUsage = "example 3.2.1\nUsage: example cmd [--number NUMBER]"
|
||||
|
||||
expectedHelp = `
|
||||
example 3.2.1
|
||||
Usage: example cmd [--number NUMBER]
|
||||
|
||||
Options:
|
||||
--number NUMBER, -n NUMBER
|
||||
compute something on the given number
|
||||
--help, -h display this help and exit
|
||||
--version display version and exit
|
||||
`
|
||||
_ = p.Parse([]string{"cmd"})
|
||||
|
||||
help = bytes.Buffer{}
|
||||
p.WriteHelp(&help)
|
||||
assert.Equal(t, expectedHelp[1:], help.String())
|
||||
|
||||
usage = bytes.Buffer{}
|
||||
p.WriteUsage(&usage)
|
||||
assert.Equal(t, expectedUsage, strings.TrimSpace(usage.String()))
|
||||
}
|
||||
|
||||
func TestUsageWithUserDefinedVersionFlagAndSubcommand(t *testing.T) {
|
||||
expectedUsage := "Usage: example [--version] <command> [<args>]"
|
||||
|
||||
expectedHelp := `
|
||||
Usage: example [--version] <command> [<args>]
|
||||
|
||||
Options:
|
||||
--version this is a user-defined version flag
|
||||
--help, -h display this help and exit
|
||||
|
||||
Commands:
|
||||
cmd
|
||||
`
|
||||
|
||||
var args struct {
|
||||
Cmd *subcommand `arg:"subcommand"`
|
||||
ShowVersion bool `arg:"--version" help:"this is a user-defined version flag"`
|
||||
}
|
||||
|
||||
os.Args[0] = "example"
|
||||
p, err := NewParser(Config{}, &args)
|
||||
require.NoError(t, err)
|
||||
|
||||
var help bytes.Buffer
|
||||
p.WriteHelp(&help)
|
||||
assert.Equal(t, expectedHelp[1:], help.String())
|
||||
|
||||
var usage bytes.Buffer
|
||||
p.WriteUsage(&usage)
|
||||
assert.Equal(t, expectedUsage, strings.TrimSpace(usage.String()))
|
||||
|
||||
expectedUsage = "Usage: example cmd [--number NUMBER]"
|
||||
|
||||
expectedHelp = `
|
||||
Usage: example cmd [--number NUMBER]
|
||||
|
||||
Options:
|
||||
--number NUMBER, -n NUMBER
|
||||
compute something on the given number
|
||||
|
||||
Global options:
|
||||
--version this is a user-defined version flag
|
||||
--help, -h display this help and exit
|
||||
`
|
||||
_ = p.Parse([]string{"cmd"})
|
||||
|
||||
help = bytes.Buffer{}
|
||||
p.WriteHelp(&help)
|
||||
assert.Equal(t, expectedHelp[1:], help.String())
|
||||
|
||||
usage = bytes.Buffer{}
|
||||
p.WriteUsage(&usage)
|
||||
assert.Equal(t, expectedUsage, strings.TrimSpace(usage.String()))
|
||||
}
|
||||
|
||||
func TestUsageWithVersionAndUserDefinedVersionFlagAndSubcommand(t *testing.T) {
|
||||
expectedUsage := "Usage: example [--version] <command> [<args>]"
|
||||
|
||||
expectedHelp := `
|
||||
Usage: example [--version] <command> [<args>]
|
||||
|
||||
Options:
|
||||
--version this is a user-defined version flag
|
||||
--help, -h display this help and exit
|
||||
|
||||
Commands:
|
||||
cmd
|
||||
`
|
||||
|
||||
var args struct {
|
||||
versioned
|
||||
Cmd *subcommand `arg:"subcommand"`
|
||||
ShowVersion bool `arg:"--version" help:"this is a user-defined version flag"`
|
||||
}
|
||||
|
||||
os.Args[0] = "example"
|
||||
p, err := NewParser(Config{}, &args)
|
||||
require.NoError(t, err)
|
||||
|
||||
var help bytes.Buffer
|
||||
p.WriteHelp(&help)
|
||||
assert.Equal(t, expectedHelp[1:], help.String())
|
||||
|
||||
var usage bytes.Buffer
|
||||
p.WriteUsage(&usage)
|
||||
assert.Equal(t, expectedUsage, strings.TrimSpace(usage.String()))
|
||||
|
||||
expectedUsage = "Usage: example cmd [--number NUMBER]"
|
||||
|
||||
expectedHelp = `
|
||||
Usage: example cmd [--number NUMBER]
|
||||
|
||||
Options:
|
||||
--number NUMBER, -n NUMBER
|
||||
compute something on the given number
|
||||
|
||||
Global options:
|
||||
--version this is a user-defined version flag
|
||||
--help, -h display this help and exit
|
||||
`
|
||||
_ = p.Parse([]string{"cmd"})
|
||||
|
||||
help = bytes.Buffer{}
|
||||
p.WriteHelp(&help)
|
||||
assert.Equal(t, expectedHelp[1:], help.String())
|
||||
|
||||
usage = bytes.Buffer{}
|
||||
p.WriteUsage(&usage)
|
||||
assert.Equal(t, expectedUsage, strings.TrimSpace(usage.String()))
|
||||
}
|
||||
|
||||
type described struct{}
|
||||
|
||||
// Described returns the description for this program
|
||||
|
|
Loading…
Reference in New Issue