-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathcommand.go
239 lines (194 loc) · 5.98 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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
// Copyright © 2018, Goomba project Authors. All rights reserved.
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with this
// work for additional information regarding copyright ownership. The ASF
// licenses this file to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package cli
import (
"io"
"os"
"github.com/goombaio/log"
)
// Command type implements a command or subcommand.
//
// A command is just that, a command for your application.
// E.g. 'go run ...' - 'run' is the command.
type Command struct {
// Name is the unique name of the command
Name string
// ShortDescription is the message shown in the usage output when using the
// flag -h or --help.
ShortDescription string
// LongDescription is the long message shown when the flag -h or -help is ç
// used in combination with the command '<this-command> -h' or
// '<this-command> -help' output.
LongDescription string
// Run is the actual work that the command will do when it is invoked.
Run func(c *Command) error
// commands are the list of subcommands that a command have associated with
// it.
commands []*Command
// arguments are the list of arguments that a command have associated with
// it.
arguments []string
// flags are the list of flags that a command have associated with it.
flags []*Flag
// output is where (an io.Writer) the reults will be printed
output io.Writer
// logger is the log.Logger being used
logger log.Logger
}
// NewCommand creates a new Command.
//
// Cli requires you to define the name and description as part of your command
// definition to ensure usability.
func NewCommand(name string, shortDescription string) *Command {
cmd := &Command{
Name: name,
ShortDescription: shortDescription,
LongDescription: "",
commands: make([]*Command, 0),
arguments: make([]string, 0),
flags: make([]*Flag, 0),
output: os.Stdout,
logger: log.NewNoopLogger(),
}
return cmd
}
// Commands returns the list of sub-commands of this command.
func (c *Command) Commands() []*Command {
return c.commands
}
// Command returns a *Command that represents an sub-command of this command given a
// numerical index.
func (c *Command) Command(id int) *Command {
return c.commands[id]
}
// Arguments returns the list of arguments of this command.
func (c *Command) Arguments() []string {
return c.arguments
}
// Argument returns an string that represents an argument of this command given a
// numerical index.
func (c *Command) Argument(id int) string {
return c.arguments[id]
}
// Flags returns the list of flags of this command.
func (c *Command) Flags() []*Flag {
return c.flags
}
// Flag returns a cli.Flag that represents a Flag of this command given a
// numerical index.
func (c *Command) Flag(id int) *Flag {
return c.flags[id]
}
// FlagName returns a cli.Flag that represents a Flag of this command given a
// string name.
func (c *Command) FlagName(name string) *Flag {
for _, flag := range c.Flags() {
if flag.ShortName == name {
return flag
}
if flag.LongName == name {
return flag
}
}
return nil
}
// Output return the destination for usage and error messages of this command.
//
// By default a Command uses os.Stdout as output.
func (c *Command) Output() io.Writer {
if c.output == nil {
c.output = os.Stdout
}
return c.output
}
// SetOutput sets the destination for usage and error messages.
func (c *Command) SetOutput(output io.Writer) {
c.output = output
}
// Logger returns the current log.Logger for this Command.
func (c *Command) Logger() log.Logger {
return c.logger
}
// SetLogger sets the log.Logger to be used.
func (c *Command) SetLogger(logger log.Logger) {
c.logger = logger
}
// AddCommand adds a subCommand to this Command.
func (c *Command) AddCommand(cmd *Command) {
c.arguments = os.Args[1:]
// Setup command default flag set
cmd.setupDefaultFlags()
cmd.SetOutput(c.Output())
cmd.SetLogger(c.Logger())
c.commands = append(c.commands, cmd)
}
// AddFlag adds a flag to this Command.
func (c *Command) AddFlag(flag *Flag) {
c.flags = append(c.flags, flag)
}
// execute executes the command.
//
// Execute uses the command arguments and run through the command tree finding
// appropriate matches for commands and then corresponding flags.
func (c *Command) execute() error {
// Setup command default flag set
c.setupDefaultFlags()
if c.output == nil {
c.SetOutput(os.Stdout)
}
if c.logger == nil {
c.logger = log.NewNoopLogger()
}
c.arguments = os.Args[1:]
// Parse commands ans subcommands from the cli, routing to the command it
// Will be selected for execution.
cmd := c.ParseCommands(c.Arguments())
// Parses flags and arguments for the selected command for execution.
cmd = cmd.ParseFlags(c.Arguments())
// If the special flags '-h', or '-help' are present on the current
// parsed flags execute the Usage() method for the command.
for _, flag := range cmd.Flags() {
if flag.ShortName == "-h" || flag.LongName == "-help" {
if flag.Parsed {
cmd.Usage()
return nil
}
}
}
// Run the command action if it is runnable.
if cmd.Run != nil {
err := cmd.Run(cmd)
if err != nil {
return err
}
}
return nil
}
// setupDefaultFlags adds default flags that all commands must support.
//
// Currently:
// -h, -help
func (c *Command) setupDefaultFlags() {
// help Flag
helpFlag := &Flag{
ShortName: "-h",
LongName: "-help",
Description: "Show help message",
Value: "false",
}
c.flags = append(c.flags, helpFlag)
}