-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuilder.go
More file actions
188 lines (165 loc) · 4.53 KB
/
builder.go
File metadata and controls
188 lines (165 loc) · 4.53 KB
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
package cli
import (
"context"
"fmt"
"os"
"github.com/ake-persson/mapslice-json"
cli "github.com/urfave/cli/v2"
)
func New(name, usage string, version ...string) *Builder {
var v string
if len(version) > 0 {
v = version[0]
}
return &Builder{
app: &cli.App{
Name: name,
Usage: usage,
Version: v,
},
}
}
// Must be created by New(), handles building the cli application
type Builder struct {
preventMain bool
daemoize bool
before Callback
app *cli.App
runner *Runner
config interface{}
configStructure mapslice.MapSlice
}
// Parses args and runs cli application
func (b *Builder) Run(args ...string) (*Runner, error) {
if b.runner != nil {
return nil, fmt.Errorf(".Run() has already been called once")
}
b.runner = &Runner{
builder: b,
flags: make(Flags),
isMain: true,
}
b.runner.ctx, b.runner.cancelFunc = context.WithCancel(context.Background())
signalHandler(b.runner.ctx, b.runner.cancelFunc)
b.preConfig()
b.app.Before = func(c *cli.Context) error {
for _, flagName := range c.LocalFlagNames() {
b.runner.flags[flagName] = c.Value(flagName)
}
b.runner.args = Args(c.Args().Slice())
b.postConfig(c)
if b.before != nil {
return b.before(b.runner, b.runner.Args(), b.runner.Flags())
}
return nil
}
if !b.preventMain {
b.app.Action = func(c *cli.Context) error {
return nil
}
}
helpFlagUsed := false // To prevent --help making app proceed
for _, arg := range os.Args {
if arg == "-h" || arg == "--help" {
helpFlagUsed = true
}
}
versionFlagUsed := false // To prevent --version making app proceed
for _, arg := range os.Args {
if arg == "-v" || arg == "--version" {
versionFlagUsed = true
}
}
err := b.app.Run(os.Args)
if b.preventMain {
b.runner.Exit(err)
} else if helpFlagUsed || versionFlagUsed {
b.runner.Exit(nil)
}
if err != nil {
return b.runner, err
}
return b.runner, nil
}
// BooleanFlag specifices a boolean flag variable input by provided name, usage and aliases
func (b *Builder) BooleanFlag(name string, usage string, aliases ...string) *Builder {
b.app.Flags = append(b.app.Flags, BooleanFlag(name, usage, aliases...))
return b
}
// IntegerFlag specifices a integer flag variable input by provided name, usage and aliases
func (b *Builder) IntegerFlag(name string, usage string, aliases ...string) *Builder {
b.app.Flags = append(b.app.Flags, IntegerFlag(name, usage, aliases...))
return b
}
// StringFlag specifices a integer flag variable input by provided name, usage and aliases
func (b *Builder) StringFlag(name string, usage string, aliases ...string) *Builder {
b.app.Flags = append(b.app.Flags, StringFlag(name, usage, aliases...))
return b
}
// Makes application exit after Run() finishes instead of a normal return
func (b *Builder) DisableMain() *Builder {
b.preventMain = true
return b
}
// Sets callback to be invoked before any command is executed
func (b *Builder) Before(callback Callback) *Builder {
b.before = callback
return b
}
func (b *Builder) Command(name string, usage string, callback Callback, flags ...cli.Flag) *Builder {
b.app.Commands = append(b.app.Commands, &cli.Command{
Name: name,
Usage: usage,
Action: func(cc *cli.Context) error {
b.runner.isMain = false
parsedFlags := make(Flags)
for _, flagName := range cc.LocalFlagNames() {
parsedFlags[flagName] = cc.Value(flagName)
}
parsedArgs := Args(cc.Args().Slice())
if err := callback(b.runner, parsedArgs, parsedFlags); err != nil {
return err
}
return nil
},
Flags: flags,
})
return b
}
func (b *Builder) SubCommand(parent string, name string, usage string, callback Callback, flags ...cli.Flag) *Builder {
var selectedCommand *cli.Command
for _, command := range b.app.Commands {
if command.Name == parent {
selectedCommand = command
break
}
}
if selectedCommand == nil {
selectedCommand = &cli.Command{
Name: parent,
}
b.app.Commands = append(b.app.Commands, selectedCommand)
}
selectedCommand.Subcommands = append(selectedCommand.Subcommands, &cli.Command{
Name: name,
Usage: usage,
Action: func(cc *cli.Context) error {
b.runner.isMain = false
parsedFlags := make(Flags)
for _, flagName := range cc.LocalFlagNames() {
parsedFlags[flagName] = cc.Value(flagName)
}
parsedArgs := Args(cc.Args().Slice())
if err := callback(b.runner, parsedArgs, parsedFlags); err != nil {
return err
}
return nil
},
Flags: flags,
})
return b
}
func (b *Builder) Config(config interface{}) *Builder {
b.config = config
return b
}