-
Notifications
You must be signed in to change notification settings - Fork 3
/
app.go
145 lines (125 loc) · 2.85 KB
/
app.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"
"os"
"path/filepath"
)
// App is the main structure of a cli application
type App struct {
// The name of the program. Defaults to path.Base(os.Args[0])
Name string
// The version of the program
Version 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
// Authors of the program
Authors string
// Examples of the program
Examples string
// SeeAlso of the program
SeeAlso string
// build information, show in --version
BuildInfo *BuildInfo
// List of flags to parse
Flags []*Flag
// List of commands to execute
Commands []*Command
// Hidden --help and --version from usage
HiddenHelp bool
HiddenVersion bool
// Display full help
ShowHelp func(*HelpContext)
// Display full version
ShowVersion func(*App)
// 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)
// Handler if panic in app.Action() and command.Action()
OnActionPanic func(*Context, error)
}
// NewApp creates a new cli Application
func NewApp() *App {
return &App{
Name: filepath.Base(os.Args[0]),
Usage: "A new cli application",
Version: "0.0.0",
ShowHelp: showHelp,
ShowVersion: showVersion,
}
}
func (a *App) initialize() {
// add --help
a.Flags = append(a.Flags, &Flag{
Name: "help",
Usage: "print this usage",
IsBool: true,
Hidden: a.HiddenHelp,
})
// add --version
a.Flags = append(a.Flags, &Flag{
Name: "version",
Usage: "print version information",
IsBool: true,
Hidden: a.HiddenVersion,
})
// initialize flags
for _, f := range a.Flags {
f.initialize()
}
}
// Run is the entry point to the cli app, parse argument and call Execute() or command.Execute()
func (a *App) Run(arguments []string) {
a.initialize()
// parse cli arguments
cl := &commandline{
flags: a.Flags,
commands: a.Commands,
}
err := cl.parse(arguments[1:])
// build context
newCtx := &Context{
name: a.Name,
app: a,
flags: a.Flags,
commands: a.Commands,
args: cl.args,
}
if err != nil {
newCtx.ShowError(err)
}
// show --help
if newCtx.GetBool("help") {
newCtx.ShowHelpAndExit(0)
}
// show --version
if newCtx.GetBool("version") {
a.ShowVersion(a)
os.Exit(0)
}
// command not found
if cl.command == nil && len(a.Commands) > 0 && len(cl.args) > 0 {
cmd := cl.args[0]
if a.OnCommandNotFound != nil {
a.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 a.Action != nil {
defer newCtx.handlePanic()
a.Action(newCtx)
} else {
newCtx.ShowHelpAndExit(0)
}
}