Add support for help command
This commit is contained in:
parent
68f3c66d07
commit
fb2146e9e5
@ -215,9 +215,9 @@ func TestChildCommandFlags(t *testing.T) {
|
||||
}
|
||||
|
||||
// Testing with flag only existing on child
|
||||
buf2 := new(bytes.Buffer)
|
||||
buf.Reset()
|
||||
c = initialize()
|
||||
c.SetOutput(buf2)
|
||||
c.SetOutput(buf)
|
||||
cmdEcho.AddCommand(cmdTimes)
|
||||
c.AddCommand(cmdPrint, cmdEcho)
|
||||
c.SetArgs(strings.Split("echo -j 99 -i77 one two", " "))
|
||||
@ -227,10 +227,9 @@ func TestChildCommandFlags(t *testing.T) {
|
||||
t.Errorf("invalid flag should generate error")
|
||||
}
|
||||
|
||||
if !strings.Contains(buf2.String(), "intone=123") {
|
||||
if !strings.Contains(buf.String(), "intone=123") {
|
||||
t.Errorf("Wrong error message displayed, \n %s", buf.String())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestPersistentFlags(t *testing.T) {
|
||||
@ -268,3 +267,29 @@ func TestPersistentFlags(t *testing.T) {
|
||||
t.Errorf("local flag not parsed correctly. Expected false, had %v", flagb2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHelpCommand(t *testing.T) {
|
||||
buf := new(bytes.Buffer)
|
||||
c := initialize()
|
||||
cmdEcho.AddCommand(cmdTimes)
|
||||
c.AddCommand(cmdPrint, cmdEcho)
|
||||
c.SetArgs(strings.Split("help echo", " "))
|
||||
c.SetOutput(buf)
|
||||
c.Execute()
|
||||
|
||||
if !strings.Contains(buf.String(), cmdEcho.Long) {
|
||||
t.Errorf("Wrong error message displayed, \n %s", buf.String())
|
||||
}
|
||||
|
||||
buf.Reset()
|
||||
c = initialize()
|
||||
cmdEcho.AddCommand(cmdTimes)
|
||||
c.AddCommand(cmdPrint, cmdEcho)
|
||||
c.SetArgs(strings.Split("help echo times", " "))
|
||||
c.SetOutput(buf)
|
||||
c.Execute()
|
||||
|
||||
if !strings.Contains(buf.String(), cmdTimes.Long) {
|
||||
t.Errorf("Wrong error message displayed, \n %s", buf.String())
|
||||
}
|
||||
}
|
||||
|
22
command.go
22
command.go
@ -53,13 +53,14 @@ type Command struct {
|
||||
}
|
||||
|
||||
// find the target command given the args and command tree
|
||||
// Meant to be run on the highest node. Only searches down.
|
||||
func (c *Command) Find(args []string) (cmd *Command, a []string, err error) {
|
||||
if c == nil {
|
||||
return nil, nil, fmt.Errorf("Called find() on a nil Command")
|
||||
}
|
||||
|
||||
validSubCommand := false
|
||||
if len(args) > 1 && c.HasSubCommands() {
|
||||
if len(args) > 0 && c.HasSubCommands() {
|
||||
for _, cmd := range c.commands {
|
||||
if cmd.Name() == args[0] {
|
||||
validSubCommand = true
|
||||
@ -74,7 +75,7 @@ func (c *Command) Find(args []string) (cmd *Command, a []string, err error) {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
func (c *Command) Commander() *Commander {
|
||||
func (c *Command) Root() *Command {
|
||||
var findRoot func(*Command) *Command
|
||||
|
||||
findRoot = func(x *Command) *Command {
|
||||
@ -84,7 +85,12 @@ func (c *Command) Commander() *Commander {
|
||||
return x
|
||||
}
|
||||
}
|
||||
cmdr := findRoot(c)
|
||||
|
||||
return findRoot(c)
|
||||
}
|
||||
|
||||
func (c *Command) Commander() *Commander {
|
||||
cmdr := c.Root()
|
||||
if cmdr.cmdr != nil {
|
||||
return cmdr.cmdr
|
||||
} else {
|
||||
@ -108,7 +114,12 @@ func (c *Command) execute(args []string) (err error) {
|
||||
if e == nil {
|
||||
err = cmd.ParseFlags(a)
|
||||
if err != nil {
|
||||
cmd.Usage()
|
||||
// report flag parsing error
|
||||
c.Println(strings.Split(err.Error(), "\n")[0])
|
||||
erx := cmd.Usage()
|
||||
if erx != nil {
|
||||
return erx
|
||||
}
|
||||
return err
|
||||
} else {
|
||||
argWoFlags := cmd.Flags().Args()
|
||||
@ -162,9 +173,6 @@ func (c *Command) Printf(format string, i ...interface{}) {
|
||||
// Can be defined by user by overriding Commander.UsageFunc
|
||||
func (c *Command) Usage() error {
|
||||
err := c.Commander().UsageFunc(c)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
53
commander.go
53
commander.go
@ -28,10 +28,12 @@ type Commander struct {
|
||||
Command
|
||||
|
||||
args []string
|
||||
output *io.Writer // nil means stderr; use out() accessor
|
||||
UsageFunc func(*Command) error // Usage can be defined by application
|
||||
UsageTemplate string // Can be defined by Application
|
||||
HelpTemplate string // Can be defined by Application
|
||||
output *io.Writer // nil means stderr; use out() accessor
|
||||
UsageFunc func(*Command) error // Usage can be defined by application
|
||||
UsageTemplate string // Can be defined by Application
|
||||
HelpTemplate string // Can be defined by Application
|
||||
HelpFunc func(*Command, []string) // Help can be defined by application
|
||||
HelpCommand *Command
|
||||
}
|
||||
|
||||
// Provide the user with a new commander.
|
||||
@ -39,10 +41,24 @@ func NewCommander() (c *Commander) {
|
||||
c = new(Commander)
|
||||
c.cmdr = c
|
||||
c.UsageFunc = c.defaultUsage
|
||||
c.HelpFunc = c.defaultHelp
|
||||
c.initTemplates()
|
||||
return
|
||||
}
|
||||
|
||||
func (c *Commander) initHelp() {
|
||||
if c.HelpCommand == nil {
|
||||
c.HelpCommand = &Command{
|
||||
Use: "help [command to learn about]",
|
||||
Short: "Help about any command",
|
||||
Long: `Help provides help for any command in the application.
|
||||
Simply type ` + c.Name() + ` help [path to command] for full details.`,
|
||||
Run: c.HelpFunc,
|
||||
}
|
||||
}
|
||||
c.AddCommand(c.HelpCommand)
|
||||
}
|
||||
|
||||
// Name for commander, should match application name
|
||||
func (c *Commander) SetName(name string) {
|
||||
c.name = name
|
||||
@ -58,6 +74,9 @@ func (c *Commander) SetArgs(a []string) {
|
||||
// and run through the command tree finding appropriate matches
|
||||
// for commands and then corresponding flags.
|
||||
func (c *Commander) Execute() (err error) {
|
||||
// initialize help as the last point possible to allow for user
|
||||
// overriding
|
||||
c.initHelp()
|
||||
if len(c.args) == 0 {
|
||||
err = c.execute(os.Args[1:])
|
||||
} else {
|
||||
@ -75,12 +94,25 @@ func (c *Commander) out() io.Writer {
|
||||
|
||||
func (cmdr *Commander) defaultUsage(c *Command) error {
|
||||
err := tmpl(cmdr.out(), cmdr.UsageTemplate, c)
|
||||
if err != nil {
|
||||
c.Println(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (cmdr *Commander) defaultHelp(c *Command, args []string) {
|
||||
cmd, _, e := c.Root().Find(args)
|
||||
if cmd == nil {
|
||||
cmdr.Printf("Unknown help topic %#q. Run '%v help'.\n", args, cmdr.Name())
|
||||
return
|
||||
}
|
||||
if e != nil {
|
||||
cmdr.Printf("Unknown help topic %#q. Run '%v help'.\n", args, cmdr.Name())
|
||||
} else {
|
||||
err := tmpl(cmdr.out(), cmdr.HelpTemplate, cmd)
|
||||
if err != nil {
|
||||
c.Println(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Print to out
|
||||
func (c *Commander) PrintOut(i ...interface{}) {
|
||||
fmt.Fprint(c.out(), i...)
|
||||
@ -90,7 +122,6 @@ func (c *Commander) PrintOut(i ...interface{}) {
|
||||
// If output is nil, os.Stderr is used.
|
||||
func (c *Commander) SetOutput(output io.Writer) {
|
||||
c.output = &output
|
||||
//*c.output = output
|
||||
}
|
||||
|
||||
func (c *Commander) initTemplates() {
|
||||
@ -112,8 +143,8 @@ Additional help topics: {{if gt .Commands 0 }}{{range .Commands}}{{if not .Runna
|
||||
Use "{{.Commander.Name}} help [command]" for more information about that command.
|
||||
`
|
||||
|
||||
c.HelpTemplate = `{{if .Runnable}}Usage: {{.ProgramName}} {{.UsageLine}}
|
||||
|
||||
{{end}}{{.Long | trim}}
|
||||
c.HelpTemplate = `{{.Name}}
|
||||
{{.Long | trim}}
|
||||
{{if .Runnable}}{{.Usage}}{{end}}
|
||||
`
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user