/
detection_order_calculator.go
106 lines (86 loc) · 2.66 KB
/
detection_order_calculator.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
package builder
import (
pubbldr "github.com/buildpacks/pack/builder"
"github.com/buildpacks/pack/pkg/dist"
)
type DetectionOrderCalculator struct{}
func NewDetectionOrderCalculator() *DetectionOrderCalculator {
return &DetectionOrderCalculator{}
}
type detectionOrderRecurser struct {
layers dist.BuildpackLayers
maxDepth int
}
func newDetectionOrderRecurser(layers dist.BuildpackLayers, maxDepth int) *detectionOrderRecurser {
return &detectionOrderRecurser{
layers: layers,
maxDepth: maxDepth,
}
}
func (c *DetectionOrderCalculator) Order(
order dist.Order,
layers dist.BuildpackLayers,
maxDepth int,
) (pubbldr.DetectionOrder, error) {
recurser := newDetectionOrderRecurser(layers, maxDepth)
return recurser.detectionOrderFromOrder(order, dist.BuildpackRef{}, 0, map[string]interface{}{}), nil
}
func (r *detectionOrderRecurser) detectionOrderFromOrder(
order dist.Order,
parentBuildpack dist.BuildpackRef,
currentDepth int,
visited map[string]interface{},
) pubbldr.DetectionOrder {
var detectionOrder pubbldr.DetectionOrder
for _, orderEntry := range order {
visitedCopy := copyMap(visited)
groupDetectionOrder := r.detectionOrderFromGroup(orderEntry.Group, currentDepth, visitedCopy)
detectionOrderEntry := pubbldr.DetectionOrderEntry{
BuildpackRef: parentBuildpack,
GroupDetectionOrder: groupDetectionOrder,
}
detectionOrder = append(detectionOrder, detectionOrderEntry)
}
return detectionOrder
}
func (r *detectionOrderRecurser) detectionOrderFromGroup(
group []dist.BuildpackRef,
currentDepth int,
visited map[string]interface{},
) pubbldr.DetectionOrder {
var groupDetectionOrder pubbldr.DetectionOrder
for _, bp := range group {
_, bpSeen := visited[bp.FullName()]
if !bpSeen {
visited[bp.FullName()] = true
}
layer, ok := r.layers.Get(bp.ID, bp.Version)
if ok && len(layer.Order) > 0 && r.shouldGoDeeper(currentDepth) && !bpSeen {
groupOrder := r.detectionOrderFromOrder(layer.Order, bp, currentDepth+1, visited)
groupDetectionOrder = append(groupDetectionOrder, groupOrder...)
} else {
groupDetectionOrderEntry := pubbldr.DetectionOrderEntry{
BuildpackRef: bp,
Cyclical: bpSeen,
}
groupDetectionOrder = append(groupDetectionOrder, groupDetectionOrderEntry)
}
}
return groupDetectionOrder
}
func (r *detectionOrderRecurser) shouldGoDeeper(currentDepth int) bool {
if r.maxDepth == pubbldr.OrderDetectionMaxDepth {
return true
}
if currentDepth < r.maxDepth {
return true
}
return false
}
func copyMap(toCopy map[string]interface{}) map[string]interface{} {
result := make(map[string]interface{}, len(toCopy))
for key := range toCopy {
result[key] = true
}
return result
}