feature: add DefaultCommand field to App

See issue #1307 for context.
main
James Alavosus 2 years ago
parent f1fc873f1f
commit 32dec1ddaa
No known key found for this signature in database
GPG Key ID: 1B900ABF298E2A89

@ -7,6 +7,7 @@ import (
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
"reflect"
"sort" "sort"
"time" "time"
) )
@ -43,6 +44,9 @@ type App struct {
Version string Version string
// Description of the program // Description of the program
Description string Description string
// DefaultCommand is the (optional) name of a command
// to run if no command names are passed as CLI arguments.
DefaultCommand string
// List of commands to execute // List of commands to execute
Commands []*Command Commands []*Command
// List of flags to parse // List of flags to parse
@ -333,14 +337,34 @@ func (a *App) RunContext(ctx context.Context, arguments []string) (err error) {
} }
} }
var c *Command
args := cCtx.Args() args := cCtx.Args()
if args.Present() { if args.Present() {
name := args.First() name := args.First()
c := a.Command(name) if a.validCommandName(name) {
c = a.Command(name)
} else {
isFlagName := false
for _, flagName := range cCtx.FlagNames() {
if name == flagName {
isFlagName = true
break
}
}
if isFlagName {
argsWithDefault := a.argsWithDefaultCommand(args)
if !reflect.DeepEqual(args, argsWithDefault) {
c = a.Command(argsWithDefault.First())
}
}
}
} else if a.DefaultCommand != "" {
c = a.Command(a.DefaultCommand)
}
if c != nil { if c != nil {
return c.Run(cCtx) return c.Run(cCtx)
} }
}
if a.Action == nil { if a.Action == nil {
a.Action = helpCommand.Action a.Action = helpCommand.Action
@ -570,6 +594,41 @@ func (a *App) handleExitCoder(cCtx *Context, err error) {
} }
} }
func (a *App) commandNames() []string {
var cmdNames []string
for _, cmd := range a.Commands {
cmdNames = append(cmdNames, cmd.Names()...)
}
return cmdNames
}
func (a *App) validCommandName(checkCmdName string) bool {
valid := false
allCommandNames := a.commandNames()
for _, cmdName := range allCommandNames {
if checkCmdName == cmdName {
valid = true
break
}
}
return valid
}
func (a *App) argsWithDefaultCommand(oldArgs Args) Args {
if a.DefaultCommand != "" {
rawArgs := append([]string{a.DefaultCommand}, oldArgs.Slice()...)
newArgs := args(rawArgs)
return &newArgs
}
return oldArgs
}
// Author represents someone who has contributed to a cli project. // Author represents someone who has contributed to a cli project.
type Author struct { type Author struct {
Name string // The Authors name Name string // The Authors name

@ -469,6 +469,42 @@ func TestApp_Command(t *testing.T) {
} }
} }
var defaultCommandAppTests = []struct {
cmdName string
defaultCmd string
expected bool
}{
{"foobar", "foobar", true},
{"batbaz", "foobar", true},
{"b", "", true},
{"f", "", true},
{"", "foobar", true},
{"", "", true},
{" ", "", false},
{"bat", "batbaz", false},
{"nothing", "batbaz", false},
{"nothing", "", false},
}
func TestApp_RunDefaultCommand(t *testing.T) {
for _, test := range defaultCommandAppTests {
testTitle := fmt.Sprintf("command=%[1]s-default=%[2]s", test.cmdName, test.defaultCmd)
t.Run(testTitle, func(t *testing.T) {
app := &App{
DefaultCommand: test.defaultCmd,
Commands: []*Command{
{Name: "foobar", Aliases: []string{"f"}},
{Name: "batbaz", Aliases: []string{"b"}},
},
}
err := app.Run([]string{"c", test.cmdName})
expect(t, err == nil, test.expected)
})
}
}
func TestApp_Setup_defaultsReader(t *testing.T) { func TestApp_Setup_defaultsReader(t *testing.T) {
app := &App{} app := &App{}
app.Setup() app.Setup()

Loading…
Cancel
Save