-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathcomandante.go
162 lines (134 loc) · 3.66 KB
/
comandante.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
156
157
158
159
160
161
162
package comandante
import (
"errors"
"flag"
"fmt"
"io"
"os"
"sort"
"strconv"
"text/template"
)
type Comandante struct {
// binaryName is the name of the binary that will be used to invoke all commands
binaryName string
// A short description of what the binary does.
description string
// registeredCommands holds a list of all commands registered to this instance
// of comandante
registeredCommands []*Command
}
// New creates a new comandante
func New(binaryName, description string) *Comandante {
c := &Comandante{
binaryName: binaryName,
description: description,
registeredCommands: make([]*Command, 0),
}
return c
}
// RegisterCommand tells Comandante about a command so that it can be used.
func (c *Comandante) RegisterCommand(cmd *Command) error {
// return an error if a command of the same name already exists
for _, registeredCmd := range c.registeredCommands {
if cmd.Name == registeredCmd.Name {
msg := fmt.Sprintf("A command with the name '%s' already exists", cmd.Name)
return errors.New(msg)
}
}
c.registeredCommands = append(c.registeredCommands, cmd)
return nil
}
// Run finds a command based on the command line argument and invokes
// the command in the case that one is found.
func (c *Comandante) Run() error {
cmdName, err := getCmdName(os.Args)
if err != nil || cmdName == "--help" || cmdName == "-h" {
c.printDefaultHelp(os.Stderr)
return nil
}
// invoke the command
cmd := c.getCommand(cmdName)
if cmd != nil {
if cmd.FlagInit != nil {
cmd.FlagInit(&cmd.flagSet)
flag.Parse()
cmd.flagSet.Parse(flag.Args()[1:])
if cmd.FlagPostParse != nil {
cmd.FlagPostParse(&cmd.flagSet)
}
}
return cmd.Action()
}
c.printDefaultHelp(os.Stderr)
return nil
}
// IncludeHelp adds the built in help command.
func (c *Comandante) IncludeHelp() {
cmd := createHelpCommand(c, os.Stderr)
c.RegisterCommand(cmd)
}
// getCommand retrieves a registered command.
func (c *Comandante) getCommand(cmdName string) *Command {
for _, cmd := range c.registeredCommands {
if cmdName == cmd.Name {
return cmd
}
}
return nil
}
// printDefaultHelp prints the default help text
func (c *Comandante) printDefaultHelp(w io.Writer) {
tpl := template.New("usage")
data := struct {
BinaryDescription string
BinaryName string
ShowHelpCommand bool
Commands []*printableCommand
}{
c.description,
c.binaryName,
(c.getCommand("help") != nil),
c.collectCommandsForHelp(),
}
template.Must(tpl.Parse(usage))
_ = tpl.Execute(w, data)
}
// collectCommands
func (c *Comandante) collectCommandsForHelp() []*printableCommand {
// find the longest command
longest := 0
for _, cmd := range c.registeredCommands {
if len(cmd.Name) > longest {
longest = len(cmd.Name)
}
}
// pad all commands
commands := make([]*printableCommand, len(c.registeredCommands))
formatter := "%-" + strconv.Itoa(longest) + "s"
for i, cmd := range c.registeredCommands {
commands[i] = &printableCommand{
PaddedName: fmt.Sprintf(formatter, cmd.Name),
Description: cmd.ShortDescription,
}
}
sort.Sort(PrintableCommandsByName{commands})
return commands
}
// getCmdName returns a command name from an arg list.
func getCmdName(args []string) (string, error) {
// command name should always be the second string in the process args
if len(args) < 2 {
return "", errors.New("Unable to find a command")
}
return args[1], nil
}
var usage = `{{.BinaryDescription}}
Usage:
{{.BinaryName}} command [arguments]
Available commands: {{ range .Commands}}
{{.PaddedName}} {{.Description}}{{ end }}
{{if .ShowHelpCommand}}
Use "{{.BinaryName}} help [command]" for more information about a command.
{{end}}
`