-
Notifications
You must be signed in to change notification settings - Fork 0
/
command.go
246 lines (195 loc) · 5.99 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
240
241
242
243
244
245
246
package kli
import (
"bufio"
"bytes"
"flag"
"fmt"
"io"
"strings"
"time"
)
var indent = 1
// todo review the interface ... it's quite big
type Command interface {
KFlag
// Description sets the shot description (except) of the Command
Description(desc string)
// Detail sets the Command details, it's the long description
// like example
Detail(detail io.Reader)
// Do sets the function to be called on execution
Do(fn func(Command, KFlag) Error)
// Parse parses flag definitions from the argument
// list, which should not include the command name.
// Must be called after all flags in the
// FlagSet are defined and before flags are accessed by the program.
// The return value will be ErrHelp if -help or -h were set but not defined.
Parse([]string) error
// Args returns the non-flag arguments.
Args() []string
// Name returns the name of the command
Name() string
// Execute calls the function that what set by Command::Do
// returns a Error function not found if the
// execute function was not set
Execute(Command, KFlag) Error
// IsExecutable returns true if the command executing
// function has been set
IsExecutable() bool
// GetKFlag returns the command Kflag
GetKFlag() KFlag
// SetChildren sets the Command Children
SetChildren(children ...Command) error
Children() []Command
// returns the Command's parent Command
Parent() Command
// SetParent sets the Command's Parent
SetParent(parent Command) error
// PrintDefaults prints, to standard error unless configured otherwise,
PrintDefaults()
// Bool sets a flag of type Bool
Bool(name string, value bool, usage string)
// Duration sets a flag of type time.Duration (int64)
Duration(name string, value time.Duration, usage string)
// Float64 sets a flag of type float64
Float64(name string, value float64, usage string)
// Int sets a flag of type Int
Int(name string, value int, usage string)
// Int64 sets a flag of type Int64
Int64(name string, value int64, usage string)
// String sets a flag of type string
String(name string, value string, usage string)
// Uint sets a flag of type Uint
Uint(name string, value uint, usage string)
// Uint64 sets a flag of type Uint64
Uint64(name string, value uint64, usage string)
}
type CMD struct {
*flag.FlagSet
KFlag
desc string
detail io.Reader
parent Command
children []Command
fn func(cmd Command, globals KFlag) Error
}
// Description sets the command's description
func (c *CMD) Description(desc string) {
c.desc = desc
}
func (c *CMD) Detail(detail io.Reader) {
c.detail = detail
}
func NewCommand(name string, handling flag.ErrorHandling) *CMD {
return &CMD{
FlagSet: flag.NewFlagSet(name, handling),
KFlag: NewKflag(),
}
}
func NewSubCommand(parent Command, name string, handling flag.ErrorHandling) *CMD {
return &CMD{
FlagSet: flag.NewFlagSet(name, handling),
KFlag: NewKflag(),
parent: parent,
}
}
func (c *CMD) Do(fn func(Command, KFlag) Error) {
c.fn = fn
}
func (c *CMD) Execute(cmd Command, f KFlag) Error {
if !c.IsExecutable() {
return ErrorWrap(nil, "executable function not set", CannotExecute)
}
return c.fn(cmd, f)
}
func (c *CMD) IsExecutable() bool {
return c.fn != nil
}
func (c *CMD) GetKFlag() KFlag {
return c.KFlag
}
// SetChildren sets the children (sub-command)
// the method also sets the parent of the children command
// as the current command
func (c *CMD) SetChildren(children ...Command) error {
for _, c := range children {
err := c.SetParent(c)
if err != nil {
return fmt.Errorf("attempting to reset the parent of a child command. %s", err.Error())
}
}
c.children = append(c.children, children...)
return nil
}
// Children returns the command's children command (it's sub-command)
func (c *CMD) Children() []Command {
return c.children
}
// setParent
func (c *CMD) SetParent(parent Command) error {
if c.parent != nil {
return fmt.Errorf("command %s already has the parent : %s", c.Name(), c.parent.Name())
}
c.parent = parent
return nil
}
// Parent return the command's parent command
func (c *CMD) Parent() Command {
return c.parent
}
func (c *CMD) PrintDefaults() {
b := bytes.Buffer{}
w := bufio.NewWriter(&b)
c.FlagSet.SetOutput(w)
padding := strings.Repeat(" ", indent*2)
_, _ = fmt.Fprintln(w)
_, _ = fmt.Fprintf(w, "%s‣ %s : %s\n%s%s\n", padding, strings.ToUpper(c.Name()), c.desc, padding, strings.Repeat("⎺", len(c.Name()+c.desc)+8))
//output the command flag
flagHeader := true
c.FlagSet.VisitAll(func(f *flag.Flag) {
if flagHeader {
_, _ = fmt.Fprintf(w, "%sarguments:\n", padding)
flagHeader = false
}
_, _ = fmt.Fprintf(w, "%s-%s\t%s (default: %s)\n", strings.Repeat(" ", indent*4), f.Name, f.Usage, f.DefValue)
})
if c.detail != nil {
_, _ = fmt.Fprintf(w, "%susage:\n", padding)
scanner := bufio.NewScanner(c.detail)
for scanner.Scan() {
_, _ = fmt.Fprintf(w, "%s%s\n", strings.Repeat(" ", indent*4), scanner.Text())
}
}
_ = w.Flush()
fmt.Println(b.String())
//print the child default
for _, child := range c.Children() {
indent++
child.PrintDefaults()
indent--
}
}
func (c *CMD) Bool(name string, value bool, usage string) {
c.KFlag.SetFlag(name, c.FlagSet.Bool(name, value, usage))
}
func (c *CMD) Duration(name string, value time.Duration, usage string) {
c.String(name, value.String(), usage)
}
func (c *CMD) Float64(name string, value float64, usage string) {
c.KFlag.SetFlag(name, c.FlagSet.Float64(name, value, usage))
}
func (c *CMD) Int(name string, value int, usage string) {
c.KFlag.SetFlag(name, c.FlagSet.Int(name, value, usage))
}
func (c *CMD) Int64(name string, value int64, usage string) {
c.KFlag.SetFlag(name, c.FlagSet.Int64(name, value, usage))
}
func (c *CMD) String(name string, value string, usage string) {
c.KFlag.SetFlag(name, c.FlagSet.String(name, value, usage))
}
func (c *CMD) Uint(name string, value uint, usage string) {
c.KFlag.SetFlag(name, c.FlagSet.Uint(name, value, usage))
}
func (c *CMD) Uint64(name string, value uint64, usage string) {
c.KFlag.SetFlag(name, c.FlagSet.Uint64(name, value, usage))
}