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  }