From bf65971a6a2f115d0f1089fa794121a150705a07 Mon Sep 17 00:00:00 2001 From: jszwedko Date: Mon, 9 Mar 2015 21:24:57 -0700 Subject: [PATCH 1/3] Add `Command.Aliases` and deprecate `Command.ShortName` `Aliases` will be more flexible while still allowing "ShortName" behaviour via `Aliases`. --- README.md | 12 +++++------ app.go | 7 ++++++- app_test.go | 53 +++++++++++++++++-------------------------------- cli_test.go | 28 +++++++++++++------------- command.go | 21 ++++++++++++++++++-- command_test.go | 4 ++-- help.go | 21 ++++++++++---------- 7 files changed, 75 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index c0bb338..3a183b1 100644 --- a/README.md +++ b/README.md @@ -210,7 +210,7 @@ Subcommands can be defined for a more git-like command line app. app.Commands = []cli.Command{ { Name: "add", - ShortName: "a", + Names: []string{"a"}, Usage: "add a task to the list", Action: func(c *cli.Context) { println("added task: ", c.Args().First()) @@ -218,7 +218,7 @@ app.Commands = []cli.Command{ }, { Name: "complete", - ShortName: "c", + Names: []string{"c"}, Usage: "complete a task on the list", Action: func(c *cli.Context) { println("completed task: ", c.Args().First()) @@ -226,7 +226,7 @@ app.Commands = []cli.Command{ }, { Name: "template", - ShortName: "r", + Names: []string{"r"}, Usage: "options for task templates", Subcommands: []cli.Command{ { @@ -244,7 +244,7 @@ app.Commands = []cli.Command{ }, }, }, - }, + }, } ... ``` @@ -262,8 +262,8 @@ app := cli.NewApp() app.EnableBashCompletion = true app.Commands = []cli.Command{ { - Name: "complete", - ShortName: "c", + Name: "complete", + Names: []string{"c"}, Usage: "complete a task on the list", Action: func(c *cli.Context) { println("completed task: ", c.Args().First()) diff --git a/app.go b/app.go index 3e7d5a6..dde0061 100644 --- a/app.go +++ b/app.go @@ -5,6 +5,7 @@ import ( "io" "io/ioutil" "os" + "strings" "text/tabwriter" "text/template" "time" @@ -91,8 +92,12 @@ func (a *App) Run(arguments []string) (err error) { }() HelpPrinter = func(templ string, data interface{}) { + funcMap := template.FuncMap{ + "join": strings.Join, + } + w := tabwriter.NewWriter(a.Writer, 0, 8, 1, '\t', 0) - t := template.Must(template.New("help").Parse(templ)) + t := template.Must(template.New("help").Funcs(funcMap).Parse(templ)) err := t.Execute(w, data) if err != nil { panic(err) diff --git a/app_test.go b/app_test.go index 6143d36..4308669 100644 --- a/app_test.go +++ b/app_test.go @@ -29,41 +29,24 @@ func ExampleApp() { // Hello Jeremy } -func ExampleAppSubcommand() { +func ExampleAppCommands() { // set args for examples sake - os.Args = []string{"say", "hi", "english", "--name", "Jeremy"} - app := cli.NewApp() - app.Name = "say" - app.Commands = []cli.Command{ - { - Name: "hello", - ShortName: "hi", - Usage: "use it to see a description", - Description: "This is how we describe hello the function", - Subcommands: []cli.Command{ - { - Name: "english", - ShortName: "en", - Usage: "sends a greeting in english", - Description: "greets someone in english", - Flags: []cli.Flag{ - cli.StringFlag{ - Name: "name", - Value: "Bob", - Usage: "Name of the person to greet", - }, - }, - Action: func(c *cli.Context) { - fmt.Println("Hello,", c.String("name")) - }, - }, - }, - }, - } + os.Args = []string{"greet", "--name", "Jeremy"} + app := cli.NewApp() + app.Name = "greet" + app.Flags = []cli.Flag{ + cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"}, + } + app.Action = func(c *cli.Context) { + fmt.Printf("Hello %v\n", c.String("name")) + } + app.Author = "Harrison" + app.Email = "harrison@lolwut.com" + app.Authors = []cli.Author{{"Oliver Allen", "oliver@toyshop.com"}} app.Run(os.Args) // Output: - // Hello, Jeremy + // Hello Jeremy } func ExampleAppHelp() { @@ -78,7 +61,7 @@ func ExampleAppHelp() { app.Commands = []cli.Command{ { Name: "describeit", - ShortName: "d", + Aliases: []string{"d"}, Usage: "use it to see a description", Description: "This is how we describe describeit the function", Action: func(c *cli.Context) { @@ -108,7 +91,7 @@ func ExampleAppBashComplete() { app.Commands = []cli.Command{ { Name: "describeit", - ShortName: "d", + Aliases: []string{"d"}, Usage: "use it to see a description", Description: "This is how we describe describeit the function", Action: func(c *cli.Context) { @@ -162,8 +145,8 @@ var commandAppTests = []struct { func TestApp_Command(t *testing.T) { app := cli.NewApp() - fooCommand := cli.Command{Name: "foobar", ShortName: "f"} - batCommand := cli.Command{Name: "batbaz", ShortName: "b"} + fooCommand := cli.Command{Name: "foobar", Aliases: []string{"f"}} + batCommand := cli.Command{Name: "batbaz", Aliases: []string{"b"}} app.Commands = []cli.Command{ fooCommand, batCommand, diff --git a/cli_test.go b/cli_test.go index 879a793..8a8df97 100644 --- a/cli_test.go +++ b/cli_test.go @@ -12,17 +12,17 @@ func Example() { app.Usage = "task list on the command line" app.Commands = []cli.Command{ { - Name: "add", - ShortName: "a", - Usage: "add a task to the list", + Name: "add", + Aliases: []string{"a"}, + Usage: "add a task to the list", Action: func(c *cli.Context) { println("added task: ", c.Args().First()) }, }, { - Name: "complete", - ShortName: "c", - Usage: "complete a task on the list", + Name: "complete", + Aliases: []string{"c"}, + Usage: "complete a task on the list", Action: func(c *cli.Context) { println("completed task: ", c.Args().First()) }, @@ -38,13 +38,13 @@ func ExampleSubcommand() { app.Commands = []cli.Command{ { Name: "hello", - ShortName: "hi", + Aliases: []string{"hi"}, Usage: "use it to see a description", Description: "This is how we describe hello the function", Subcommands: []cli.Command{ { Name: "english", - ShortName: "en", + Aliases: []string{"en"}, Usage: "sends a greeting in english", Description: "greets someone in english", Flags: []cli.Flag{ @@ -58,9 +58,9 @@ func ExampleSubcommand() { println("Hello, ", c.String("name")) }, }, { - Name: "spanish", - ShortName: "sp", - Usage: "sends a greeting in spanish", + Name: "spanish", + Aliases: []string{"sp"}, + Usage: "sends a greeting in spanish", Flags: []cli.Flag{ cli.StringFlag{ Name: "surname", @@ -72,9 +72,9 @@ func ExampleSubcommand() { println("Hola, ", c.String("surname")) }, }, { - Name: "french", - ShortName: "fr", - Usage: "sends a greeting in french", + Name: "french", + Aliases: []string{"fr"}, + Usage: "sends a greeting in french", Flags: []cli.Flag{ cli.StringFlag{ Name: "nickname", diff --git a/command.go b/command.go index 07c919a..b61691c 100644 --- a/command.go +++ b/command.go @@ -10,8 +10,10 @@ import ( type Command struct { // The name of the command Name string - // short name of the command. Typically one character + // short name of the command. Typically one character (deprecated, use `Aliases`) ShortName string + // A list of aliases for the command + Aliases []string // A short description of the usage of this command Usage string // A longer explanation of how the command works @@ -117,9 +119,24 @@ func (c Command) Run(ctx *Context) error { return nil } +func (c Command) Names() []string { + names := []string{c.Name} + + if c.ShortName != "" { + names = append(names, c.ShortName) + } + + return append(names, c.Aliases...) +} + // Returns true if Command.Name or Command.ShortName matches given name func (c Command) HasName(name string) bool { - return c.Name == name || (c.ShortName != "" && c.ShortName == name) + for _, n := range c.Names() { + if n == name { + return true + } + } + return false } func (c Command) startApp(ctx *Context) error { diff --git a/command_test.go b/command_test.go index c0f556a..4125b0c 100644 --- a/command_test.go +++ b/command_test.go @@ -17,7 +17,7 @@ func TestCommandDoNotIgnoreFlags(t *testing.T) { command := cli.Command{ Name: "test-cmd", - ShortName: "tc", + Aliases: []string{"tc"}, Usage: "this is for testing", Description: "testing", Action: func(_ *cli.Context) {}, @@ -37,7 +37,7 @@ func TestCommandIgnoreFlags(t *testing.T) { command := cli.Command{ Name: "test-cmd", - ShortName: "tc", + Aliases: []string{"tc"}, Usage: "this is for testing", Description: "testing", Action: func(_ *cli.Context) {}, diff --git a/help.go b/help.go index 8d17655..17465d7 100644 --- a/help.go +++ b/help.go @@ -18,7 +18,7 @@ AUTHOR(S): {{range .Authors}}{{ . }} {{end}} COMMANDS: - {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} + {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} {{end}}{{if .Flags}} GLOBAL OPTIONS: {{range .Flags}}{{.}} @@ -52,7 +52,7 @@ USAGE: {{.Name}} command{{if .Flags}} [command options]{{end}} [arguments...] COMMANDS: - {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} + {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} {{end}}{{if .Flags}} OPTIONS: {{range .Flags}}{{.}} @@ -60,9 +60,9 @@ OPTIONS: ` var helpCommand = Command{ - Name: "help", - ShortName: "h", - Usage: "Shows a list of commands or help for one command", + Name: "help", + Aliases: []string{"h"}, + Usage: "Shows a list of commands or help for one command", Action: func(c *Context) { args := c.Args() if args.Present() { @@ -74,9 +74,9 @@ var helpCommand = Command{ } var helpSubcommand = Command{ - Name: "help", - ShortName: "h", - Usage: "Shows a list of commands or help for one command", + Name: "help", + Aliases: []string{"h"}, + Usage: "Shows a list of commands or help for one command", Action: func(c *Context) { args := c.Args() if args.Present() { @@ -102,9 +102,8 @@ func ShowAppHelp(c *Context) { // Prints the list of subcommands as the default app completion method func DefaultAppComplete(c *Context) { for _, command := range c.App.Commands { - fmt.Fprintln(c.App.Writer, command.Name) - if command.ShortName != "" { - fmt.Fprintln(c.App.Writer, command.ShortName) + for _, name := range command.Names() { + fmt.Fprintln(c.App.Writer, name) } } } From 474646abed5582b4f4265ffadb1ed1625fa6f114 Mon Sep 17 00:00:00 2001 From: jszwedko Date: Mon, 16 Mar 2015 18:04:57 -0700 Subject: [PATCH 2/3] Didn't mean to remove ExampleAppSubcommand Also specify struct field initializers --- app_test.go | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/app_test.go b/app_test.go index 4308669..2e5cdfb 100644 --- a/app_test.go +++ b/app_test.go @@ -23,12 +23,49 @@ func ExampleApp() { } app.Author = "Harrison" app.Email = "harrison@lolwut.com" - app.Authors = []cli.Author{{"Oliver Allen", "oliver@toyshop.com"}} + app.Authors = []cli.Author{cli.Author{Name: "Oliver Allen", Email: "oliver@toyshop.com"}} app.Run(os.Args) // Output: // Hello Jeremy } +func ExampleAppSubcommand() { + // set args for examples sake + os.Args = []string{"say", "hi", "english", "--name", "Jeremy"} + app := cli.NewApp() + app.Name = "say" + app.Commands = []cli.Command{ + { + Name: "hello", + Aliases: []string{"hi"}, + Usage: "use it to see a description", + Description: "This is how we describe hello the function", + Subcommands: []cli.Command{ + { + Name: "english", + Aliases: []string{"en"}, + Usage: "sends a greeting in english", + Description: "greets someone in english", + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "name", + Value: "Bob", + Usage: "Name of the person to greet", + }, + }, + Action: func(c *cli.Context) { + fmt.Println("Hello,", c.String("name")) + }, + }, + }, + }, + } + + app.Run(os.Args) + // Output: + // Hello, Jeremy +} + func ExampleAppCommands() { // set args for examples sake os.Args = []string{"greet", "--name", "Jeremy"} @@ -43,7 +80,6 @@ func ExampleAppCommands() { } app.Author = "Harrison" app.Email = "harrison@lolwut.com" - app.Authors = []cli.Author{{"Oliver Allen", "oliver@toyshop.com"}} app.Run(os.Args) // Output: // Hello Jeremy From daad50e530f8799aa8ef8e670130ed53fa83dca1 Mon Sep 17 00:00:00 2001 From: jszwedko Date: Mon, 16 Mar 2015 18:48:06 -0700 Subject: [PATCH 3/3] Turns out I didn't mean to add ExampleAppCommands at all --- app_test.go | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/app_test.go b/app_test.go index 2e5cdfb..4a40b89 100644 --- a/app_test.go +++ b/app_test.go @@ -66,25 +66,6 @@ func ExampleAppSubcommand() { // Hello, Jeremy } -func ExampleAppCommands() { - // set args for examples sake - os.Args = []string{"greet", "--name", "Jeremy"} - - app := cli.NewApp() - app.Name = "greet" - app.Flags = []cli.Flag{ - cli.StringFlag{Name: "name", Value: "bob", Usage: "a name to say"}, - } - app.Action = func(c *cli.Context) { - fmt.Printf("Hello %v\n", c.String("name")) - } - app.Author = "Harrison" - app.Email = "harrison@lolwut.com" - app.Run(os.Args) - // Output: - // Hello Jeremy -} - func ExampleAppHelp() { // set args for examples sake os.Args = []string{"greet", "h", "describeit"}