generated from golang-templates/seed
/
task.go
129 lines (110 loc) · 2.83 KB
/
task.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
package goyek
// Task represents a named task that can have action and dependencies.
type Task struct {
// Name uniquely identifies the task.
// It cannot be empty and should be easily representable on the CLI.
Name string
// Usage provides information what the task does.
Usage string
// Action is function that is called when the task is run.
// A task can have only dependencies and no action to act as a pipeline.
Action func(a *A)
// Deps is a collection of defined tasks
// that need to be run before this task is executed.
Deps Deps
// Parallel marks that this task can be run in parallel
// with (and only with) other parallel tasks.
Parallel bool
}
// DefinedTask represents a task that has been defined.
// It can be used as a dependency for another task.
type DefinedTask struct {
*taskSnapshot
flow *Flow
}
// Deps represents a collection of dependencies.
type Deps []*DefinedTask
// Name returns the name of the task.
func (r *DefinedTask) Name() string {
return r.name
}
// SetName changes the name of the task.
func (r *DefinedTask) SetName(s string) {
if _, ok := r.flow.tasks[s]; ok {
panic("task with the same name is already defined")
}
oldName := r.name
snap := r.flow.tasks[oldName]
snap.name = s
r.flow.tasks[s] = snap
delete(r.flow.tasks, oldName)
}
// Usage returns the description of the task.
func (r *DefinedTask) Usage() string {
return r.usage
}
// SetUsage sets the description of the task.
func (r *DefinedTask) SetUsage(s string) {
r.usage = s
}
// Action returns the action of the task.
func (r *DefinedTask) Action() func(a *A) {
return r.action
}
// SetAction changes the action of the task.
func (r *DefinedTask) SetAction(fn func(a *A)) {
r.action = fn
}
// Deps returns all task's dependencies.
func (r *DefinedTask) Deps() Deps {
count := len(r.deps)
if count == 0 {
return nil
}
deps := make(Deps, 0, count)
for _, dep := range r.deps {
deps = append(deps, &DefinedTask{r.flow.tasks[dep.name], r.flow})
}
return deps
}
// SetDeps sets all task's dependencies.
func (r *DefinedTask) SetDeps(deps Deps) {
count := len(deps)
if count == 0 {
r.deps = nil
return
}
for _, dep := range deps {
if !r.flow.isDefined(dep.Name(), dep.flow) {
panic("dependency was not defined: " + dep.Name())
}
}
visited := map[string]bool{}
if ok := r.noCycle(deps, visited); !ok {
panic("circular dependency")
}
depNames := make([]*taskSnapshot, 0, count)
for _, dep := range deps {
depNames = append(depNames, dep.taskSnapshot)
}
r.deps = depNames
}
func (r *DefinedTask) noCycle(deps Deps, visited map[string]bool) bool {
if len(deps) == 0 {
return true
}
for _, dep := range deps {
name := dep.Name()
if visited[name] {
return true
}
visited[name] = true
if name == r.name {
return false
}
if !r.noCycle(dep.Deps(), visited) {
return false
}
}
return true
}