-
Notifications
You must be signed in to change notification settings - Fork 3
/
command.go
145 lines (123 loc) · 2.74 KB
/
command.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package cli
import (
"fmt"
"strings"
)
// Command is a subcommand for a cli.App
type Command struct {
// The name of the program. Defaults to path.Base(os.Args[0])
Name string
// Short description of the program.
Usage string
// Text to override the USAGE section of help
UsageText string
// Long description of the program
Description string
// Examples of the program
Examples string
// SeeAlso of the program
SeeAlso string
// List of flags to parse
Flags []*Flag
// List of commands to execute
Commands []*Command
// hidden --help from usage
HiddenHelp bool
// Treat all flags as normal arguments if true
SkipFlagParsing bool
// Boolean to hide this command from help
Hidden bool
// Display full help
ShowHelp func(*HelpContext)
// The action to execute when no subcommands are specified
Action func(*Context)
// Execute this function if the proper command cannot be found
OnCommandNotFound func(*Context, string)
}
func (c *Command) initialize() {
// add --help
c.Flags = append(c.Flags, &Flag{
Name: "help",
Usage: "print this usage",
IsBool: true,
Hidden: c.HiddenHelp,
})
// initialize flags
for _, f := range c.Flags {
f.initialize()
}
}
// Run is the entry point to the command, parse argument and call Execute() or subcommand.Execute()
func (c *Command) Run(ctx *Context) {
c.initialize()
if c.ShowHelp == nil {
c.ShowHelp = showHelp
}
// parse cli arguments
cl := &commandline{
flags: c.Flags,
commands: c.Commands,
}
var err error
if c.SkipFlagParsing {
cl.args = ctx.args[1:]
} else {
err = cl.parse(ctx.args[1:])
}
// build context
newCtx := &Context{
name: ctx.name + " " + c.Name,
app: ctx.app,
command: c,
flags: c.Flags,
commands: c.Commands,
args: cl.args,
parent: ctx,
}
if err != nil {
newCtx.ShowError(err)
}
// show --help
if newCtx.GetBool("help") {
newCtx.ShowHelpAndExit(0)
}
// command not found
if cl.command == nil && len(c.Commands) > 0 && len(cl.args) > 0 {
cmd := cl.args[0]
if c.OnCommandNotFound != nil {
c.OnCommandNotFound(newCtx, cmd)
} else {
newCtx.ShowError(fmt.Errorf("no such command: %s", cmd))
}
return
}
// run command
if cl.command != nil {
cl.command.Run(newCtx)
return
}
if c.Action != nil {
defer newCtx.handlePanic()
c.Action(newCtx)
} else {
newCtx.ShowHelpAndExit(0)
}
}
// Names returns the names including short names and aliases
func (c *Command) Names() []string {
names := strings.Split(c.Name, ",")
for i, name := range names {
names[i] = strings.TrimSpace(name)
}
return names
}
func lookupCommand(commands []*Command, name string) *Command {
for _, c := range commands {
for _, n := range c.Names() {
if n == name {
return c
}
}
}
return nil
}