-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcli.go
155 lines (126 loc) · 3.02 KB
/
cli.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
146
147
148
149
150
151
152
153
154
155
package omcli
import (
"flag"
"fmt"
"os"
)
// Command is a command to be run from the command line
type Command struct {
// Name is the name of the command, if empty,
// fallback to trying first word of usage, then short, then long
Name string
// Usage is the single line usage information
Usage string
// Short is a short description of the command used when help is called
Short string
// Long is the long description of the command used when help [command] is called
Long string
// Flags are the command line flags for the command
// The root command will not have it's flags parsed, flags are reserved
// for subcommands
Flags flag.FlagSet
// Run runs the command
Run func(*Command, []string)
subCommands []*Command
root *Command
}
// AddCommand ands a subcommand to the command
func (c *Command) AddCommand(command *Command) {
if c.root != nil {
panic("commands can only be added to a root")
}
command.root = c
c.subCommands = append(c.subCommands, command)
}
// Execute runs the command
func (c *Command) Execute() {
if c.root != nil {
panic("Execute should only be called on a root command")
}
flag.Usage = c.help
flag.Parse()
args := flag.Args()
if len(args) < 1 {
c.help()
os.Exit(-1)
}
cname := args[0]
if cname == "help" {
if len(args) < 2 {
c.help()
os.Exit(-1)
}
c.doHelp(args[1])
os.Exit(0)
}
cmd := c.findCommand(cname)
if cmd == nil {
c.unknownExit(cname)
}
cmd.Flags.Usage = cmd.usage
if err := cmd.Flags.Parse(args[1:]); err != nil {
panic(err)
}
args = cmd.Flags.Args()
cmd.Run(cmd, args)
}
func (c *Command) unknownExit(name string) {
c.println("unknown command: ", name)
c.println("Run", "'"+c.Name, "help' for available commands.")
os.Exit(-1)
}
func (c *Command) doHelp(name string) {
cmd := c.findCommand(name)
if cmd == nil {
c.unknownExit(name)
}
cmd.help()
}
func (c *Command) findCommand(name string) *Command {
for _, cmd := range c.subCommands {
if cmd.Name == name && cmd.runnable() {
return cmd
}
}
return nil
}
func (c *Command) usage() {
c.println("usage: ", c.Usage)
c.println()
c.Flags.SetOutput(os.Stderr)
c.Flags.PrintDefaults()
c.println()
c.println(c.Long)
os.Exit(-1)
}
func (c *Command) help() {
c.printf("%s\n\n", c.Short)
if c.root == nil {
c.printf("Usage:\n %s command [arguments]\n\n", c.Name)
c.printf("Available commands:\n\n")
for _, cmd := range c.subCommands {
if cmd.runnable() {
c.printf("%+10s %s\n", cmd.Name, cmd.Short)
}
}
c.printf("\nUse '%s help' [command] to view a command's documentation.\n\n", c.Name)
return
}
c.printf("Usage:\n\n %s\n\n", c.Usage)
c.Flags.SetOutput(os.Stderr)
c.Flags.PrintDefaults()
c.printf("\n%s\n\n", c.Long)
}
func (c *Command) printf(format string, args ...interface{}) {
if _, err := fmt.Fprintf(os.Stderr, format, args...); err != nil {
panic(err)
}
}
func (c *Command) println(args ...interface{}) {
if _, err := fmt.Fprintln(os.Stderr, args...); err != nil {
panic(err)
}
}
func (c *Command) runnable() bool {
return c.Run != nil
}