Merge pull request #401 from mattfarina/cleanup

Code cleanup from Go Report Card
This commit is contained in:
Dan Buch 2016-05-09 10:45:19 -04:00
commit 1d47addf28
12 changed files with 146 additions and 110 deletions

27
app.go
View File

@ -51,7 +51,7 @@ type App struct {
HideHelp bool HideHelp bool
// Boolean to hide built-in version flag and the VERSION section of help // Boolean to hide built-in version flag and the VERSION section of help
HideVersion bool HideVersion bool
// Populate on app startup, only gettable throught method Categories() // Populate on app startup, only gettable through method Categories()
categories CommandCategories categories CommandCategories
// An action to execute when the bash-completion flag is set // An action to execute when the bash-completion flag is set
BashComplete BashCompleteFunc BashComplete BashCompleteFunc
@ -100,7 +100,8 @@ func compileTime() time.Time {
return info.ModTime() return info.ModTime()
} }
// Creates a new cli Application with some reasonable defaults for Name, Usage, Version and Action. // NewApp creates a new cli Application with some reasonable defaults for Name,
// Usage, Version and Action.
func NewApp() *App { func NewApp() *App {
return &App{ return &App{
Name: filepath.Base(os.Args[0]), Name: filepath.Base(os.Args[0]),
@ -162,7 +163,8 @@ func (a *App) Setup() {
} }
} }
// Entry point to the cli app. Parses the arguments slice and routes to the proper flag/args combination // Run is the entry point to the cli app. Parses the arguments slice and routes
// to the proper flag/args combination
func (a *App) Run(arguments []string) (err error) { func (a *App) Run(arguments []string) (err error) {
a.Setup() a.Setup()
@ -187,11 +189,10 @@ func (a *App) Run(arguments []string) (err error) {
err := a.OnUsageError(context, err, false) err := a.OnUsageError(context, err, false)
HandleExitCoder(err) HandleExitCoder(err)
return err return err
} else {
fmt.Fprintf(a.Writer, "%s\n\n", "Incorrect Usage.")
ShowAppHelp(context)
return err
} }
fmt.Fprintf(a.Writer, "%s\n\n", "Incorrect Usage.")
ShowAppHelp(context)
return err
} }
if !a.HideHelp && checkHelp(context) { if !a.HideHelp && checkHelp(context) {
@ -254,7 +255,8 @@ func (a *App) RunAndExitOnError() {
} }
} }
// Invokes the subcommand given the context, parses ctx.Args() to generate command-specific flags // RunAsSubcommand invokes the subcommand given the context, parses ctx.Args() to
// generate command-specific flags
func (a *App) RunAsSubcommand(ctx *Context) (err error) { func (a *App) RunAsSubcommand(ctx *Context) (err error) {
// append help to commands // append help to commands
if len(a.Commands) > 0 { if len(a.Commands) > 0 {
@ -307,11 +309,10 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
err = a.OnUsageError(context, err, true) err = a.OnUsageError(context, err, true)
HandleExitCoder(err) HandleExitCoder(err)
return err return err
} else {
fmt.Fprintf(a.Writer, "%s\n\n", "Incorrect Usage.")
ShowSubcommandHelp(context)
return err
} }
fmt.Fprintf(a.Writer, "%s\n\n", "Incorrect Usage.")
ShowSubcommandHelp(context)
return err
} }
if len(a.Commands) > 0 { if len(a.Commands) > 0 {
@ -363,7 +364,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
return err return err
} }
// Returns the named command on App. Returns nil if the command does not exist // Command returns the named command on App. Returns nil if the command does not exist
func (a *App) Command(name string) *Command { func (a *App) Command(name string) *Command {
for _, c := range a.Commands { for _, c := range a.Commands {
if c.HasName(name) { if c.HasName(name) {

View File

@ -33,7 +33,7 @@ func ExampleApp_Run() {
app.UsageText = "app [first_arg] [second_arg]" app.UsageText = "app [first_arg] [second_arg]"
app.Author = "Harrison" app.Author = "Harrison"
app.Email = "harrison@lolwut.com" app.Email = "harrison@lolwut.com"
app.Authors = []Author{Author{Name: "Oliver Allen", Email: "oliver@toyshop.com"}} app.Authors = []Author{{Name: "Oliver Allen", Email: "oliver@toyshop.com"}}
app.Run(os.Args) app.Run(os.Args)
// Output: // Output:
// Hello Jeremy // Hello Jeremy
@ -307,12 +307,12 @@ func TestApp_CommandWithNoFlagBeforeTerminator(t *testing.T) {
func TestApp_VisibleCommands(t *testing.T) { func TestApp_VisibleCommands(t *testing.T) {
app := NewApp() app := NewApp()
app.Commands = []Command{ app.Commands = []Command{
Command{ {
Name: "frob", Name: "frob",
HelpName: "foo frob", HelpName: "foo frob",
Action: func(_ *Context) error { return nil }, Action: func(_ *Context) error { return nil },
}, },
Command{ {
Name: "frib", Name: "frib",
HelpName: "foo frib", HelpName: "foo frib",
Hidden: true, Hidden: true,
@ -517,7 +517,7 @@ func TestApp_BeforeFunc(t *testing.T) {
} }
app.Commands = []Command{ app.Commands = []Command{
Command{ {
Name: "sub", Name: "sub",
Action: func(c *Context) error { Action: func(c *Context) error {
counts.Total++ counts.Total++
@ -609,7 +609,7 @@ func TestApp_AfterFunc(t *testing.T) {
} }
app.Commands = []Command{ app.Commands = []Command{
Command{ {
Name: "sub", Name: "sub",
Action: func(c *Context) error { Action: func(c *Context) error {
counts.Total++ counts.Total++
@ -724,7 +724,7 @@ func TestApp_CommandNotFound(t *testing.T) {
} }
app.Commands = []Command{ app.Commands = []Command{
Command{ {
Name: "bar", Name: "bar",
Action: func(c *Context) error { Action: func(c *Context) error {
counts.Total++ counts.Total++
@ -791,7 +791,7 @@ func TestApp_OrderOfOperations(t *testing.T) {
app.After = afterNoError app.After = afterNoError
app.Commands = []Command{ app.Commands = []Command{
Command{ {
Name: "bar", Name: "bar",
Action: func(c *Context) error { Action: func(c *Context) error {
counts.Total++ counts.Total++
@ -1126,15 +1126,15 @@ func TestApp_Run_Categories(t *testing.T) {
app := NewApp() app := NewApp()
app.Name = "categories" app.Name = "categories"
app.Commands = []Command{ app.Commands = []Command{
Command{ {
Name: "command1", Name: "command1",
Category: "1", Category: "1",
}, },
Command{ {
Name: "command2", Name: "command2",
Category: "1", Category: "1",
}, },
Command{ {
Name: "command3", Name: "command3",
Category: "2", Category: "2",
}, },
@ -1175,18 +1175,18 @@ func TestApp_VisibleCategories(t *testing.T) {
app := NewApp() app := NewApp()
app.Name = "visible-categories" app.Name = "visible-categories"
app.Commands = []Command{ app.Commands = []Command{
Command{ {
Name: "command1", Name: "command1",
Category: "1", Category: "1",
HelpName: "foo command1", HelpName: "foo command1",
Hidden: true, Hidden: true,
}, },
Command{ {
Name: "command2", Name: "command2",
Category: "2", Category: "2",
HelpName: "foo command2", HelpName: "foo command2",
}, },
Command{ {
Name: "command3", Name: "command3",
Category: "3", Category: "3",
HelpName: "foo command3", HelpName: "foo command3",
@ -1194,13 +1194,13 @@ func TestApp_VisibleCategories(t *testing.T) {
} }
expected := []*CommandCategory{ expected := []*CommandCategory{
&CommandCategory{ {
Name: "2", Name: "2",
Commands: []Command{ Commands: []Command{
app.Commands[1], app.Commands[1],
}, },
}, },
&CommandCategory{ {
Name: "3", Name: "3",
Commands: []Command{ Commands: []Command{
app.Commands[2], app.Commands[2],
@ -1214,19 +1214,19 @@ func TestApp_VisibleCategories(t *testing.T) {
app = NewApp() app = NewApp()
app.Name = "visible-categories" app.Name = "visible-categories"
app.Commands = []Command{ app.Commands = []Command{
Command{ {
Name: "command1", Name: "command1",
Category: "1", Category: "1",
HelpName: "foo command1", HelpName: "foo command1",
Hidden: true, Hidden: true,
}, },
Command{ {
Name: "command2", Name: "command2",
Category: "2", Category: "2",
HelpName: "foo command2", HelpName: "foo command2",
Hidden: true, Hidden: true,
}, },
Command{ {
Name: "command3", Name: "command3",
Category: "3", Category: "3",
HelpName: "foo command3", HelpName: "foo command3",
@ -1234,7 +1234,7 @@ func TestApp_VisibleCategories(t *testing.T) {
} }
expected = []*CommandCategory{ expected = []*CommandCategory{
&CommandCategory{ {
Name: "3", Name: "3",
Commands: []Command{ Commands: []Command{
app.Commands[2], app.Commands[2],
@ -1248,19 +1248,19 @@ func TestApp_VisibleCategories(t *testing.T) {
app = NewApp() app = NewApp()
app.Name = "visible-categories" app.Name = "visible-categories"
app.Commands = []Command{ app.Commands = []Command{
Command{ {
Name: "command1", Name: "command1",
Category: "1", Category: "1",
HelpName: "foo command1", HelpName: "foo command1",
Hidden: true, Hidden: true,
}, },
Command{ {
Name: "command2", Name: "command2",
Category: "2", Category: "2",
HelpName: "foo command2", HelpName: "foo command2",
Hidden: true, Hidden: true,
}, },
Command{ {
Name: "command3", Name: "command3",
Category: "3", Category: "3",
HelpName: "foo command3", HelpName: "foo command3",
@ -1296,9 +1296,9 @@ func TestApp_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
func TestApp_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) { func TestApp_Run_SubcommandDoesNotOverwriteErrorFromBefore(t *testing.T) {
app := NewApp() app := NewApp()
app.Commands = []Command{ app.Commands = []Command{
Command{ {
Subcommands: []Command{ Subcommands: []Command{
Command{ {
Name: "sub", Name: "sub",
}, },
}, },
@ -1336,7 +1336,7 @@ func TestApp_OnUsageError_WithWrongFlagValue(t *testing.T) {
return errors.New("intercepted: " + err.Error()) return errors.New("intercepted: " + err.Error())
} }
app.Commands = []Command{ app.Commands = []Command{
Command{ {
Name: "bar", Name: "bar",
}, },
} }
@ -1366,7 +1366,7 @@ func TestApp_OnUsageError_WithWrongFlagValue_ForSubcommand(t *testing.T) {
return errors.New("intercepted: " + err.Error()) return errors.New("intercepted: " + err.Error())
} }
app.Commands = []Command{ app.Commands = []Command{
Command{ {
Name: "bar", Name: "bar",
}, },
} }

View File

@ -1,7 +1,9 @@
package cli package cli
// CommandCategories is a slice of *CommandCategory.
type CommandCategories []*CommandCategory type CommandCategories []*CommandCategory
// CommandCategory is a category containing commands.
type CommandCategory struct { type CommandCategory struct {
Name string Name string
Commands Commands Commands Commands
@ -19,6 +21,7 @@ func (c CommandCategories) Swap(i, j int) {
c[i], c[j] = c[j], c[i] c[i], c[j] = c[j], c[i]
} }
// AddCommand adds a command to a category.
func (c CommandCategories) AddCommand(category string, command Command) CommandCategories { func (c CommandCategories) AddCommand(category string, command Command) CommandCategories {
for _, commandCategory := range c { for _, commandCategory := range c {
if commandCategory.Name == category { if commandCategory.Name == category {

View File

@ -56,7 +56,7 @@ type Command struct {
commandNamePath []string commandNamePath []string
} }
// Returns the full name of the command. // FullName returns the full name of the command.
// For subcommands this ensures that parent commands are part of the command path // For subcommands this ensures that parent commands are part of the command path
func (c Command) FullName() string { func (c Command) FullName() string {
if c.commandNamePath == nil { if c.commandNamePath == nil {
@ -65,9 +65,10 @@ func (c Command) FullName() string {
return strings.Join(c.commandNamePath, " ") return strings.Join(c.commandNamePath, " ")
} }
// Commands is a slice of Command
type Commands []Command type Commands []Command
// Invokes the command given the context, parses ctx.Args() to generate command-specific flags // Run invokes the command given the context, parses ctx.Args() to generate command-specific flags
func (c Command) Run(ctx *Context) (err error) { func (c Command) Run(ctx *Context) (err error) {
if len(c.Subcommands) > 0 { if len(c.Subcommands) > 0 {
return c.startApp(ctx) return c.startApp(ctx)
@ -131,12 +132,11 @@ func (c Command) Run(ctx *Context) (err error) {
err := c.OnUsageError(ctx, err, false) err := c.OnUsageError(ctx, err, false)
HandleExitCoder(err) HandleExitCoder(err)
return err return err
} else {
fmt.Fprintln(ctx.App.Writer, "Incorrect Usage.")
fmt.Fprintln(ctx.App.Writer)
ShowCommandHelp(ctx, c.Name)
return err
} }
fmt.Fprintln(ctx.App.Writer, "Incorrect Usage.")
fmt.Fprintln(ctx.App.Writer)
ShowCommandHelp(ctx, c.Name)
return err
} }
nerr := normalizeFlags(c.Flags, set) nerr := normalizeFlags(c.Flags, set)
@ -191,6 +191,7 @@ func (c Command) Run(ctx *Context) (err error) {
return err return err
} }
// Names returns the names including short names and aliases.
func (c Command) Names() []string { func (c Command) Names() []string {
names := []string{c.Name} names := []string{c.Name}
@ -201,7 +202,7 @@ func (c Command) Names() []string {
return append(names, c.Aliases...) return append(names, c.Aliases...)
} }
// Returns true if Command.Name or Command.ShortName matches given name // HasName returns true if Command.Name or Command.ShortName matches given name
func (c Command) HasName(name string) bool { func (c Command) HasName(name string) bool {
for _, n := range c.Names() { for _, n := range c.Names() {
if n == name { if n == name {

View File

@ -49,7 +49,7 @@ func TestCommandFlagParsing(t *testing.T) {
func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) { func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
app := NewApp() app := NewApp()
app.Commands = []Command{ app.Commands = []Command{
Command{ {
Name: "bar", Name: "bar",
Before: func(c *Context) error { Before: func(c *Context) error {
return fmt.Errorf("before error") return fmt.Errorf("before error")
@ -76,7 +76,7 @@ func TestCommand_Run_DoesNotOverwriteErrorFromBefore(t *testing.T) {
func TestCommand_OnUsageError_WithWrongFlagValue(t *testing.T) { func TestCommand_OnUsageError_WithWrongFlagValue(t *testing.T) {
app := NewApp() app := NewApp()
app.Commands = []Command{ app.Commands = []Command{
Command{ {
Name: "bar", Name: "bar",
Flags: []Flag{ Flags: []Flag{
IntFlag{Name: "flag"}, IntFlag{Name: "flag"},

View File

@ -21,57 +21,62 @@ type Context struct {
parentContext *Context parentContext *Context
} }
// Creates a new context. For use in when invoking an App or Command action. // NewContext creates a new context. For use in when invoking an App or Command action.
func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context { func NewContext(app *App, set *flag.FlagSet, parentCtx *Context) *Context {
return &Context{App: app, flagSet: set, parentContext: parentCtx} return &Context{App: app, flagSet: set, parentContext: parentCtx}
} }
// Looks up the value of a local int flag, returns 0 if no int flag exists // Int looks up the value of a local int flag, returns 0 if no int flag exists
func (c *Context) Int(name string) int { func (c *Context) Int(name string) int {
return lookupInt(name, c.flagSet) return lookupInt(name, c.flagSet)
} }
// Looks up the value of a local time.Duration flag, returns 0 if no time.Duration flag exists // Duration looks up the value of a local time.Duration flag, returns 0 if no
// time.Duration flag exists
func (c *Context) Duration(name string) time.Duration { func (c *Context) Duration(name string) time.Duration {
return lookupDuration(name, c.flagSet) return lookupDuration(name, c.flagSet)
} }
// Looks up the value of a local float64 flag, returns 0 if no float64 flag exists // Float64 looks up the value of a local float64 flag, returns 0 if no float64
// flag exists
func (c *Context) Float64(name string) float64 { func (c *Context) Float64(name string) float64 {
return lookupFloat64(name, c.flagSet) return lookupFloat64(name, c.flagSet)
} }
// Looks up the value of a local bool flag, returns false if no bool flag exists // Bool looks up the value of a local bool flag, returns false if no bool flag exists
func (c *Context) Bool(name string) bool { func (c *Context) Bool(name string) bool {
return lookupBool(name, c.flagSet) return lookupBool(name, c.flagSet)
} }
// Looks up the value of a local boolT flag, returns false if no bool flag exists // BoolT looks up the value of a local boolT flag, returns false if no bool flag exists
func (c *Context) BoolT(name string) bool { func (c *Context) BoolT(name string) bool {
return lookupBoolT(name, c.flagSet) return lookupBoolT(name, c.flagSet)
} }
// Looks up the value of a local string flag, returns "" if no string flag exists // String looks up the value of a local string flag, returns "" if no string flag exists
func (c *Context) String(name string) string { func (c *Context) String(name string) string {
return lookupString(name, c.flagSet) return lookupString(name, c.flagSet)
} }
// Looks up the value of a local string slice flag, returns nil if no string slice flag exists // StringSlice looks up the value of a local string slice flag, returns nil if no
// string slice flag exists
func (c *Context) StringSlice(name string) []string { func (c *Context) StringSlice(name string) []string {
return lookupStringSlice(name, c.flagSet) return lookupStringSlice(name, c.flagSet)
} }
// Looks up the value of a local int slice flag, returns nil if no int slice flag exists // IntSlice looks up the value of a local int slice flag, returns nil if no int
// slice flag exists
func (c *Context) IntSlice(name string) []int { func (c *Context) IntSlice(name string) []int {
return lookupIntSlice(name, c.flagSet) return lookupIntSlice(name, c.flagSet)
} }
// Looks up the value of a local generic flag, returns nil if no generic flag exists // Generic looks up the value of a local generic flag, returns nil if no generic
// flag exists
func (c *Context) Generic(name string) interface{} { func (c *Context) Generic(name string) interface{} {
return lookupGeneric(name, c.flagSet) return lookupGeneric(name, c.flagSet)
} }
// Looks up the value of a global int flag, returns 0 if no int flag exists // GlobalInt looks up the value of a global int flag, returns 0 if no int flag exists
func (c *Context) GlobalInt(name string) int { func (c *Context) GlobalInt(name string) int {
if fs := lookupGlobalFlagSet(name, c); fs != nil { if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupInt(name, fs) return lookupInt(name, fs)
@ -79,8 +84,8 @@ func (c *Context) GlobalInt(name string) int {
return 0 return 0
} }
// Looks up the value of a global float64 flag, returns float64(0) if no float64 // GlobalFloat64 looks up the value of a global float64 flag, returns float64(0)
// flag exists // if no float64 flag exists
func (c *Context) GlobalFloat64(name string) float64 { func (c *Context) GlobalFloat64(name string) float64 {
if fs := lookupGlobalFlagSet(name, c); fs != nil { if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupFloat64(name, fs) return lookupFloat64(name, fs)
@ -88,7 +93,8 @@ func (c *Context) GlobalFloat64(name string) float64 {
return float64(0) return float64(0)
} }
// Looks up the value of a global time.Duration flag, returns 0 if no time.Duration flag exists // GlobalDuration 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 { func (c *Context) GlobalDuration(name string) time.Duration {
if fs := lookupGlobalFlagSet(name, c); fs != nil { if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupDuration(name, fs) return lookupDuration(name, fs)
@ -96,7 +102,8 @@ func (c *Context) GlobalDuration(name string) time.Duration {
return 0 return 0
} }
// Looks up the value of a global bool flag, returns false if no bool flag exists // GlobalBool looks up the value of a global bool flag, returns false if no bool
// flag exists
func (c *Context) GlobalBool(name string) bool { func (c *Context) GlobalBool(name string) bool {
if fs := lookupGlobalFlagSet(name, c); fs != nil { if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupBool(name, fs) return lookupBool(name, fs)
@ -104,7 +111,8 @@ func (c *Context) GlobalBool(name string) bool {
return false return false
} }
// Looks up the value of a global bool flag, returns true if no bool flag exists // GlobalBoolT looks up the value of a global bool flag, returns true if no bool
// flag exists
func (c *Context) GlobalBoolT(name string) bool { func (c *Context) GlobalBoolT(name string) bool {
if fs := lookupGlobalFlagSet(name, c); fs != nil { if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupBoolT(name, fs) return lookupBoolT(name, fs)
@ -112,7 +120,8 @@ func (c *Context) GlobalBoolT(name string) bool {
return false return false
} }
// Looks up the value of a global string flag, returns "" if no string flag exists // GlobalString looks up the value of a global string flag, returns "" if no
// string flag exists
func (c *Context) GlobalString(name string) string { func (c *Context) GlobalString(name string) string {
if fs := lookupGlobalFlagSet(name, c); fs != nil { if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupString(name, fs) return lookupString(name, fs)
@ -120,7 +129,8 @@ func (c *Context) GlobalString(name string) string {
return "" return ""
} }
// Looks up the value of a global string slice flag, returns nil if no string slice flag exists // GlobalStringSlice 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 { func (c *Context) GlobalStringSlice(name string) []string {
if fs := lookupGlobalFlagSet(name, c); fs != nil { if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupStringSlice(name, fs) return lookupStringSlice(name, fs)
@ -128,7 +138,8 @@ func (c *Context) GlobalStringSlice(name string) []string {
return nil return nil
} }
// Looks up the value of a global int slice flag, returns nil if no int slice flag exists // GlobalIntSlice 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 { func (c *Context) GlobalIntSlice(name string) []int {
if fs := lookupGlobalFlagSet(name, c); fs != nil { if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupIntSlice(name, fs) return lookupIntSlice(name, fs)
@ -136,7 +147,8 @@ func (c *Context) GlobalIntSlice(name string) []int {
return nil return nil
} }
// Looks up the value of a global generic flag, returns nil if no generic flag exists // GlobalGeneric looks up the value of a global generic flag, returns nil if no
// generic flag exists
func (c *Context) GlobalGeneric(name string) interface{} { func (c *Context) GlobalGeneric(name string) interface{} {
if fs := lookupGlobalFlagSet(name, c); fs != nil { if fs := lookupGlobalFlagSet(name, c); fs != nil {
return lookupGeneric(name, fs) return lookupGeneric(name, fs)
@ -144,7 +156,7 @@ func (c *Context) GlobalGeneric(name string) interface{} {
return nil return nil
} }
// Returns the number of flags set // NumFlags returns the number of flags set
func (c *Context) NumFlags() int { func (c *Context) NumFlags() int {
return c.flagSet.NFlag() return c.flagSet.NFlag()
} }
@ -159,7 +171,7 @@ func (c *Context) GlobalSet(name, value string) error {
return globalContext(c).flagSet.Set(name, value) return globalContext(c).flagSet.Set(name, value)
} }
// Determines if the flag was actually set // IsSet determines if the flag was actually set
func (c *Context) IsSet(name string) bool { func (c *Context) IsSet(name string) bool {
if c.setFlags == nil { if c.setFlags == nil {
c.setFlags = make(map[string]bool) c.setFlags = make(map[string]bool)
@ -170,7 +182,7 @@ func (c *Context) IsSet(name string) bool {
return c.setFlags[name] == true return c.setFlags[name] == true
} }
// Determines if the global flag was actually set // GlobalIsSet determines if the global flag was actually set
func (c *Context) GlobalIsSet(name string) bool { func (c *Context) GlobalIsSet(name string) bool {
if c.globalSetFlags == nil { if c.globalSetFlags == nil {
c.globalSetFlags = make(map[string]bool) c.globalSetFlags = make(map[string]bool)
@ -187,7 +199,7 @@ func (c *Context) GlobalIsSet(name string) bool {
return c.globalSetFlags[name] return c.globalSetFlags[name]
} }
// Returns a slice of flag names used in this context. // FlagNames returns a slice of flag names used in this context.
func (c *Context) FlagNames() (names []string) { func (c *Context) FlagNames() (names []string) {
for _, flag := range c.Command.Flags { for _, flag := range c.Command.Flags {
name := strings.Split(flag.GetName(), ",")[0] name := strings.Split(flag.GetName(), ",")[0]
@ -199,7 +211,7 @@ func (c *Context) FlagNames() (names []string) {
return return
} }
// Returns a slice of global flag names used by the app. // GlobalFlagNames returns a slice of global flag names used by the app.
func (c *Context) GlobalFlagNames() (names []string) { func (c *Context) GlobalFlagNames() (names []string) {
for _, flag := range c.App.Flags { for _, flag := range c.App.Flags {
name := strings.Split(flag.GetName(), ",")[0] name := strings.Split(flag.GetName(), ",")[0]
@ -211,25 +223,26 @@ func (c *Context) GlobalFlagNames() (names []string) {
return return
} }
// Returns the parent context, if any // Parent returns the parent context, if any
func (c *Context) Parent() *Context { func (c *Context) Parent() *Context {
return c.parentContext return c.parentContext
} }
// Args contains apps console arguments
type Args []string type Args []string
// Returns the command line arguments associated with the context. // Args returns the command line arguments associated with the context.
func (c *Context) Args() Args { func (c *Context) Args() Args {
args := Args(c.flagSet.Args()) args := Args(c.flagSet.Args())
return args return args
} }
// Returns the number of the command line arguments. // NArg returns the number of the command line arguments.
func (c *Context) NArg() int { func (c *Context) NArg() int {
return len(c.Args()) return len(c.Args())
} }
// Returns the nth argument, or else a blank string // Get returns the nth argument, or else a blank string
func (a Args) Get(n int) string { func (a Args) Get(n int) string {
if len(a) > n { if len(a) > n {
return a[n] return a[n]
@ -237,12 +250,12 @@ func (a Args) Get(n int) string {
return "" return ""
} }
// Returns the first argument, or else a blank string // First returns the first argument, or else a blank string
func (a Args) First() string { func (a Args) First() string {
return a.Get(0) return a.Get(0)
} }
// Return the rest of the arguments (not the first one) // Tail returns the rest of the arguments (not the first one)
// or else an empty string slice // or else an empty string slice
func (a Args) Tail() []string { func (a Args) Tail() []string {
if len(a) >= 2 { if len(a) >= 2 {
@ -251,12 +264,12 @@ func (a Args) Tail() []string {
return []string{} return []string{}
} }
// Checks if there are any arguments present // Present checks if there are any arguments present
func (a Args) Present() bool { func (a Args) Present() bool {
return len(a) != 0 return len(a) != 0
} }
// Swaps arguments at the given indexes // Swap swaps arguments at the given indexes
func (a Args) Swap(from, to int) error { func (a Args) Swap(from, to int) error {
if from >= len(a) || to >= len(a) { if from >= len(a) || to >= len(a) {
return errors.New("index out of range") return errors.New("index out of range")

View File

@ -199,7 +199,7 @@ func TestContext_GlobalFlagsInSubcommands(t *testing.T) {
} }
app.Commands = []Command{ app.Commands = []Command{
Command{ {
Name: "foo", Name: "foo",
Flags: []Flag{ Flags: []Flag{
BoolFlag{Name: "parent, p", Usage: "Parent flag"}, BoolFlag{Name: "parent, p", Usage: "Parent flag"},

View File

@ -7,20 +7,24 @@ import (
"strings" "strings"
) )
// OsExiter is the function used when the app exits. If not set defaults to os.Exit.
var OsExiter = os.Exit var OsExiter = os.Exit
// ErrWriter is used to write errors to the user. This can be anything // ErrWriter is used to write errors to the user. This can be anything
// implementing the io.Writer interface and defaults to os.Stderr. // implementing the io.Writer interface and defaults to os.Stderr.
var ErrWriter io.Writer = os.Stderr var ErrWriter io.Writer = os.Stderr
// MultiError is an error that wraps multiple errors.
type MultiError struct { type MultiError struct {
Errors []error Errors []error
} }
// NewMultiError creates a new MultiError. Pass in one or more errors.
func NewMultiError(err ...error) MultiError { func NewMultiError(err ...error) MultiError {
return MultiError{Errors: err} return MultiError{Errors: err}
} }
// Error implents the error interface.
func (m MultiError) Error() string { func (m MultiError) Error() string {
errs := make([]string, len(m.Errors)) errs := make([]string, len(m.Errors))
for i, err := range m.Errors { for i, err := range m.Errors {

24
flag.go
View File

@ -13,19 +13,19 @@ import (
const defaultPlaceholder = "value" const defaultPlaceholder = "value"
// This flag enables bash-completion for all commands and subcommands // BashCompletionFlag enables bash-completion for all commands and subcommands
var BashCompletionFlag = BoolFlag{ var BashCompletionFlag = BoolFlag{
Name: "generate-bash-completion", Name: "generate-bash-completion",
Hidden: true, Hidden: true,
} }
// This flag prints the version for the application // VersionFlag prints the version for the application
var VersionFlag = BoolFlag{ var VersionFlag = BoolFlag{
Name: "version, v", Name: "version, v",
Usage: "print the version", Usage: "print the version",
} }
// This flag prints the help for all commands and subcommands // HelpFlag prints the help for all commands and subcommands
// Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand // Set to the zero value (BoolFlag{}) to disable flag -- keeps subcommand
// unless HideHelp is set to true) // unless HideHelp is set to true)
var HelpFlag = BoolFlag{ var HelpFlag = BoolFlag{
@ -33,6 +33,8 @@ var HelpFlag = BoolFlag{
Usage: "show help", Usage: "show help",
} }
// FlagStringer converts a flag definition to a string. This is used by help
// to display a flag.
var FlagStringer FlagStringFunc = stringifyFlag var FlagStringer FlagStringFunc = stringifyFlag
// Flag is a common interface related to parsing flags in cli. // Flag is a common interface related to parsing flags in cli.
@ -103,6 +105,7 @@ func (f GenericFlag) Apply(set *flag.FlagSet) {
}) })
} }
// GetName returns the name of a flag.
func (f GenericFlag) GetName() string { func (f GenericFlag) GetName() string {
return f.Name return f.Name
} }
@ -126,7 +129,7 @@ func (f *StringSlice) Value() []string {
return *f return *f
} }
// StringSlice is a string flag that can be specified multiple times on the // StringSliceFlag is a string flag that can be specified multiple times on the
// command-line // command-line
type StringSliceFlag struct { type StringSliceFlag struct {
Name string Name string
@ -166,11 +169,12 @@ func (f StringSliceFlag) Apply(set *flag.FlagSet) {
}) })
} }
// GetName returns the name of a flag.
func (f StringSliceFlag) GetName() string { func (f StringSliceFlag) GetName() string {
return f.Name return f.Name
} }
// StringSlice is an opaque type for []int to satisfy flag.Value // IntSlice is an opaque type for []int to satisfy flag.Value
type IntSlice []int type IntSlice []int
// Set parses the value into an integer and appends it to the list of values // Set parses the value into an integer and appends it to the list of values
@ -178,9 +182,8 @@ func (f *IntSlice) Set(value string) error {
tmp, err := strconv.Atoi(value) tmp, err := strconv.Atoi(value)
if err != nil { if err != nil {
return err return err
} else {
*f = append(*f, tmp)
} }
*f = append(*f, tmp)
return nil return nil
} }
@ -237,6 +240,7 @@ func (f IntSliceFlag) Apply(set *flag.FlagSet) {
}) })
} }
// GetName returns the name of the flag.
func (f IntSliceFlag) GetName() string { func (f IntSliceFlag) GetName() string {
return f.Name return f.Name
} }
@ -280,6 +284,7 @@ func (f BoolFlag) Apply(set *flag.FlagSet) {
}) })
} }
// GetName returns the name of the flag.
func (f BoolFlag) GetName() string { func (f BoolFlag) GetName() string {
return f.Name return f.Name
} }
@ -324,6 +329,7 @@ func (f BoolTFlag) Apply(set *flag.FlagSet) {
}) })
} }
// GetName returns the name of the flag.
func (f BoolTFlag) GetName() string { func (f BoolTFlag) GetName() string {
return f.Name return f.Name
} }
@ -364,6 +370,7 @@ func (f StringFlag) Apply(set *flag.FlagSet) {
}) })
} }
// GetName returns the name of the flag.
func (f StringFlag) GetName() string { func (f StringFlag) GetName() string {
return f.Name return f.Name
} }
@ -408,6 +415,7 @@ func (f IntFlag) Apply(set *flag.FlagSet) {
}) })
} }
// GetName returns the name of the flag.
func (f IntFlag) GetName() string { func (f IntFlag) GetName() string {
return f.Name return f.Name
} }
@ -452,6 +460,7 @@ func (f DurationFlag) Apply(set *flag.FlagSet) {
}) })
} }
// GetName returns the name of the flag.
func (f DurationFlag) GetName() string { func (f DurationFlag) GetName() string {
return f.Name return f.Name
} }
@ -495,6 +504,7 @@ func (f Float64Flag) Apply(set *flag.FlagSet) {
}) })
} }
// GetName returns the name of the flag.
func (f Float64Flag) GetName() string { func (f Float64Flag) GetName() string {
return f.Name return f.Name
} }

View File

@ -1,23 +1,23 @@
package cli package cli
// An action to execute when the bash-completion flag is set // BashCompleteFunc is an action to execute when the bash-completion flag is set
type BashCompleteFunc func(*Context) type BashCompleteFunc func(*Context)
// An action to execute before any subcommands are run, but after the context is ready // BeforeFunc is an action to execute before any subcommands are run, but after
// If a non-nil error is returned, no subcommands are run // the context is ready if a non-nil error is returned, no subcommands are run
type BeforeFunc func(*Context) error type BeforeFunc func(*Context) error
// An action to execute after any subcommands are run, but after the subcommand has finished // AfterFunc is an action to execute after any subcommands are run, but after the
// It is run even if Action() panics // subcommand has finished it is run even if Action() panics
type AfterFunc func(*Context) error type AfterFunc func(*Context) error
// The action to execute when no subcommands are specified // ActionFunc is the action to execute when no subcommands are specified
type ActionFunc func(*Context) error type ActionFunc func(*Context) error
// Execute this function if the proper command cannot be found // CommandNotFoundFunc is executed if the proper command cannot be found
type CommandNotFoundFunc func(*Context, string) type CommandNotFoundFunc func(*Context, string)
// Execute this function if an usage error occurs. This is useful for displaying // OnUsageErrorFunc is executed if an usage error occurs. This is useful for displaying
// customized usage error messages. This function is able to replace the // customized usage error messages. This function is able to replace the
// original error messages. If this function is not set, the "Incorrect usage" // original error messages. If this function is not set, the "Incorrect usage"
// is displayed and the execution is interrupted. // is displayed and the execution is interrupted.

24
help.go
View File

@ -9,7 +9,7 @@ import (
"text/template" "text/template"
) )
// The text template for the Default help topic. // AppHelpTemplate is the text template for the Default help topic.
// 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 AppHelpTemplate = `NAME: var AppHelpTemplate = `NAME:
@ -36,7 +36,7 @@ COPYRIGHT:
{{end}} {{end}}
` `
// The text template for the command help topic. // CommandHelpTemplate is the text template for the command help topic.
// 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:
@ -56,7 +56,7 @@ OPTIONS:
{{end}}{{end}} {{end}}{{end}}
` `
// The text template for the subcommand help topic. // SubcommandHelpTemplate is the text template for the subcommand help topic.
// 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:
@ -108,16 +108,20 @@ var helpSubcommand = Command{
// Prints help for the App or Command // Prints help for the App or Command
type helpPrinter func(w io.Writer, templ string, data interface{}) type helpPrinter func(w io.Writer, templ string, data interface{})
// HelpPrinter is a function that writes the help output. If not set a default
// is used. The function signature is:
// func(w io.Writer, templ string, data interface{})
var HelpPrinter helpPrinter = printHelp var HelpPrinter helpPrinter = printHelp
// Prints version for the App // VersionPrinter prints the version for the App
var VersionPrinter = printVersion var VersionPrinter = printVersion
// ShowAppHelp is an action that displays the help.
func ShowAppHelp(c *Context) { func ShowAppHelp(c *Context) {
HelpPrinter(c.App.Writer, AppHelpTemplate, c.App) HelpPrinter(c.App.Writer, AppHelpTemplate, c.App)
} }
// Prints the list of subcommands as the default app completion method // DefaultAppComplete prints the list of subcommands as the default app completion method
func DefaultAppComplete(c *Context) { func DefaultAppComplete(c *Context) {
for _, command := range c.App.Commands { for _, command := range c.App.Commands {
if command.Hidden { if command.Hidden {
@ -129,7 +133,7 @@ func DefaultAppComplete(c *Context) {
} }
} }
// Prints help for the given command // ShowCommandHelp prints help for the given command
func ShowCommandHelp(ctx *Context, command string) error { func ShowCommandHelp(ctx *Context, command string) error {
// show the subcommand help for a command with subcommands // show the subcommand help for a command with subcommands
if command == "" { if command == "" {
@ -152,12 +156,12 @@ func ShowCommandHelp(ctx *Context, command string) error {
return nil return nil
} }
// Prints help for the given subcommand // ShowSubcommandHelp prints help for the given subcommand
func ShowSubcommandHelp(c *Context) error { func ShowSubcommandHelp(c *Context) error {
return ShowCommandHelp(c, c.Command.Name) return ShowCommandHelp(c, c.Command.Name)
} }
// Prints the version number of the App // ShowVersion prints the version number of the App
func ShowVersion(c *Context) { func ShowVersion(c *Context) {
VersionPrinter(c) VersionPrinter(c)
} }
@ -166,7 +170,7 @@ func printVersion(c *Context) {
fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version) fmt.Fprintf(c.App.Writer, "%v version %v\n", c.App.Name, c.App.Version)
} }
// Prints the lists of commands within a given context // ShowCompletions prints the lists of commands within a given context
func ShowCompletions(c *Context) { func ShowCompletions(c *Context) {
a := c.App a := c.App
if a != nil && a.BashComplete != nil { if a != nil && a.BashComplete != nil {
@ -174,7 +178,7 @@ func ShowCompletions(c *Context) {
} }
} }
// Prints the custom completions for a given command // ShowCommandCompletions prints the custom completions for a given command
func ShowCommandCompletions(ctx *Context, command string) { func ShowCommandCompletions(ctx *Context, command string) {
c := ctx.App.Command(command) c := ctx.App.Command(command)
if c != nil && c.BashComplete != nil { if c != nil && c.BashComplete != nil {

View File

@ -172,13 +172,13 @@ func Test_helpSubcommand_Action_ErrorIfNoTopic(t *testing.T) {
func TestShowAppHelp_HiddenCommand(t *testing.T) { func TestShowAppHelp_HiddenCommand(t *testing.T) {
app := &App{ app := &App{
Commands: []Command{ Commands: []Command{
Command{ {
Name: "frobbly", Name: "frobbly",
Action: func(ctx *Context) error { Action: func(ctx *Context) error {
return nil return nil
}, },
}, },
Command{ {
Name: "secretfrob", Name: "secretfrob",
Hidden: true, Hidden: true,
Action: func(ctx *Context) error { Action: func(ctx *Context) error {