From bcfb32b8b0ea078afdd72bed4de03ccd59bea40d Mon Sep 17 00:00:00 2001 From: jszwedko Date: Fri, 11 Jul 2014 18:16:19 -0400 Subject: [PATCH 1/9] Updating tests to pass `go vet` Mostly lack of struct field names in literals and one sprintf format specifier mismatch. --- app_test.go | 6 +++--- cli_test.go | 9 +++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app_test.go b/app_test.go index cf0e3d0..9414c1b 100644 --- a/app_test.go +++ b/app_test.go @@ -43,7 +43,7 @@ func ExampleAppSubcommand() { Usage: "sends a greeting in english", Description: "greets someone in english", Flags: []cli.Flag{ - cli.StringFlag{"name", "Bob", "Name of the person to greet"}, + cli.StringFlag{Name: "name", Value: "Bob", Usage: "Name of the person to greet"}, }, Action: func(c *cli.Context) { fmt.Println("Hello,", c.String("name")) @@ -255,11 +255,11 @@ func TestApp_ParseSliceFlags(t *testing.T) { var expectedStringSlice = []string{"8.8.8.8", "8.8.4.4"} if !IntsEquals(parsedIntSlice, expectedIntSlice) { - t.Errorf("%s does not match %s", parsedIntSlice, expectedIntSlice) + t.Errorf("%v does not match %v", parsedIntSlice, expectedIntSlice) } if !StrsEquals(parsedStringSlice, expectedStringSlice) { - t.Errorf("%s does not match %s", parsedStringSlice, expectedStringSlice) + t.Errorf("%v does not match %v", parsedStringSlice, expectedStringSlice) } } diff --git a/cli_test.go b/cli_test.go index 30f3c13..4d7bd84 100644 --- a/cli_test.go +++ b/cli_test.go @@ -1,8 +1,9 @@ package cli_test import ( - "github.com/codegangsta/cli" "os" + + "github.com/codegangsta/cli" ) func Example() { @@ -47,7 +48,7 @@ func ExampleSubcommand() { Usage: "sends a greeting in english", Description: "greets someone in english", Flags: []cli.Flag{ - cli.StringFlag{"name", "Bob", "Name of the person to greet"}, + cli.StringFlag{Name: "name", Value: "Bob", Usage: "Name of the person to greet"}, }, Action: func(c *cli.Context) { println("Hello, ", c.String("name")) @@ -57,7 +58,7 @@ func ExampleSubcommand() { ShortName: "sp", Usage: "sends a greeting in spanish", Flags: []cli.Flag{ - cli.StringFlag{"surname", "Jones", "Surname of the person to greet"}, + cli.StringFlag{Name: "surname", Value: "Jones", Usage: "Surname of the person to greet"}, }, Action: func(c *cli.Context) { println("Hola, ", c.String("surname")) @@ -67,7 +68,7 @@ func ExampleSubcommand() { ShortName: "fr", Usage: "sends a greeting in french", Flags: []cli.Flag{ - cli.StringFlag{"nickname", "Stevie", "Nickname of the person to greet"}, + cli.StringFlag{Name: "nickname", Value: "Stevie", Usage: "Nickname of the person to greet"}, }, Action: func(c *cli.Context) { println("Bonjour, ", c.String("nickname")) From c99454b374ae684d01fb654b41d82c2c2584a38d Mon Sep 17 00:00:00 2001 From: jszwedko Date: Fri, 11 Jul 2014 18:17:30 -0400 Subject: [PATCH 2/9] Adding struct field names to examples in README Idiomatic Go --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4621310..59806f4 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ Setting and querying flags is simple. ``` go ... app.Flags = []cli.Flag { - cli.StringFlag{"lang", "english", "language for the greeting"}, + cli.StringFlag{Name: "lang", Value: "english", Usage: "language for the greeting"}, } app.Action = func(c *cli.Context) { name := "someone" @@ -159,7 +159,7 @@ You can set alternate (or short) names for flags by providing a comma-delimited ``` go app.Flags = []cli.Flag { - cli.StringFlag{"lang, l", "english", "language for the greeting"}, + cli.StringFlag{Name: "lang, l", Value: "english", Usage: "language for the greeting"}, } ``` From 4a645835f0602f2d510484e5baae8595bbb442c3 Mon Sep 17 00:00:00 2001 From: Audrius Butkevicius Date: Sun, 13 Jul 2014 14:16:30 +0100 Subject: [PATCH 3/9] Add HideHelp flag in App and Command --- app.go | 10 ++++++---- command.go | 15 ++++++++++----- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/app.go b/app.go index 9ba043e..a4e3ff7 100644 --- a/app.go +++ b/app.go @@ -22,6 +22,8 @@ type App struct { Flags []Flag // Boolean to enable bash completion commands EnableBashCompletion bool + // Boolean to hide built-in help command + HideHelp bool // An action to execute when the bash-completion flag is set BashComplete func(context *Context) // An action to execute before any subcommands are run, but after the context is ready @@ -66,8 +68,9 @@ func NewApp() *App { // Entry point to the cli app. Parses the arguments slice and routes to the proper flag/args combination func (a *App) Run(arguments []string) error { // append help to commands - if a.Command(helpCommand.Name) == nil { + if a.Command(helpCommand.Name) == nil && !a.HideHelp { a.Commands = append(a.Commands, helpCommand) + a.appendFlag(HelpFlag) } //append version/help flags @@ -75,7 +78,6 @@ func (a *App) Run(arguments []string) error { a.appendFlag(BashCompletionFlag) } a.appendFlag(VersionFlag) - a.appendFlag(HelpFlag) // parse flags set := flagSet(a.Name, a.Flags) @@ -135,8 +137,9 @@ func (a *App) Run(arguments []string) error { func (a *App) RunAsSubcommand(ctx *Context) error { // append help to commands if len(a.Commands) > 0 { - if a.Command(helpCommand.Name) == nil { + if a.Command(helpCommand.Name) == nil && !a.HideHelp { a.Commands = append(a.Commands, helpCommand) + a.appendFlag(HelpFlag) } } @@ -144,7 +147,6 @@ func (a *App) RunAsSubcommand(ctx *Context) error { if a.EnableBashCompletion { a.appendFlag(BashCompletionFlag) } - a.appendFlag(HelpFlag) // parse flags set := flagSet(a.Name, a.Flags) diff --git a/command.go b/command.go index 9d8fff4..dcc8de5 100644 --- a/command.go +++ b/command.go @@ -29,6 +29,8 @@ type Command struct { Flags []Flag // Treat all flags as normal arguments if true SkipFlagParsing bool + // Boolean to hide built-in help command + HideHelp bool } // Invokes the command given the context, parses ctx.Args() to generate command-specific flags @@ -38,11 +40,13 @@ func (c Command) Run(ctx *Context) error { return c.startApp(ctx) } - // append help to flags - c.Flags = append( - c.Flags, - HelpFlag, - ) + if !c.HideHelp { + // append help to flags + c.Flags = append( + c.Flags, + HelpFlag, + ) + } if ctx.App.EnableBashCompletion { c.Flags = append(c.Flags, BashCompletionFlag) @@ -117,6 +121,7 @@ func (c Command) startApp(ctx *Context) error { // set the flags and commands app.Commands = c.Subcommands app.Flags = c.Flags + app.HideHelp = c.HideHelp // bash completion app.EnableBashCompletion = ctx.App.EnableBashCompletion From d6d4e6448b03fcbff51263649b9b5a012acac650 Mon Sep 17 00:00:00 2001 From: Audrius Butkevicius Date: Sun, 13 Jul 2014 14:27:44 +0100 Subject: [PATCH 4/9] Hide "Options" sections in help, if no flags are defined --- help.go | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/help.go b/help.go index 7c04005..845e805 100644 --- a/help.go +++ b/help.go @@ -14,17 +14,17 @@ var AppHelpTemplate = `NAME: {{.Name}} - {{.Usage}} USAGE: - {{.Name}} [global options] command [command options] [arguments...] + {{.Name}} {{ if .Flags }}[global options] {{ end }}command{{ if .Flags }} [command options]{{ end }} [arguments...] VERSION: {{.Version}} COMMANDS: {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} - {{end}} + {{end}}{{ if .Flags }} GLOBAL OPTIONS: {{range .Flags}}{{.}} - {{end}} + {{end}}{{ end }} ` // The text template for the command help topic. @@ -34,14 +34,14 @@ var CommandHelpTemplate = `NAME: {{.Name}} - {{.Usage}} USAGE: - command {{.Name}} [command options] [arguments...] + command {{.Name}}{{ if .Flags }} [command options]{{ end }} [arguments...] DESCRIPTION: - {{.Description}} + {{.Description}}{{ if .Flags }} OPTIONS: {{range .Flags}}{{.}} - {{end}} + {{end}}{{ end }} ` // The text template for the subcommand help topic. @@ -51,14 +51,14 @@ var SubcommandHelpTemplate = `NAME: {{.Name}} - {{.Usage}} USAGE: - {{.Name}} [global options] command [command options] [arguments...] + {{.Name}} [global options] command{{ if .Flags }} [command options]{{ end }} [arguments...] COMMANDS: {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} - {{end}} + {{end}}{{ if .Flags }} OPTIONS: {{range .Flags}}{{.}} - {{end}} + {{end}}{{ end }} ` var helpCommand = Command{ From bc02933ea4b153fe92a4517a2891b084fa479141 Mon Sep 17 00:00:00 2001 From: Audrius Butkevicius Date: Sun, 13 Jul 2014 14:29:30 +0100 Subject: [PATCH 5/9] Fix Subcommand help text --- help.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/help.go b/help.go index 845e805..ccca036 100644 --- a/help.go +++ b/help.go @@ -51,7 +51,7 @@ var SubcommandHelpTemplate = `NAME: {{.Name}} - {{.Usage}} USAGE: - {{.Name}} [global options] command{{ if .Flags }} [command options]{{ end }} [arguments...] + {{.Name}} command{{ if .Flags }} [command options]{{ end }} [arguments...] COMMANDS: {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} From 9e036e08f164beaa5062c6ff959ceecd88709459 Mon Sep 17 00:00:00 2001 From: Audrius Butkevicius Date: Sun, 13 Jul 2014 18:52:30 +0100 Subject: [PATCH 6/9] Fix tests --- app_test.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app_test.go b/app_test.go index 9414c1b..a915624 100644 --- a/app_test.go +++ b/app_test.go @@ -84,12 +84,10 @@ func ExampleAppHelp() { // describeit - use it to see a description // // USAGE: - // command describeit [command options] [arguments...] + // command describeit [arguments...] // // DESCRIPTION: // This is how we describe describeit the function - // - // OPTIONS: } func ExampleAppBashComplete() { From 6f8cfa703a6b5eabeef4b957d14cfc200a16c908 Mon Sep 17 00:00:00 2001 From: Audrius Butkevicius Date: Sun, 13 Jul 2014 15:18:45 +0100 Subject: [PATCH 7/9] Add Args.Swap command for swapping arguments The usecase: my-cli user set Being able to swap with set argument, we can have nested subcommands while preserving all variable arguments along the way. --- context.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/context.go b/context.go index b2c51bb..1e023ce 100644 --- a/context.go +++ b/context.go @@ -140,6 +140,15 @@ func (a Args) Present() bool { return len(a) != 0 } +// Swaps arguments at the given indexes +func (a Args) Swap(from, to int) error { + if from >= len(a) || to >= len(a) { + return errors.New("index out of range") + } + a[from], a[to] = a[to], a[from] + return nil +} + func lookupInt(name string, set *flag.FlagSet) int { f := set.Lookup(name) if f != nil { From 449f261ee9faccc374c97ed04bb58def80ac34ed Mon Sep 17 00:00:00 2001 From: Audrius Butkevicius Date: Sun, 13 Jul 2014 17:26:20 +0100 Subject: [PATCH 8/9] Add App.RunAndExitOnError shortcut --- app.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app.go b/app.go index 9ba043e..2f4bd34 100644 --- a/app.go +++ b/app.go @@ -131,6 +131,14 @@ func (a *App) Run(arguments []string) error { return nil } +// Another entry point to the cli app, takes care of passing arguments and error handling +func (a *App) RunAndExitOnError() { + if err := a.Run(os.Args); err != nil { + os.Stderr.WriteString(fmt.Sprintln(err)) + os.Exit(1) + } +} + // Invokes the subcommand given the context, parses ctx.Args() to generate command-specific flags func (a *App) RunAsSubcommand(ctx *Context) error { // append help to commands From 9e5f47524bd6569c08a45b2f07657e19cdcd2b87 Mon Sep 17 00:00:00 2001 From: jszwedko Date: Mon, 14 Jul 2014 13:48:52 -0400 Subject: [PATCH 9/9] Run `go vet` as part of Travis build --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 2379c61..baf46ab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,2 +1,6 @@ language: go go: 1.1 + +script: +- go vet ./... +- go test -v ./...