Add custom help function to command

This commit is contained in:
Brendan Le Glaunec 2019-12-02 17:34:06 +01:00 committed by Traefiker Bot
parent cf1ace3a73
commit 4cb9eec257
3 changed files with 82 additions and 10 deletions

View file

@ -4,6 +4,7 @@ package cli
import ( import (
"fmt" "fmt"
"io"
"os" "os"
"path/filepath" "path/filepath"
) )
@ -15,6 +16,7 @@ type Command struct {
Configuration interface{} Configuration interface{}
Resources []ResourceLoader Resources []ResourceLoader
Run func([]string) error Run func([]string) error
CustomHelpFunc func(io.Writer, *Command) error
Hidden bool Hidden bool
// AllowArg if not set, disallows any argument that is not a known command or a sub-command. // AllowArg if not set, disallows any argument that is not a known command or a sub-command.
AllowArg bool AllowArg bool
@ -35,6 +37,15 @@ func (c *Command) AddCommand(cmd *Command) error {
return nil return nil
} }
// PrintHelp calls the custom help function of the command if it's set.
// Otherwise, it calls the default help function.
func (c *Command) PrintHelp(w io.Writer) error {
if c.CustomHelpFunc != nil {
return c.CustomHelpFunc(w, c)
}
return PrintHelp(w, c)
}
// Execute Executes a command. // Execute Executes a command.
func Execute(cmd *Command) error { func Execute(cmd *Command) error {
return execute(cmd, os.Args, true) return execute(cmd, os.Args, true)
@ -92,16 +103,16 @@ func execute(cmd *Command, args []string, root bool) error {
func run(cmd *Command, args []string) error { func run(cmd *Command, args []string) error {
if len(args) > 0 && !isFlag(args[0]) && !cmd.AllowArg { if len(args) > 0 && !isFlag(args[0]) && !cmd.AllowArg {
_ = PrintHelp(os.Stdout, cmd) _ = cmd.PrintHelp(os.Stdout)
return fmt.Errorf("command not found: %s", args[0]) return fmt.Errorf("command not found: %s", args[0])
} }
if isHelp(args) { if isHelp(args) {
return PrintHelp(os.Stdout, cmd) return cmd.PrintHelp(os.Stdout)
} }
if cmd.Run == nil { if cmd.Run == nil {
_ = PrintHelp(os.Stdout, cmd) _ = cmd.PrintHelp(os.Stdout)
return fmt.Errorf("command %s is not runnable", cmd.Name) return fmt.Errorf("command %s is not runnable", cmd.Name)
} }

View file

@ -1,6 +1,10 @@
package cli package cli
import ( import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil" "io/ioutil"
"os" "os"
"strings" "strings"
@ -55,6 +59,63 @@ func TestCommand_AddCommand(t *testing.T) {
} }
} }
func TestCommand_PrintHelp(t *testing.T) {
testCases := []struct {
desc string
command *Command
expectedOutput string
expectedError error
}{
{
desc: "print default help",
command: &Command{},
expectedOutput: " \n\nUsage: [command] [flags] [arguments]\n\nUse \" [command] --help\" for help on any command.\n\n",
},
{
desc: "print custom help",
command: &Command{
Name: "root",
Description: "Description for root",
Configuration: &struct {
Foo []struct {
Field string
}
}{},
Run: func(args []string) error {
return nil
},
CustomHelpFunc: func(w io.Writer, _ *Command) error {
_, _ = fmt.Fprintln(w, "test")
return nil
},
},
expectedOutput: "test\n",
},
{
desc: "error is returned from called help",
command: &Command{
CustomHelpFunc: func(_ io.Writer, _ *Command) error {
return errors.New("test")
},
},
expectedError: errors.New("test"),
},
}
for _, test := range testCases {
test := test
t.Run(test.desc, func(t *testing.T) {
t.Parallel()
buffer := &bytes.Buffer{}
err := test.command.PrintHelp(buffer)
assert.Equal(t, test.expectedError, err)
assert.Equal(t, test.expectedOutput, buffer.String())
})
}
}
func Test_execute(t *testing.T) { func Test_execute(t *testing.T) {
var called string var called string

View file

@ -25,7 +25,7 @@ func (f *FileLoader) GetFilename() string {
func (f *FileLoader) Load(args []string, cmd *Command) (bool, error) { func (f *FileLoader) Load(args []string, cmd *Command) (bool, error) {
ref, err := flag.Parse(args, cmd.Configuration) ref, err := flag.Parse(args, cmd.Configuration)
if err != nil { if err != nil {
_ = PrintHelp(os.Stdout, cmd) _ = cmd.PrintHelp(os.Stdout)
return false, err return false, err
} }