Merge pull request #267 from tristanz/master

Add ArgsUsage field to document the use of arguments
This commit is contained in:
Jesse Szwedko 2015-10-06 19:45:04 -07:00
commit 9039757268
4 changed files with 143 additions and 15 deletions

23
app.go
View File

@ -13,8 +13,12 @@ import (
type App struct { type App struct {
// The name of the program. Defaults to os.Args[0] // The name of the program. Defaults to os.Args[0]
Name string Name string
// Full name of command for help, defaults to Name
HelpName string
// Description of the program. // Description of the program.
Usage string Usage string
// Description of the program argument format.
ArgsUsage string
// Version of the program // Version of the program
Version string Version string
// List of commands to execute // List of commands to execute
@ -67,6 +71,7 @@ func compileTime() time.Time {
func NewApp() *App { func NewApp() *App {
return &App{ return &App{
Name: os.Args[0], Name: os.Args[0],
HelpName: os.Args[0],
Usage: "A new cli application", Usage: "A new cli application",
Version: "0.0.0", Version: "0.0.0",
BashComplete: DefaultAppComplete, BashComplete: DefaultAppComplete,
@ -82,6 +87,15 @@ func (a *App) Run(arguments []string) (err error) {
a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email}) a.Authors = append(a.Authors, Author{Name: a.Author, Email: a.Email})
} }
newCmds := []Command{}
for _, c := range a.Commands {
if c.HelpName == "" {
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
}
newCmds = append(newCmds, c)
}
a.Commands = newCmds
// append help to commands // append help to commands
if a.Command(helpCommand.Name) == nil && !a.HideHelp { if a.Command(helpCommand.Name) == nil && !a.HideHelp {
a.Commands = append(a.Commands, helpCommand) a.Commands = append(a.Commands, helpCommand)
@ -185,6 +199,15 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
} }
} }
newCmds := []Command{}
for _, c := range a.Commands {
if c.HelpName == "" {
c.HelpName = fmt.Sprintf("%s %s", a.HelpName, c.Name)
}
newCmds = append(newCmds, c)
}
a.Commands = newCmds
// append flags // append flags
if a.EnableBashCompletion { if a.EnableBashCompletion {
a.appendFlag(BashCompletionFlag) a.appendFlag(BashCompletionFlag)

View File

@ -90,10 +90,10 @@ func ExampleAppHelp() {
app.Run(os.Args) app.Run(os.Args)
// Output: // Output:
// NAME: // NAME:
// describeit - use it to see a description // greet describeit - use it to see a description
// //
// USAGE: // USAGE:
// command describeit [arguments...] // greet describeit [arguments...]
// //
// DESCRIPTION: // DESCRIPTION:
// This is how we describe describeit the function // This is how we describe describeit the function
@ -737,7 +737,7 @@ func TestApp_Run_SubcommandFullPath(t *testing.T) {
app := NewApp() app := NewApp()
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
app.Writer = buf app.Writer = buf
app.Name = "command"
subCmd := Command{ subCmd := Command{
Name: "bar", Name: "bar",
Usage: "does bar things", Usage: "does bar things",
@ -755,7 +755,7 @@ func TestApp_Run_SubcommandFullPath(t *testing.T) {
} }
output := buf.String() output := buf.String()
if !strings.Contains(output, "foo bar - does bar things") { if !strings.Contains(output, "command foo bar - does bar things") {
t.Errorf("expected full path to subcommand: %s", output) t.Errorf("expected full path to subcommand: %s", output)
} }
if !strings.Contains(output, "command foo bar [arguments...]") { if !strings.Contains(output, "command foo bar [arguments...]") {
@ -763,6 +763,99 @@ func TestApp_Run_SubcommandFullPath(t *testing.T) {
} }
} }
func TestApp_Run_SubcommandHelpName(t *testing.T) {
app := NewApp()
buf := new(bytes.Buffer)
app.Writer = buf
app.Name = "command"
subCmd := Command{
Name: "bar",
HelpName: "custom",
Usage: "does bar things",
}
cmd := Command{
Name: "foo",
Description: "foo commands",
Subcommands: []Command{subCmd},
}
app.Commands = []Command{cmd}
err := app.Run([]string{"command", "foo", "bar", "--help"})
if err != nil {
t.Error(err)
}
output := buf.String()
if !strings.Contains(output, "custom - does bar things") {
t.Errorf("expected HelpName for subcommand: %s", output)
}
if !strings.Contains(output, "custom [arguments...]") {
t.Errorf("expected HelpName to subcommand: %s", output)
}
}
func TestApp_Run_CommandHelpName(t *testing.T) {
app := NewApp()
buf := new(bytes.Buffer)
app.Writer = buf
app.Name = "command"
subCmd := Command{
Name: "bar",
Usage: "does bar things",
}
cmd := Command{
Name: "foo",
HelpName: "custom",
Description: "foo commands",
Subcommands: []Command{subCmd},
}
app.Commands = []Command{cmd}
err := app.Run([]string{"command", "foo", "bar", "--help"})
if err != nil {
t.Error(err)
}
output := buf.String()
if !strings.Contains(output, "command foo bar - does bar things") {
t.Errorf("expected full path to subcommand: %s", output)
}
if !strings.Contains(output, "command foo bar [arguments...]") {
t.Errorf("expected full path to subcommand: %s", output)
}
}
func TestApp_Run_CommandSubcommandHelpName(t *testing.T) {
app := NewApp()
buf := new(bytes.Buffer)
app.Writer = buf
app.Name = "base"
subCmd := Command{
Name: "bar",
HelpName: "custom",
Usage: "does bar things",
}
cmd := Command{
Name: "foo",
Description: "foo commands",
Subcommands: []Command{subCmd},
}
app.Commands = []Command{cmd}
err := app.Run([]string{"command", "foo", "--help"})
if err != nil {
t.Error(err)
}
output := buf.String()
if !strings.Contains(output, "base foo - foo commands") {
t.Errorf("expected full path to subcommand: %s", output)
}
if !strings.Contains(output, "base foo command [command options] [arguments...]") {
t.Errorf("expected full path to subcommand: %s", output)
}
}
func TestApp_Run_Help(t *testing.T) { func TestApp_Run_Help(t *testing.T) {
var helpArguments = [][]string{{"boom", "--help"}, {"boom", "-h"}, {"boom", "help"}} var helpArguments = [][]string{{"boom", "--help"}, {"boom", "-h"}, {"boom", "help"}}

View File

@ -18,6 +18,8 @@ type Command struct {
Usage string Usage string
// A longer explanation of how the command works // A longer explanation of how the command works
Description string Description string
// A short description of the arguments of this command
ArgsUsage string
// The function to call when checking for bash command completions // The function to call when checking for bash command completions
BashComplete func(context *Context) BashComplete func(context *Context)
// An action to execute before any sub-subcommands are run, but after the context is ready // An action to execute before any sub-subcommands are run, but after the context is ready
@ -37,6 +39,8 @@ type Command struct {
// Boolean to hide built-in help command // Boolean to hide built-in help command
HideHelp bool HideHelp bool
// Full name of command for help, defaults to full command name, including parent commands.
HelpName string
commandNamePath []string commandNamePath []string
} }
@ -153,6 +157,12 @@ func (c Command) startApp(ctx *Context) error {
// set the name and usage // set the name and usage
app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name) app.Name = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
if c.HelpName == "" {
app.HelpName = c.HelpName
} else {
app.HelpName = fmt.Sprintf("%s %s", ctx.App.Name, c.Name)
}
if c.Description != "" { if c.Description != "" {
app.Usage = c.Description app.Usage = c.Description
} else { } else {

12
help.go
View File

@ -15,7 +15,7 @@ var AppHelpTemplate = `NAME:
{{.Name}} - {{.Usage}} {{.Name}} - {{.Usage}}
USAGE: USAGE:
{{.Name}} {{if .Flags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} [arguments...] {{.HelpName}} {{if .Flags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
{{if .Version}} {{if .Version}}
VERSION: VERSION:
{{.Version}} {{.Version}}
@ -38,10 +38,10 @@ COPYRIGHT:
// cli.go uses text/template to render templates. You can // cli.go uses text/template to render templates. You can
// render custom help text by setting this variable. // render custom help text by setting this variable.
var CommandHelpTemplate = `NAME: var CommandHelpTemplate = `NAME:
{{.FullName}} - {{.Usage}} {{.HelpName}} - {{.Usage}}
USAGE: USAGE:
command {{.FullName}}{{if .Flags}} [command options]{{end}} [arguments...]{{if .Description}} {{.HelpName}}{{if .Flags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}{{if .Description}}
DESCRIPTION: DESCRIPTION:
{{.Description}}{{end}}{{if .Flags}} {{.Description}}{{end}}{{if .Flags}}
@ -55,10 +55,10 @@ OPTIONS:
// cli.go uses text/template to render templates. You can // cli.go uses text/template to render templates. You can
// render custom help text by setting this variable. // render custom help text by setting this variable.
var SubcommandHelpTemplate = `NAME: var SubcommandHelpTemplate = `NAME:
{{.Name}} - {{.Usage}} {{.HelpName}} - {{.Usage}}
USAGE: USAGE:
{{.Name}} command{{if .Flags}} [command options]{{end}} [arguments...] {{.HelpName}} command{{if .Flags}} [command options]{{end}} {{if .ArgsUsage}}{{.ArgsUsage}}{{else}}[arguments...]{{end}}
COMMANDS: COMMANDS:
{{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}}
@ -72,6 +72,7 @@ var helpCommand = Command{
Name: "help", Name: "help",
Aliases: []string{"h"}, Aliases: []string{"h"},
Usage: "Shows a list of commands or help for one command", Usage: "Shows a list of commands or help for one command",
ArgsUsage: "[command]",
Action: func(c *Context) { Action: func(c *Context) {
args := c.Args() args := c.Args()
if args.Present() { if args.Present() {
@ -86,6 +87,7 @@ var helpSubcommand = Command{
Name: "help", Name: "help",
Aliases: []string{"h"}, Aliases: []string{"h"},
Usage: "Shows a list of commands or help for one command", Usage: "Shows a list of commands or help for one command",
ArgsUsage: "[command]",
Action: func(c *Context) { Action: func(c *Context) {
args := c.Args() args := c.Args()
if args.Present() { if args.Present() {