Add custom help function to command
This commit is contained in:
parent
cf1ace3a73
commit
4cb9eec257
3 changed files with 82 additions and 10 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue