-
-
Notifications
You must be signed in to change notification settings - Fork 671
/
Copy pathexecutor.go
329 lines (291 loc) · 8.97 KB
/
executor.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
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
package task
import (
"context"
"io"
"os"
"sync"
"time"
"github.com/sajari/fuzzy"
"github.com/go-task/task/v3/internal/logger"
"github.com/go-task/task/v3/internal/output"
"github.com/go-task/task/v3/internal/sort"
"github.com/go-task/task/v3/internal/tracing"
"github.com/go-task/task/v3/taskfile/ast"
)
type (
// An ExecutorOption is a functional option for an [Executor].
ExecutorOption func(*Executor)
// An Executor is used for processing Taskfile(s) and executing the task(s)
// within them.
Executor struct {
// Flags
Dir string
Entrypoint string
TempDir TempDir
Force bool
ForceAll bool
Insecure bool
Download bool
Offline bool
Timeout time.Duration
Watch bool
Verbose bool
Silent bool
AssumeYes bool
AssumeTerm bool // Used for testing
Dry bool
Summary bool
Parallel bool
Color bool
Concurrency int
Interval time.Duration
// I/O
Stdin io.Reader
Stdout io.Writer
Stderr io.Writer
// Internal
Taskfile *ast.Taskfile
Logger *logger.Logger
Compiler *Compiler
Output output.Output
OutputStyle ast.Output
TaskSorter sort.Sorter
UserWorkingDir string
EnableVersionCheck bool
fuzzyModel *fuzzy.Model
concurrencySemaphore chan struct{}
taskCallCount map[string]*int32
mkdirMutexMap map[string]*sync.Mutex
executionHashes map[string]context.Context
executionHashesMutex sync.Mutex
tracer *tracing.Tracer
}
TempDir struct {
Remote string
Fingerprint string
}
)
// NewExecutor creates a new [Executor] and applies the given functional options
// to it.
func NewExecutor(opts ...ExecutorOption) *Executor {
e := &Executor{
Timeout: time.Second * 10,
Interval: time.Second * 5,
Stdin: os.Stdin,
Stdout: os.Stdout,
Stderr: os.Stderr,
Logger: nil,
Compiler: nil,
Output: nil,
OutputStyle: ast.Output{},
TaskSorter: sort.AlphaNumericWithRootTasksFirst,
UserWorkingDir: "",
fuzzyModel: nil,
concurrencySemaphore: nil,
taskCallCount: map[string]*int32{},
mkdirMutexMap: map[string]*sync.Mutex{},
executionHashes: map[string]context.Context{},
executionHashesMutex: sync.Mutex{},
}
e.Options(opts...)
return e
}
// Options loops through the given [ExecutorOption] functions and applies them
// to the [Executor].
func (e *Executor) Options(opts ...ExecutorOption) {
for _, opt := range opts {
opt(e)
}
}
// ExecutorWithDir sets the working directory of the [Executor]. By default, the
// directory is set to the user's current working directory.
func ExecutorWithDir(dir string) ExecutorOption {
return func(e *Executor) {
e.Dir = dir
}
}
// ExecutorWithEntrypoint sets the entrypoint (main Taskfile) of the [Executor].
// By default, Task will search for one of the default Taskfiles in the given
// directory.
func ExecutorWithEntrypoint(entrypoint string) ExecutorOption {
return func(e *Executor) {
e.Entrypoint = entrypoint
}
}
// ExecutorWithTempDir sets the temporary directory that will be used by
// [Executor] for storing temporary files like checksums and cached remote
// files. By default, the temporary directory is set to the user's temporary
// directory.
func ExecutorWithTempDir(tempDir TempDir) ExecutorOption {
return func(e *Executor) {
e.TempDir = tempDir
}
}
// ExecutorWithForce ensures that the [Executor] always runs a task, even when
// fingerprinting or prompts would normally stop it.
func ExecutorWithForce(force bool) ExecutorOption {
return func(e *Executor) {
e.Force = force
}
}
// ExecutorWithForceAll ensures that the [Executor] always runs all tasks
// (including subtasks), even when fingerprinting or prompts would normally stop
// them.
func ExecutorWithForceAll(forceAll bool) ExecutorOption {
return func(e *Executor) {
e.ForceAll = forceAll
}
}
// ExecutorWithInsecure allows the [Executor] to make insecure connections when
// reading remote taskfiles. By default, insecure connections are rejected.
func ExecutorWithInsecure(insecure bool) ExecutorOption {
return func(e *Executor) {
e.Insecure = insecure
}
}
// ExecutorWithDownload forces the [Executor] to download a fresh copy of the
// taskfile from the remote source.
func ExecutorWithDownload(download bool) ExecutorOption {
return func(e *Executor) {
e.Download = download
}
}
// ExecutorWithOffline stops the [Executor] from being able to make network
// connections. It will still be able to read local files and cached copies of
// remote files.
func ExecutorWithOffline(offline bool) ExecutorOption {
return func(e *Executor) {
e.Offline = offline
}
}
// ExecutorWithTimeout sets the [Executor]'s timeout for fetching remote
// taskfiles. By default, the timeout is set to 10 seconds.
func ExecutorWithTimeout(timeout time.Duration) ExecutorOption {
return func(e *Executor) {
e.Timeout = timeout
}
}
// ExecutorWithWatch tells the [Executor] to keep running in the background and
// watch for changes to the fingerprint of the tasks that are run. When changes
// are detected, a new task run is triggered.
func ExecutorWithWatch(watch bool) ExecutorOption {
return func(e *Executor) {
e.Watch = watch
}
}
// ExecutorWithVerbose tells the [Executor] to output more information about the
// tasks that are run.
func ExecutorWithVerbose(verbose bool) ExecutorOption {
return func(e *Executor) {
e.Verbose = verbose
}
}
// ExecutorWithSilent tells the [Executor] to suppress all output except for the
// output of the tasks that are run.
func ExecutorWithSilent(silent bool) ExecutorOption {
return func(e *Executor) {
e.Silent = silent
}
}
// ExecutorWithAssumeYes tells the [Executor] to assume "yes" for all prompts.
func ExecutorWithAssumeYes(assumeYes bool) ExecutorOption {
return func(e *Executor) {
e.AssumeYes = assumeYes
}
}
// WithAssumeTerm is used for testing purposes to simulate a terminal.
func ExecutorWithDry(dry bool) ExecutorOption {
return func(e *Executor) {
e.Dry = dry
}
}
// ExecutorWithSummary tells the [Executor] to output a summary of the given
// tasks instead of running them.
func ExecutorWithSummary(summary bool) ExecutorOption {
return func(e *Executor) {
e.Summary = summary
}
}
// ExecutorWithParallel tells the [Executor] to run tasks given in the same call
// in parallel.
func ExecutorWithParallel(parallel bool) ExecutorOption {
return func(e *Executor) {
e.Parallel = parallel
}
}
// ExecutorWithColor tells the [Executor] whether or not to output using
// colorized strings.
func ExecutorWithColor(color bool) ExecutorOption {
return func(e *Executor) {
e.Color = color
}
}
// ExecutorWithConcurrency sets the maximum number of tasks that the [Executor]
// can run in parallel.
func ExecutorWithConcurrency(concurrency int) ExecutorOption {
return func(e *Executor) {
e.Concurrency = concurrency
}
}
// ExecutorWithInterval sets the interval at which the [Executor] will check for
// changes when watching tasks.
func ExecutorWithInterval(interval time.Duration) ExecutorOption {
return func(e *Executor) {
e.Interval = interval
}
}
// ExecutorWithOutputStyle sets the output style of the [Executor]. By default,
// the output style is set to the style defined in the Taskfile.
func ExecutorWithOutputStyle(outputStyle ast.Output) ExecutorOption {
return func(e *Executor) {
e.OutputStyle = outputStyle
}
}
// ExecutorWithTaskSorter sets the sorter that the [Executor] will use to sort
// tasks. By default, the sorter is set to sort tasks alphabetically, but with
// tasks with no namespace (in the root Taskfile) first.
func ExecutorWithTaskSorter(sorter sort.Sorter) ExecutorOption {
return func(e *Executor) {
e.TaskSorter = sorter
}
}
// ExecutorWithStdin sets the [Executor]'s standard input [io.Reader].
func ExecutorWithStdin(stdin io.Reader) ExecutorOption {
return func(e *Executor) {
e.Stdin = stdin
}
}
// ExecutorWithStdout sets the [Executor]'s standard output [io.Writer].
func ExecutorWithStdout(stdout io.Writer) ExecutorOption {
return func(e *Executor) {
e.Stdout = stdout
}
}
// ExecutorWithStderr sets the [Executor]'s standard error [io.Writer].
func ExecutorWithStderr(stderr io.Writer) ExecutorOption {
return func(e *Executor) {
e.Stderr = stderr
}
}
// ExecutorWithIO sets the [Executor]'s standard input, output, and error to the
// same [io.ReadWriter].
func ExecutorWithIO(rw io.ReadWriter) ExecutorOption {
return func(e *Executor) {
e.Stdin = rw
e.Stdout = rw
e.Stderr = rw
}
}
// ExecutorWithVersionCheck tells the [Executor] whether or not to check the
// version of
func ExecutorWithVersionCheck(enableVersionCheck bool) ExecutorOption {
return func(e *Executor) {
e.EnableVersionCheck = enableVersionCheck
}
}
// ExecutorWithTracer configures execution tracing
func ExecutorWithTracer(outFile string) ExecutorOption {
return func(e *Executor) {
e.tracer = tracing.NewTracer(outFile)
}
}