-
Notifications
You must be signed in to change notification settings - Fork 2
/
plan.go
162 lines (147 loc) · 3.72 KB
/
plan.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
package main
import (
"fmt"
"strings"
)
func BuildExecutionPlan(workspaces []*Workspace, roots []string, debug func(string)) ([][]*Workspace, error) {
plan := [][]*Workspace{}
if len(roots) == 0 {
// root are all workspaces which do not depend on anything
for _, workspace := range workspaces {
if len(workspace.Inputs) == 0 {
roots = append(roots, workspace.Root)
}
}
} else {
// reduce workspaces to only the ones that depend on the give roots
var getRelevantWorkspaces func(*Workspace) []*Workspace
getRelevantWorkspaces = func(ws *Workspace) []*Workspace {
out := []*Workspace{ws}
for _, output := range ws.Outputs {
for _, input := range output.ReferedBy {
out = append(out, getRelevantWorkspaces(input.BelongsTo)...)
}
}
return out
}
relevantWorkspaces := []*Workspace{}
for _, root := range roots {
exists := false
for _, ws := range workspaces {
if strings.Contains(ws.Root, root) {
exists = true
relevantWorkspaces = append(relevantWorkspaces, getRelevantWorkspaces(ws)...)
}
}
if !exists {
err := fmt.Errorf("Workspace '%s' does not exist", root)
return plan, err
}
}
workspaces = relevantWorkspaces
// remove roots that depend on workspaces that are considered
newRoots := []string{}
for _, root := range roots {
hasDependencies := false
for _, ws := range workspaces {
if strings.Contains(ws.Root, root) {
for _, input := range ws.Inputs {
for _, wrkspce := range workspaces {
if input.ReferesTo.BelongsTo.Root == wrkspce.Root {
hasDependencies = true
}
}
}
}
}
if !hasDependencies {
newRoots = append(newRoots, root)
}
}
roots = newRoots
}
firstTier := []*Workspace{}
for _, root := range roots {
for _, ws := range workspaces {
if strings.Contains(ws.Root, root) {
firstTier = append(firstTier, ws)
}
}
}
plan = append(plan, firstTier)
var nextTier func(plan [][]*Workspace, workspaces []*Workspace) [][]*Workspace
nextTier = func(plan [][]*Workspace, workspaces []*Workspace) [][]*Workspace {
// get a list of all workspaces that already have been planned
planned := []*Workspace{}
for _, i := range plan {
planned = append(planned, i...)
}
// get a list of uniq unplanned workspaces
unplanned := []*Workspace{}
for _, i := range workspaces {
isPlanned := false
for _, j := range planned {
if i.RemoteState.equals(j.RemoteState) {
isPlanned = true
}
}
if !isPlanned {
exists := false
for _, y := range unplanned {
if i.RemoteState.equals(y.RemoteState) {
exists = true
}
}
if !exists {
unplanned = append(unplanned, i)
}
}
}
// exit if all is planned
if len(unplanned) < 1 {
return plan
}
// plan all unplanned with satisfied dependencies
next := []*Workspace{}
for _, ws := range unplanned {
debug(fmt.Sprintf("Checking unplanned workspace %s\n", ws.Root))
toSatisfy := map[string]bool{}
for _, dep := range ws.Dependencies {
for _, i := range workspaces {
if dep.equals(i.RemoteState) {
toSatisfy[dep.Name] = false
break
}
}
}
for _, dep := range ws.Dependencies {
for _, p := range planned {
if dep.equals(p.RemoteState) {
toSatisfy[dep.Name] = true
break
}
}
}
satisfied := true
for _, v := range toSatisfy {
if !v {
satisfied = false
break
}
}
if satisfied {
debug("\tsatisfied\n")
next = append(next, ws)
} else {
for k, v := range toSatisfy {
if !v {
debug(fmt.Sprintf("\t%s NOT satisfied\n", k))
}
}
}
}
plan = append(plan, next)
return nextTier(plan, workspaces)
}
return nextTier(plan, workspaces), nil
}