github.com/YousefHaggyHeroku/pack@v1.5.5/internal/builder/detection_order_calculator.go (about) 1 package builder 2 3 import ( 4 pubbldr "github.com/YousefHaggyHeroku/pack/builder" 5 "github.com/YousefHaggyHeroku/pack/internal/dist" 6 ) 7 8 type DetectionOrderCalculator struct{} 9 10 func NewDetectionOrderCalculator() *DetectionOrderCalculator { 11 return &DetectionOrderCalculator{} 12 } 13 14 type detectionOrderRecurser struct { 15 layers dist.BuildpackLayers 16 maxDepth int 17 } 18 19 func newDetectionOrderRecurser(layers dist.BuildpackLayers, maxDepth int) *detectionOrderRecurser { 20 return &detectionOrderRecurser{ 21 layers: layers, 22 maxDepth: maxDepth, 23 } 24 } 25 26 func (c *DetectionOrderCalculator) Order( 27 order dist.Order, 28 layers dist.BuildpackLayers, 29 maxDepth int, 30 ) (pubbldr.DetectionOrder, error) { 31 recurser := newDetectionOrderRecurser(layers, maxDepth) 32 33 return recurser.detectionOrderFromOrder(order, dist.BuildpackRef{}, 0, map[dist.BuildpackRef]interface{}{}), nil 34 } 35 36 func (r *detectionOrderRecurser) detectionOrderFromOrder( 37 order dist.Order, 38 parentBuildpack dist.BuildpackRef, 39 currentDepth int, 40 visited map[dist.BuildpackRef]interface{}, 41 ) pubbldr.DetectionOrder { 42 var detectionOrder pubbldr.DetectionOrder 43 for _, orderEntry := range order { 44 visitedCopy := copyMap(visited) 45 groupDetectionOrder := r.detectionOrderFromGroup(orderEntry.Group, currentDepth, visitedCopy) 46 47 detectionOrderEntry := pubbldr.DetectionOrderEntry{ 48 BuildpackRef: parentBuildpack, 49 GroupDetectionOrder: groupDetectionOrder, 50 } 51 52 detectionOrder = append(detectionOrder, detectionOrderEntry) 53 } 54 55 return detectionOrder 56 } 57 58 func (r *detectionOrderRecurser) detectionOrderFromGroup( 59 group []dist.BuildpackRef, 60 currentDepth int, 61 visited map[dist.BuildpackRef]interface{}, 62 ) pubbldr.DetectionOrder { 63 var groupDetectionOrder pubbldr.DetectionOrder 64 65 for _, bp := range group { 66 _, bpSeen := visited[bp] 67 if !bpSeen { 68 visited[bp] = true 69 } 70 71 layer, ok := r.layers.Get(bp.ID, bp.Version) 72 if ok && len(layer.Order) > 0 && r.shouldGoDeeper(currentDepth) && !bpSeen { 73 groupOrder := r.detectionOrderFromOrder(layer.Order, bp, currentDepth+1, visited) 74 groupDetectionOrder = append(groupDetectionOrder, groupOrder...) 75 } else { 76 groupDetectionOrderEntry := pubbldr.DetectionOrderEntry{ 77 BuildpackRef: bp, 78 Cyclical: bpSeen, 79 } 80 groupDetectionOrder = append(groupDetectionOrder, groupDetectionOrderEntry) 81 } 82 } 83 84 return groupDetectionOrder 85 } 86 87 func (r *detectionOrderRecurser) shouldGoDeeper(currentDepth int) bool { 88 if r.maxDepth == pubbldr.OrderDetectionMaxDepth { 89 return true 90 } 91 92 if currentDepth < r.maxDepth { 93 return true 94 } 95 96 return false 97 } 98 99 func copyMap(toCopy map[dist.BuildpackRef]interface{}) map[dist.BuildpackRef]interface{} { 100 result := make(map[dist.BuildpackRef]interface{}, len(toCopy)) 101 for key := range toCopy { 102 result[key] = true 103 } 104 105 return result 106 }