From 2726643347a6dfbed620bc0e87857b26a2178b53 Mon Sep 17 00:00:00 2001 From: Peter Olds Date: Tue, 9 Jun 2015 16:35:50 -0600 Subject: [PATCH 1/9] Add the ability to add a copyright Signed-off-by: Peter Olds --- app.go | 2 ++ help.go | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app.go b/app.go index 891416d2a5..a1cf6e1ed4 100644 --- a/app.go +++ b/app.go @@ -43,6 +43,8 @@ type App struct { Compiled time.Time // List of all authors who contributed Authors []Author + // Copyright of the binary if any + Copyright string // Name of Author (Note: Use App.Authors, this is deprecated) Author string // Email of Author (Note: Use App.Authors, this is deprecated) diff --git a/help.go b/help.go index 1117945f0e..906fe7c2a8 100644 --- a/help.go +++ b/help.go @@ -28,7 +28,10 @@ COMMANDS: {{end}}{{if .Flags}} GLOBAL OPTIONS: {{range .Flags}}{{.}} - {{end}}{{end}} + {{end}}{{end}}{{if .Copyright }} +COPYRIGHT: + {{.Copyright}}{{end}} + ` // The text template for the command help topic. From 4a11a6ba052ebb4c831741a506ad7eaa8e20e3b2 Mon Sep 17 00:00:00 2001 From: Peter Olds Date: Tue, 16 Jun 2015 15:23:29 -0600 Subject: [PATCH 2/9] Remove whitespace #238 Signed-off-by: Peter Olds --- help.go | 1 - 1 file changed, 1 deletion(-) diff --git a/help.go b/help.go index 906fe7c2a8..8e362e888e 100644 --- a/help.go +++ b/help.go @@ -31,7 +31,6 @@ GLOBAL OPTIONS: {{end}}{{end}}{{if .Copyright }} COPYRIGHT: {{.Copyright}}{{end}} - ` // The text template for the command help topic. From 15e6b2fcc755130371d60193cc6d04b50ef9d546 Mon Sep 17 00:00:00 2001 From: Brian Goff Date: Fri, 19 Jun 2015 17:06:04 -0400 Subject: [PATCH 3/9] Add func to get context parent Signed-off-by: Brian Goff --- context.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/context.go b/context.go index 5b67129f0a..c75607eef4 100644 --- a/context.go +++ b/context.go @@ -180,6 +180,11 @@ func (c *Context) GlobalFlagNames() (names []string) { return } +// Returns the parent context, if any +func (c *Context) Parent() *Context { + return c.parentContext +} + type Args []string // Returns the command line arguments associated with the context. From ee2cde7a77216d0c9eb00a39c7836ed4f5ec662f Mon Sep 17 00:00:00 2001 From: Martin Falatic Date: Wed, 24 Jun 2015 22:46:33 -0700 Subject: [PATCH 4/9] Print blank lines in help and error outputs more consistently. --- app.go | 10 +++++----- command.go | 5 ++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/app.go b/app.go index ac6700d0b9..e7caec99bd 100644 --- a/app.go +++ b/app.go @@ -108,15 +108,14 @@ func (a *App) Run(arguments []string) (err error) { fmt.Fprintln(a.Writer, nerr) context := NewContext(a, set, nil) ShowAppHelp(context) - fmt.Fprintln(a.Writer) return nerr } context := NewContext(a, set, nil) if err != nil { - fmt.Fprintf(a.Writer, "Incorrect Usage.\n\n") - ShowAppHelp(context) + fmt.Fprintln(a.Writer, "Incorrect Usage.") fmt.Fprintln(a.Writer) + ShowAppHelp(context) return err } @@ -200,17 +199,18 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) { if nerr != nil { fmt.Fprintln(a.Writer, nerr) + fmt.Fprintln(a.Writer) if len(a.Commands) > 0 { ShowSubcommandHelp(context) } else { ShowCommandHelp(ctx, context.Args().First()) } - fmt.Fprintln(a.Writer) return nerr } if err != nil { - fmt.Fprintf(a.Writer, "Incorrect Usage.\n\n") + fmt.Fprintln(a.Writer, "Incorrect Usage.") + fmt.Fprintln(a.Writer) ShowSubcommandHelp(context) return err } diff --git a/command.go b/command.go index b721c0af22..212f128b94 100644 --- a/command.go +++ b/command.go @@ -91,9 +91,9 @@ func (c Command) Run(ctx *Context) error { } if err != nil { - fmt.Fprint(ctx.App.Writer, "Incorrect Usage.\n\n") - ShowCommandHelp(ctx, c.Name) + fmt.Fprintln(ctx.App.Writer, "Incorrect Usage.") fmt.Fprintln(ctx.App.Writer) + ShowCommandHelp(ctx, c.Name) return err } @@ -102,7 +102,6 @@ func (c Command) Run(ctx *Context) error { fmt.Fprintln(ctx.App.Writer, nerr) fmt.Fprintln(ctx.App.Writer) ShowCommandHelp(ctx, c.Name) - fmt.Fprintln(ctx.App.Writer) return nerr } context := NewContext(ctx.App, set, ctx) From 595c055010bb8321f1a054c155ddc19ce8ae5910 Mon Sep 17 00:00:00 2001 From: Martin Falatic Date: Wed, 24 Jun 2015 23:07:32 -0700 Subject: [PATCH 5/9] If Version is an empty string, suppress version output in usage help. --- help.go | 4 ++-- help_test.go | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/help.go b/help.go index ef362f6123..c80636a671 100644 --- a/help.go +++ b/help.go @@ -15,10 +15,10 @@ var AppHelpTemplate = `NAME: {{.Name}} - {{.Usage}} USAGE: - {{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...] + {{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...]{{if len .Version}} VERSION: - {{.Version}}{{if len .Authors}} + {{.Version}}{{end}}{{if len .Authors}} AUTHOR(S): {{range .Authors}}{{ . }}{{end}}{{end}} diff --git a/help_test.go b/help_test.go index b3c1fda69e..bff931f1fe 100644 --- a/help_test.go +++ b/help_test.go @@ -20,3 +20,17 @@ func Test_ShowAppHelp_NoAuthor(t *testing.T) { t.Errorf("expected\n%snot to include %s", output.String(), "AUTHOR(S):") } } + +func Test_ShowAppHelp_NoVersion(t *testing.T) { + output := new(bytes.Buffer) + app := cli.NewApp() + app.Writer = output + + c := cli.NewContext(app, nil, nil) + + cli.ShowAppHelp(c) + + if bytes.Index(output.Bytes(), []byte("VERSION:")) != -1 { + t.Errorf("expected\n%snot to include %s", output.String(), "VERSION:") + } +} From dbde3303cf0ee27c8c2ec99089b19f257d1056bf Mon Sep 17 00:00:00 2001 From: Martin Falatic Date: Wed, 24 Jun 2015 23:11:59 -0700 Subject: [PATCH 6/9] Test updated --- help_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/help_test.go b/help_test.go index bff931f1fe..c85f957720 100644 --- a/help_test.go +++ b/help_test.go @@ -26,6 +26,8 @@ func Test_ShowAppHelp_NoVersion(t *testing.T) { app := cli.NewApp() app.Writer = output + app.Version = "" + c := cli.NewContext(app, nil, nil) cli.ShowAppHelp(c) From 4d3820c145448b83214c1d951b82791cbc93a023 Mon Sep 17 00:00:00 2001 From: Martin Falatic Date: Thu, 25 Jun 2015 01:30:54 -0700 Subject: [PATCH 7/9] If there are no commands, don't show Commands section. Also fixed Copyright section formatting. --- help.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/help.go b/help.go index c80636a671..7148c19579 100644 --- a/help.go +++ b/help.go @@ -21,14 +21,16 @@ VERSION: {{.Version}}{{end}}{{if len .Authors}} AUTHOR(S): - {{range .Authors}}{{ . }}{{end}}{{end}} + {{range .Authors}}{{ . }}{{end}}{{end}}{{if .Commands}} COMMANDS: {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} - {{end}}{{if .Flags}} + {{end}}{{end}}{{if .Flags}} + GLOBAL OPTIONS: {{range .Flags}}{{.}} {{end}}{{end}}{{if .Copyright }} + COPYRIGHT: {{.Copyright}}{{end}} ` From 8cae4991af6e8b3312601375a1709e56ea7fb018 Mon Sep 17 00:00:00 2001 From: Martin Falatic Date: Thu, 25 Jun 2015 01:53:32 -0700 Subject: [PATCH 8/9] Fixing more formatting --- help.go | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/help.go b/help.go index 7148c19579..e2cf82ebeb 100644 --- a/help.go +++ b/help.go @@ -15,24 +15,23 @@ var AppHelpTemplate = `NAME: {{.Name}} - {{.Usage}} USAGE: - {{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...]{{if len .Version}} - + {{.Name}} {{if .Flags}}[global options]{{end}}{{if .Commands}} command [command options]{{end}} [arguments...] + {{if .Version}} VERSION: - {{.Version}}{{end}}{{if len .Authors}} - + {{.Version}} + {{end}}{{if len .Authors}} AUTHOR(S): - {{range .Authors}}{{ . }}{{end}}{{end}}{{if .Commands}} - + {{range .Authors}}{{ . }}{{end}} + {{end}}{{if .Commands}} COMMANDS: {{range .Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} {{end}}{{end}}{{if .Flags}} - GLOBAL OPTIONS: {{range .Flags}}{{.}} {{end}}{{end}}{{if .Copyright }} - COPYRIGHT: - {{.Copyright}}{{end}} + {{.Copyright}} + {{end}} ` // The text template for the command help topic. From a2d4ae59392f39d8f02757647068405180572673 Mon Sep 17 00:00:00 2001 From: Fabian Ruff Date: Mon, 29 Jun 2015 23:20:27 +0200 Subject: [PATCH 9/9] Fix global flags processing on top level This fixes a regression introduced by #227. When looking up global flags by walking up the parent context's we need to consider the special case when we are starting at the very top and there is no parent context to start the traversal. Fixes #252 --- app_test.go | 17 +++++++++++++++++ context.go | 27 +++++++++++++++++---------- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/app_test.go b/app_test.go index 46ec33f9c9..b224d63e20 100644 --- a/app_test.go +++ b/app_test.go @@ -627,6 +627,23 @@ func TestAppCommandNotFound(t *testing.T) { expect(t, subcommandRun, false) } +func TestGlobalFlag(t *testing.T) { + var globalFlag string + var globalFlagSet bool + app := cli.NewApp() + app.Flags = []cli.Flag{ + cli.StringFlag{Name: "global, g", Usage: "global"}, + } + app.Action = func(c *cli.Context) { + globalFlag = c.GlobalString("global") + globalFlagSet = c.GlobalIsSet("global") + } + app.Run([]string{"command", "-g", "foo"}) + expect(t, globalFlag, "foo") + expect(t, globalFlagSet, true) + +} + func TestGlobalFlagsInSubcommands(t *testing.T) { subcommandRun := false parentFlag := false diff --git a/context.go b/context.go index c75607eef4..f541f41c3c 100644 --- a/context.go +++ b/context.go @@ -73,7 +73,7 @@ func (c *Context) Generic(name string) interface{} { // Looks up the value of a global int flag, returns 0 if no int flag exists func (c *Context) GlobalInt(name string) int { - if fs := lookupParentFlagSet(name, c); fs != nil { + if fs := lookupGlobalFlagSet(name, c); fs != nil { return lookupInt(name, fs) } return 0 @@ -81,7 +81,7 @@ func (c *Context) GlobalInt(name string) int { // Looks up the value of a global time.Duration flag, returns 0 if no time.Duration flag exists func (c *Context) GlobalDuration(name string) time.Duration { - if fs := lookupParentFlagSet(name, c); fs != nil { + if fs := lookupGlobalFlagSet(name, c); fs != nil { return lookupDuration(name, fs) } return 0 @@ -89,7 +89,7 @@ func (c *Context) GlobalDuration(name string) time.Duration { // Looks up the value of a global bool flag, returns false if no bool flag exists func (c *Context) GlobalBool(name string) bool { - if fs := lookupParentFlagSet(name, c); fs != nil { + if fs := lookupGlobalFlagSet(name, c); fs != nil { return lookupBool(name, fs) } return false @@ -97,7 +97,7 @@ func (c *Context) GlobalBool(name string) bool { // Looks up the value of a global string flag, returns "" if no string flag exists func (c *Context) GlobalString(name string) string { - if fs := lookupParentFlagSet(name, c); fs != nil { + if fs := lookupGlobalFlagSet(name, c); fs != nil { return lookupString(name, fs) } return "" @@ -105,7 +105,7 @@ func (c *Context) GlobalString(name string) string { // Looks up the value of a global string slice flag, returns nil if no string slice flag exists func (c *Context) GlobalStringSlice(name string) []string { - if fs := lookupParentFlagSet(name, c); fs != nil { + if fs := lookupGlobalFlagSet(name, c); fs != nil { return lookupStringSlice(name, fs) } return nil @@ -113,7 +113,7 @@ func (c *Context) GlobalStringSlice(name string) []string { // Looks up the value of a global int slice flag, returns nil if no int slice flag exists func (c *Context) GlobalIntSlice(name string) []int { - if fs := lookupParentFlagSet(name, c); fs != nil { + if fs := lookupGlobalFlagSet(name, c); fs != nil { return lookupIntSlice(name, fs) } return nil @@ -121,7 +121,7 @@ func (c *Context) GlobalIntSlice(name string) []int { // Looks up the value of a global generic flag, returns nil if no generic flag exists func (c *Context) GlobalGeneric(name string) interface{} { - if fs := lookupParentFlagSet(name, c); fs != nil { + if fs := lookupGlobalFlagSet(name, c); fs != nil { return lookupGeneric(name, fs) } return nil @@ -147,7 +147,11 @@ func (c *Context) IsSet(name string) bool { func (c *Context) GlobalIsSet(name string) bool { if c.globalSetFlags == nil { c.globalSetFlags = make(map[string]bool) - for ctx := c.parentContext; ctx != nil && c.globalSetFlags[name] == false; ctx = ctx.parentContext { + ctx := c + if ctx.parentContext != nil { + ctx = ctx.parentContext + } + for ; ctx != nil && c.globalSetFlags[name] == false; ctx = ctx.parentContext { ctx.flagSet.Visit(func(f *flag.Flag) { c.globalSetFlags[f.Name] = true }) @@ -229,8 +233,11 @@ func (a Args) Swap(from, to int) error { return nil } -func lookupParentFlagSet(name string, ctx *Context) *flag.FlagSet { - for ctx := ctx.parentContext; ctx != nil; ctx = ctx.parentContext { +func lookupGlobalFlagSet(name string, ctx *Context) *flag.FlagSet { + if ctx.parentContext != nil { + ctx = ctx.parentContext + } + for ; ctx != nil; ctx = ctx.parentContext { if f := ctx.flagSet.Lookup(name); f != nil { return ctx.flagSet }