Add support for help command
This commit is contained in:
		@ -215,9 +215,9 @@ func TestChildCommandFlags(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Testing with flag only existing on child
 | 
						// Testing with flag only existing on child
 | 
				
			||||||
	buf2 := new(bytes.Buffer)
 | 
						buf.Reset()
 | 
				
			||||||
	c = initialize()
 | 
						c = initialize()
 | 
				
			||||||
	c.SetOutput(buf2)
 | 
						c.SetOutput(buf)
 | 
				
			||||||
	cmdEcho.AddCommand(cmdTimes)
 | 
						cmdEcho.AddCommand(cmdTimes)
 | 
				
			||||||
	c.AddCommand(cmdPrint, cmdEcho)
 | 
						c.AddCommand(cmdPrint, cmdEcho)
 | 
				
			||||||
	c.SetArgs(strings.Split("echo -j 99 -i77 one two", " "))
 | 
						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")
 | 
							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())
 | 
							t.Errorf("Wrong error message displayed, \n %s", buf.String())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestPersistentFlags(t *testing.T) {
 | 
					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)
 | 
							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
 | 
					// 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) {
 | 
					func (c *Command) Find(args []string) (cmd *Command, a []string, err error) {
 | 
				
			||||||
	if c == nil {
 | 
						if c == nil {
 | 
				
			||||||
		return nil, nil, fmt.Errorf("Called find() on a nil Command")
 | 
							return nil, nil, fmt.Errorf("Called find() on a nil Command")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	validSubCommand := false
 | 
						validSubCommand := false
 | 
				
			||||||
	if len(args) > 1 && c.HasSubCommands() {
 | 
						if len(args) > 0 && c.HasSubCommands() {
 | 
				
			||||||
		for _, cmd := range c.commands {
 | 
							for _, cmd := range c.commands {
 | 
				
			||||||
			if cmd.Name() == args[0] {
 | 
								if cmd.Name() == args[0] {
 | 
				
			||||||
				validSubCommand = true
 | 
									validSubCommand = true
 | 
				
			||||||
@ -74,7 +75,7 @@ func (c *Command) Find(args []string) (cmd *Command, a []string, err error) {
 | 
				
			|||||||
	return nil, nil, nil
 | 
						return nil, nil, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *Command) Commander() *Commander {
 | 
					func (c *Command) Root() *Command {
 | 
				
			||||||
	var findRoot func(*Command) *Command
 | 
						var findRoot func(*Command) *Command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	findRoot = func(x *Command) *Command {
 | 
						findRoot = func(x *Command) *Command {
 | 
				
			||||||
@ -84,7 +85,12 @@ func (c *Command) Commander() *Commander {
 | 
				
			|||||||
			return x
 | 
								return x
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	cmdr := findRoot(c)
 | 
					
 | 
				
			||||||
 | 
						return findRoot(c)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func (c *Command) Commander() *Commander {
 | 
				
			||||||
 | 
						cmdr := c.Root()
 | 
				
			||||||
	if cmdr.cmdr != nil {
 | 
						if cmdr.cmdr != nil {
 | 
				
			||||||
		return cmdr.cmdr
 | 
							return cmdr.cmdr
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
@ -108,7 +114,12 @@ func (c *Command) execute(args []string) (err error) {
 | 
				
			|||||||
	if e == nil {
 | 
						if e == nil {
 | 
				
			||||||
		err = cmd.ParseFlags(a)
 | 
							err = cmd.ParseFlags(a)
 | 
				
			||||||
		if err != nil {
 | 
							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
 | 
								return err
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			argWoFlags := cmd.Flags().Args()
 | 
								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
 | 
					// Can be defined by user by overriding Commander.UsageFunc
 | 
				
			||||||
func (c *Command) Usage() error {
 | 
					func (c *Command) Usage() error {
 | 
				
			||||||
	err := c.Commander().UsageFunc(c)
 | 
						err := c.Commander().UsageFunc(c)
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		fmt.Println(err)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										41
									
								
								commander.go
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								commander.go
									
									
									
									
									
								
							@ -32,6 +32,8 @@ type Commander struct {
 | 
				
			|||||||
	UsageFunc     func(*Command) error     // Usage can be defined by application
 | 
						UsageFunc     func(*Command) error     // Usage can be defined by application
 | 
				
			||||||
	UsageTemplate string                   // Can be defined by Application
 | 
						UsageTemplate string                   // Can be defined by Application
 | 
				
			||||||
	HelpTemplate  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.
 | 
					// Provide the user with a new commander.
 | 
				
			||||||
@ -39,10 +41,24 @@ func NewCommander() (c *Commander) {
 | 
				
			|||||||
	c = new(Commander)
 | 
						c = new(Commander)
 | 
				
			||||||
	c.cmdr = c
 | 
						c.cmdr = c
 | 
				
			||||||
	c.UsageFunc = c.defaultUsage
 | 
						c.UsageFunc = c.defaultUsage
 | 
				
			||||||
 | 
						c.HelpFunc = c.defaultHelp
 | 
				
			||||||
	c.initTemplates()
 | 
						c.initTemplates()
 | 
				
			||||||
	return
 | 
						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
 | 
					// Name for commander, should match application name
 | 
				
			||||||
func (c *Commander) SetName(name string) {
 | 
					func (c *Commander) SetName(name string) {
 | 
				
			||||||
	c.name = name
 | 
						c.name = name
 | 
				
			||||||
@ -58,6 +74,9 @@ func (c *Commander) SetArgs(a []string) {
 | 
				
			|||||||
// and run through the command tree finding appropriate matches
 | 
					// and run through the command tree finding appropriate matches
 | 
				
			||||||
// for commands and then corresponding flags.
 | 
					// for commands and then corresponding flags.
 | 
				
			||||||
func (c *Commander) Execute() (err error) {
 | 
					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 {
 | 
						if len(c.args) == 0 {
 | 
				
			||||||
		err = c.execute(os.Args[1:])
 | 
							err = c.execute(os.Args[1:])
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
@ -75,10 +94,23 @@ func (c *Commander) out() io.Writer {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func (cmdr *Commander) defaultUsage(c *Command) error {
 | 
					func (cmdr *Commander) defaultUsage(c *Command) error {
 | 
				
			||||||
	err := tmpl(cmdr.out(), cmdr.UsageTemplate, c)
 | 
						err := tmpl(cmdr.out(), cmdr.UsageTemplate, c)
 | 
				
			||||||
 | 
						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 {
 | 
							if err != nil {
 | 
				
			||||||
			c.Println(err)
 | 
								c.Println(err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	return err
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//Print to out
 | 
					//Print to out
 | 
				
			||||||
@ -90,7 +122,6 @@ func (c *Commander) PrintOut(i ...interface{}) {
 | 
				
			|||||||
// If output is nil, os.Stderr is used.
 | 
					// If output is nil, os.Stderr is used.
 | 
				
			||||||
func (c *Commander) SetOutput(output io.Writer) {
 | 
					func (c *Commander) SetOutput(output io.Writer) {
 | 
				
			||||||
	c.output = &output
 | 
						c.output = &output
 | 
				
			||||||
	//*c.output = output
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *Commander) initTemplates() {
 | 
					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.
 | 
					Use "{{.Commander.Name}} help [command]" for more information about that command.
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	c.HelpTemplate = `{{if .Runnable}}Usage: {{.ProgramName}} {{.UsageLine}}
 | 
						c.HelpTemplate = `{{.Name}}
 | 
				
			||||||
 | 
					{{.Long | trim}}
 | 
				
			||||||
{{end}}{{.Long | trim}}
 | 
					{{if .Runnable}}{{.Usage}}{{end}}
 | 
				
			||||||
`
 | 
					`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user