mirror of https://github.com/buildpacks/pack.git
101 lines
3.5 KiB
Go
101 lines
3.5 KiB
Go
package stack
|
|
|
|
import (
|
|
"sort"
|
|
|
|
"github.com/buildpacks/pack/internal/stringset"
|
|
"github.com/buildpacks/pack/pkg/dist"
|
|
)
|
|
|
|
const WildcardStack = "*"
|
|
|
|
// MergeCompatible determines the allowable set of stacks that a combination of buildpacks may run on, given each
|
|
// buildpack's set of stacks. Compatibility between the two sets of buildpack stacks is defined by the following rules:
|
|
//
|
|
// 1. The stack must be supported by both buildpacks. That is, any resulting stack ID must appear in both input sets.
|
|
// 2. For each supported stack ID, all required mixins for all buildpacks must be provided by the result. That is,
|
|
// mixins for the stack ID in both input sets are unioned.
|
|
// 3. If there is a wildcard stack in either of the stack list, the stack list not having the wild card stack is returned.
|
|
// 4. If both the stack lists contain a wildcard stack, a list containing just the wildcard stack is returned.
|
|
//
|
|
// ---
|
|
//
|
|
// Examples:
|
|
//
|
|
// stacksA = [{ID: "stack1", mixins: ["build:mixinA", "mixinB", "run:mixinC"]}}]
|
|
// stacksB = [{ID: "stack1", mixins: ["build:mixinA", "run:mixinC"]}}]
|
|
// result = [{ID: "stack1", mixins: ["build:mixinA", "mixinB", "run:mixinC"]}}]
|
|
//
|
|
// stacksA = [{ID: "stack1", mixins: ["build:mixinA"]}}, {ID: "stack2", mixins: ["mixinA"]}}]
|
|
// stacksB = [{ID: "stack1", mixins: ["run:mixinC"]}}, {ID: "stack2", mixins: ["mixinA"]}}]
|
|
// result = [{ID: "stack1", mixins: ["build:mixinA", "run:mixinC"]}}, {ID: "stack2", mixins: ["mixinA"]}}]
|
|
//
|
|
// stacksA = [{ID: "stack1", mixins: ["build:mixinA"]}}, {ID: "stack2", mixins: ["mixinA"]}}]
|
|
// stacksB = [{ID: "stack2", mixins: ["mixinA", "run:mixinB"]}}]
|
|
// result = [{ID: "stack2", mixins: ["mixinA", "run:mixinB"]}}]
|
|
//
|
|
// stacksA = [{ID: "stack1", mixins: ["build:mixinA"]}}]
|
|
// stacksB = [{ID: "stack2", mixins: ["mixinA", "run:mixinB"]}}]
|
|
// result = []
|
|
//
|
|
// stacksA = [{ID: "*"}, {ID: "stack1", mixins: ["build:mixinC"]}]
|
|
// stacksB = [{ID: "stack1", mixins: ["build:mixinA"]}, {ID: "stack2", mixins: ["mixinA", "run:mixinB"]}]
|
|
// result = [{ID: "stack1", mixins: ["build:mixinA"]}, {ID: "stack2", mixins: ["mixinA", "run:mixinB"]}]
|
|
//
|
|
// stacksA = [{ID: "stack1", mixins: ["build:mixinA"]}, {ID: "stack2", mixins: ["mixinA", "run:mixinB"]}]
|
|
// stacksB = [{ID: "*"}, {ID: "stack1", mixins: ["build:mixinC"]}]
|
|
// result = [{ID: "stack1", mixins: ["build:mixinA"]}, {ID: "stack2", mixins: ["mixinA", "run:mixinB"]}]
|
|
//
|
|
// stacksA = [{ID: "*"}, {ID: "stack1", mixins: ["build:mixinA"]}, {ID: "stack2", mixins: ["mixinA", "run:mixinB"]}]
|
|
// stacksB = [{ID: "*"}, {ID: "stack1", mixins: ["build:mixinC"]}]
|
|
// result = [{ID: "*"}]
|
|
func MergeCompatible(stacksA []dist.Stack, stacksB []dist.Stack) []dist.Stack {
|
|
set := map[string][]string{}
|
|
AHasWildcardStack, BHasWildcardStack := false, false
|
|
|
|
for _, s := range stacksA {
|
|
set[s.ID] = s.Mixins
|
|
if s.ID == WildcardStack {
|
|
AHasWildcardStack = true
|
|
}
|
|
}
|
|
|
|
for _, s := range stacksB {
|
|
if s.ID == WildcardStack {
|
|
BHasWildcardStack = true
|
|
}
|
|
}
|
|
|
|
if AHasWildcardStack && BHasWildcardStack {
|
|
return []dist.Stack{{ID: WildcardStack}}
|
|
}
|
|
|
|
if AHasWildcardStack {
|
|
return stacksB
|
|
}
|
|
|
|
if BHasWildcardStack {
|
|
return stacksA
|
|
}
|
|
|
|
var results []dist.Stack
|
|
|
|
for _, s := range stacksB {
|
|
if stackMixins, ok := set[s.ID]; ok {
|
|
mixinsSet := stringset.FromSlice(append(stackMixins, s.Mixins...))
|
|
var mixins []string
|
|
for m := range mixinsSet {
|
|
mixins = append(mixins, m)
|
|
}
|
|
sort.Strings(mixins)
|
|
|
|
results = append(results, dist.Stack{
|
|
ID: s.ID,
|
|
Mixins: mixins,
|
|
})
|
|
}
|
|
}
|
|
|
|
return results
|
|
}
|