github.com/YousefHaggyHeroku/pack@v1.5.5/internal/stack/merge.go (about)

     1  package stack
     2  
     3  import (
     4  	"sort"
     5  
     6  	"github.com/YousefHaggyHeroku/pack/internal/dist"
     7  	"github.com/YousefHaggyHeroku/pack/internal/stringset"
     8  )
     9  
    10  // MergeCompatible determines the allowable set of stacks that a combination of buildpacks may run on, given each
    11  // buildpack's set of stacks. Compatibility between the two sets of buildpack stacks is defined by the following rules:
    12  //
    13  //   1. The stack must be supported by both buildpacks. That is, any resulting stack ID must appear in both input sets.
    14  //   2. For each supported stack ID, all required mixins for all buildpacks must be provided by the result. That is,
    15  // 		mixins for the stack ID in both input sets are unioned.
    16  //
    17  // ---
    18  //
    19  // Examples:
    20  //
    21  // 	stacksA = [{ID: "stack1", mixins: ["build:mixinA", "mixinB", "run:mixinC"]}}]
    22  // 	stacksB = [{ID: "stack1", mixins: ["build:mixinA", "run:mixinC"]}}]
    23  // 	result = [{ID: "stack1", mixins: ["build:mixinA", "mixinB", "run:mixinC"]}}]
    24  //
    25  // 	stacksA = [{ID: "stack1", mixins: ["build:mixinA"]}}, {ID: "stack2", mixins: ["mixinA"]}}]
    26  // 	stacksB = [{ID: "stack1", mixins: ["run:mixinC"]}}, {ID: "stack2", mixins: ["mixinA"]}}]
    27  // 	result = [{ID: "stack1", mixins: ["build:mixinA", "run:mixinC"]}}, {ID: "stack2", mixins: ["mixinA"]}}]
    28  //
    29  // 	stacksA = [{ID: "stack1", mixins: ["build:mixinA"]}}, {ID: "stack2", mixins: ["mixinA"]}}]
    30  // 	stacksB = [{ID: "stack2", mixins: ["mixinA", "run:mixinB"]}}]
    31  // 	result = [{ID: "stack2", mixins: ["mixinA", "run:mixinB"]}}]
    32  //
    33  // 	stacksA = [{ID: "stack1", mixins: ["build:mixinA"]}}]
    34  // 	stacksB = [{ID: "stack2", mixins: ["mixinA", "run:mixinB"]}}]
    35  // 	result = []
    36  //
    37  func MergeCompatible(stacksA []dist.Stack, stacksB []dist.Stack) []dist.Stack {
    38  	set := map[string][]string{}
    39  
    40  	for _, s := range stacksA {
    41  		set[s.ID] = s.Mixins
    42  	}
    43  
    44  	var results []dist.Stack
    45  	for _, s := range stacksB {
    46  		if stackMixins, ok := set[s.ID]; ok {
    47  			mixinsSet := stringset.FromSlice(append(stackMixins, s.Mixins...))
    48  			var mixins []string
    49  			for s := range mixinsSet {
    50  				mixins = append(mixins, s)
    51  			}
    52  			sort.Strings(mixins)
    53  
    54  			results = append(results, dist.Stack{
    55  				ID:     s.ID,
    56  				Mixins: mixins,
    57  			})
    58  		}
    59  	}
    60  
    61  	return results
    62  }