Skip to content

Commit

Permalink
Add custom help function to command
Browse files Browse the repository at this point in the history
  • Loading branch information
Ullaakut authored and traefiker committed Dec 2, 2019
1 parent cf1ace3 commit 4cb9eec
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 10 deletions.
29 changes: 20 additions & 9 deletions pkg/cli/commands.go
Expand Up @@ -4,18 +4,20 @@ package cli

import (
"fmt"
"io"
"os"
"path/filepath"
)

// Command structure contains program/command information (command name and description).
type Command struct {
Name string
Description string
Configuration interface{}
Resources []ResourceLoader
Run func([]string) error
Hidden bool
Name string
Description string
Configuration interface{}
Resources []ResourceLoader
Run func([]string) error
CustomHelpFunc func(io.Writer, *Command) error
Hidden bool
// AllowArg if not set, disallows any argument that is not a known command or a sub-command.
AllowArg bool
subCommands []*Command
Expand All @@ -35,6 +37,15 @@ func (c *Command) AddCommand(cmd *Command) error {
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.
func Execute(cmd *Command) error {
return execute(cmd, os.Args, true)
Expand Down Expand Up @@ -92,16 +103,16 @@ func execute(cmd *Command, args []string, root bool) error {

func run(cmd *Command, args []string) error {
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])
}

if isHelp(args) {
return PrintHelp(os.Stdout, cmd)
return cmd.PrintHelp(os.Stdout)
}

if cmd.Run == nil {
_ = PrintHelp(os.Stdout, cmd)
_ = cmd.PrintHelp(os.Stdout)
return fmt.Errorf("command %s is not runnable", cmd.Name)
}

Expand Down
61 changes: 61 additions & 0 deletions pkg/cli/commands_test.go
@@ -1,6 +1,10 @@
package cli

import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"strings"
Expand Down Expand Up @@ -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) {
var called string

Expand Down
2 changes: 1 addition & 1 deletion pkg/cli/loader_file.go
Expand Up @@ -25,7 +25,7 @@ func (f *FileLoader) GetFilename() string {
func (f *FileLoader) Load(args []string, cmd *Command) (bool, error) {
ref, err := flag.Parse(args, cmd.Configuration)
if err != nil {
_ = PrintHelp(os.Stdout, cmd)
_ = cmd.PrintHelp(os.Stdout)
return false, err
}

Expand Down

0 comments on commit 4cb9eec

Please sign in to comment.