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
|
// 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
53
commander.go
53
commander.go
@ -28,10 +28,12 @@ type Commander struct {
|
|||||||
Command
|
Command
|
||||||
|
|
||||||
args []string
|
args []string
|
||||||
output *io.Writer // nil means stderr; use out() accessor
|
output *io.Writer // nil means stderr; use out() accessor
|
||||||
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,12 +94,25 @@ 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)
|
||||||
if err != nil {
|
|
||||||
c.Println(err)
|
|
||||||
}
|
|
||||||
return 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
|
//Print to out
|
||||||
func (c *Commander) PrintOut(i ...interface{}) {
|
func (c *Commander) PrintOut(i ...interface{}) {
|
||||||
fmt.Fprint(c.out(), i...)
|
fmt.Fprint(c.out(), i...)
|
||||||
@ -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}}
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user