mirror of
https://github.com/spf13/cobra
synced 2024-11-24 14:47:12 +00:00
Add decent usage message
This commit is contained in:
parent
6067837866
commit
8858462331
2 changed files with 140 additions and 21 deletions
157
cobra.go
157
cobra.go
|
@ -22,7 +22,10 @@ import (
|
||||||
flag "github.com/spf13/pflag"
|
flag "github.com/spf13/pflag"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"text/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ = flag.ContinueOnError
|
var _ = flag.ContinueOnError
|
||||||
|
@ -32,14 +35,19 @@ type Commander struct {
|
||||||
// A Commander is also a Command for top level and global help & flags
|
// A Commander is also a Command for top level and global help & flags
|
||||||
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
|
||||||
|
UsageTemplate string // Can be defined by Application
|
||||||
|
HelpTemplate string // Can be defined by Application
|
||||||
}
|
}
|
||||||
|
|
||||||
// Provide the user with a new commander.
|
// Provide the user with a new commander.
|
||||||
func NewCommander() (c *Commander) {
|
func NewCommander() (c *Commander) {
|
||||||
c = new(Commander)
|
c = new(Commander)
|
||||||
c.cmdr = c
|
c.cmdr = c
|
||||||
|
c.UsageFunc = c.defaultUsage
|
||||||
|
c.initTemplates()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +81,14 @@ func (c *Commander) out() io.Writer {
|
||||||
return c.output
|
return c.output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cmdr *Commander) defaultUsage(c *Command) error {
|
||||||
|
err := tmpl(cmdr.out(), cmdr.UsageTemplate, c)
|
||||||
|
if err != nil {
|
||||||
|
c.Println(err)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
//Print to out
|
//Print to out
|
||||||
func (c *Commander) POut(i ...interface{}) {
|
func (c *Commander) POut(i ...interface{}) {
|
||||||
fmt.Fprint(c.out(), i...)
|
fmt.Fprint(c.out(), i...)
|
||||||
|
@ -84,6 +100,29 @@ func (c *Commander) SetOutput(output io.Writer) {
|
||||||
c.output = output
|
c.output = output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Commander) initTemplates() {
|
||||||
|
c.UsageTemplate = `{{ $cmd := . }}{{.CommandPath | printf "%-11s"}} :: {{.Short}}
|
||||||
|
Usage:
|
||||||
|
{{.UseLine}}{{if .HasSubCommands}} command{{end}}{{if .HasFlags}} [flags]{{end}}
|
||||||
|
{{ if .HasSubCommands}}
|
||||||
|
The commands are:
|
||||||
|
{{range .Commands}}{{if .Runnable}}
|
||||||
|
{{.UseLine | printf "%-11s"}} {{.Short}}{{end}}{{end}}
|
||||||
|
Use "{{$.CommandPath}} help [command]" for more information about a command.
|
||||||
|
{{end}}
|
||||||
|
Additional help topics: {{if gt .Commands 0 }}
|
||||||
|
{{range .Commands}}{{if not .Runnable}}{{.CommandPath | printf "%-11s"}} {{.Short}}{{end}}{{end}}{{end}}{{if gt .Parent.Commands 1 }}
|
||||||
|
{{range .Parent.Commands}}{{if .Runnable}}{{if not (eq .Name $cmd.Name) }}{{end}}
|
||||||
|
{{.CommandPath | printf "%-11s"}} :: {{.Short}}{{end}}{{end}}{{end}}
|
||||||
|
Use "{{.Commander.Name}} help [topic]" for more information about that topic.
|
||||||
|
`
|
||||||
|
|
||||||
|
c.HelpTemplate = `{{if .Runnable}}Usage: {{.ProgramName}} {{.UsageLine}}
|
||||||
|
|
||||||
|
{{end}}{{.Long | trim}}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
// Command is just that, a command for your application.
|
// Command is just that, a command for your application.
|
||||||
// eg. 'go run' ... 'run' is the command. Cobra requires
|
// eg. 'go run' ... 'run' is the command. Cobra requires
|
||||||
// you to define the usage and description as part of your command
|
// you to define the usage and description as part of your command
|
||||||
|
@ -135,6 +174,10 @@ 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 {
|
||||||
|
return c.cmdr
|
||||||
|
}
|
||||||
|
|
||||||
// execute the command determined by args and the command tree
|
// execute the command determined by args and the command tree
|
||||||
func (c *Command) execute(args []string) (err error) {
|
func (c *Command) execute(args []string) (err error) {
|
||||||
err = fmt.Errorf("unknown subcommand %q\nRun 'help' for usage.\n", args[0])
|
err = fmt.Errorf("unknown subcommand %q\nRun 'help' for usage.\n", args[0])
|
||||||
|
@ -147,6 +190,7 @@ 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()
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
argWoFlags := cmd.Flags().Args()
|
argWoFlags := cmd.Flags().Args()
|
||||||
|
@ -163,6 +207,10 @@ func (c *Command) ResetCommands() {
|
||||||
c.commands = nil
|
c.commands = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Command) Commands() []*Command {
|
||||||
|
return c.commands
|
||||||
|
}
|
||||||
|
|
||||||
// Add one or many commands as children of this
|
// Add one or many commands as children of this
|
||||||
func (c *Command) AddCommand(cmds ...*Command) {
|
func (c *Command) AddCommand(cmds ...*Command) {
|
||||||
for i, x := range cmds {
|
for i, x := range cmds {
|
||||||
|
@ -189,20 +237,33 @@ func (c *Command) Printf(format string, i ...interface{}) {
|
||||||
c.Print(str)
|
c.Print(str)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The full usage for a given command (including parents)
|
func (c *Command) Usage() error {
|
||||||
func (c *Command) Usage(depth ...int) string {
|
err := c.cmdr.UsageFunc(c)
|
||||||
i := 0
|
if err != nil {
|
||||||
if len(depth) > 0 {
|
fmt.Println(err)
|
||||||
i = depth[0]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.HasParent() {
|
return err
|
||||||
return c.parent.Usage(i+1) + " " + c.Use
|
}
|
||||||
} else if i > 0 {
|
|
||||||
return c.Name()
|
func (c *Command) CommandPath() string {
|
||||||
} else {
|
str := c.Name()
|
||||||
return c.Use
|
x := c
|
||||||
|
for x.HasParent() {
|
||||||
|
str = x.parent.Name() + " " + str
|
||||||
|
x = x.parent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
//The full usage for a given command (including parents)
|
||||||
|
func (c *Command) UseLine() string {
|
||||||
|
str := ""
|
||||||
|
if c.HasParent() {
|
||||||
|
str = c.parent.CommandPath() + " "
|
||||||
|
}
|
||||||
|
return str + c.Use
|
||||||
}
|
}
|
||||||
|
|
||||||
// For use in determining which flags have been assigned to which commands
|
// For use in determining which flags have been assigned to which commands
|
||||||
|
@ -251,13 +312,13 @@ func (c *Command) DebugFlags() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Usage prints the usage details to the standard output.
|
// Usage prints the usage details to the standard output.
|
||||||
func (c *Command) PrintUsage() {
|
//func (c *Command) PrintUsage() {
|
||||||
if c.Runnable() {
|
//if c.Runnable() {
|
||||||
c.Printf("usage: %s\n\n", c.Usage())
|
//c.Printf("usage: %s\n\n", c.Usage())
|
||||||
}
|
//}
|
||||||
|
|
||||||
c.Println(strings.Trim(c.Long, "\n"))
|
//c.Println(strings.Trim(c.Long, "\n"))
|
||||||
}
|
//}
|
||||||
|
|
||||||
// Name returns the command's name: the first word in the use line.
|
// Name returns the command's name: the first word in the use line.
|
||||||
func (c *Command) Name() string {
|
func (c *Command) Name() string {
|
||||||
|
@ -382,3 +443,61 @@ func (c *Command) mergePersistentFlags() {
|
||||||
|
|
||||||
rmerge(c)
|
rmerge(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Command) Parent() *Command {
|
||||||
|
return c.parent
|
||||||
|
}
|
||||||
|
|
||||||
|
func Gt(a interface{}, b interface{}) bool {
|
||||||
|
var left, right int64
|
||||||
|
av := reflect.ValueOf(a)
|
||||||
|
|
||||||
|
switch av.Kind() {
|
||||||
|
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
|
||||||
|
left = int64(av.Len())
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
left = av.Int()
|
||||||
|
case reflect.String:
|
||||||
|
left, _ = strconv.ParseInt(av.String(), 10, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
bv := reflect.ValueOf(b)
|
||||||
|
|
||||||
|
switch bv.Kind() {
|
||||||
|
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
|
||||||
|
right = int64(bv.Len())
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
right = bv.Int()
|
||||||
|
case reflect.String:
|
||||||
|
right, _ = strconv.ParseInt(bv.String(), 10, 64)
|
||||||
|
}
|
||||||
|
|
||||||
|
return left > right
|
||||||
|
}
|
||||||
|
|
||||||
|
func Eq(a interface{}, b interface{}) bool {
|
||||||
|
av := reflect.ValueOf(a)
|
||||||
|
bv := reflect.ValueOf(b)
|
||||||
|
|
||||||
|
switch av.Kind() {
|
||||||
|
case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice:
|
||||||
|
panic("Eq called on unsupported type")
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return av.Int() == bv.Int()
|
||||||
|
case reflect.String:
|
||||||
|
return av.String() == bv.String()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// tmpl executes the given template text on data, writing the result to w.
|
||||||
|
func tmpl(w io.Writer, text string, data interface{}) error {
|
||||||
|
t := template.New("top")
|
||||||
|
t.Funcs(template.FuncMap{
|
||||||
|
"trim": strings.TrimSpace,
|
||||||
|
"gt": Gt,
|
||||||
|
"eq": Eq,
|
||||||
|
})
|
||||||
|
template.Must(t.Parse(text))
|
||||||
|
return t.Execute(w, data)
|
||||||
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ var cmdEcho = &Command{
|
||||||
}
|
}
|
||||||
|
|
||||||
var cmdTimes = &Command{
|
var cmdTimes = &Command{
|
||||||
Use: "times [string to echo]",
|
Use: "times [# times] [string to echo]",
|
||||||
Short: "Echo anything to the screen more times",
|
Short: "Echo anything to the screen more times",
|
||||||
Long: `an slightly useless command for testing.`,
|
Long: `an slightly useless command for testing.`,
|
||||||
Run: timesRunner,
|
Run: timesRunner,
|
||||||
|
@ -69,7 +69,7 @@ func commandInit() {
|
||||||
func initialize() *Commander {
|
func initialize() *Commander {
|
||||||
tt, tp, te = nil, nil, nil
|
tt, tp, te = nil, nil, nil
|
||||||
var c = NewCommander()
|
var c = NewCommander()
|
||||||
c.SetName("cobra test")
|
c.SetName("cobratest")
|
||||||
flagInit()
|
flagInit()
|
||||||
commandInit()
|
commandInit()
|
||||||
return c
|
return c
|
||||||
|
|
Loading…
Reference in a new issue