-
Notifications
You must be signed in to change notification settings - Fork 26
/
planner.go
108 lines (94 loc) · 3.33 KB
/
planner.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
107
108
// Package draft provides a service for resolving the priority of buildpack
// plan entries as well as consilidating build and launch requirements.
package draft
import (
"reflect"
"regexp"
"sort"
"github.com/paketo-buildpacks/packit/v2"
)
// A Planner sorts buildpack plan entries using a given list of priorities. A
// Planner can also give the OR merged state of launch and build fields that
// are defined in the buildpack plan entries metadata field.
type Planner struct {
}
// NewPlanner returns a new Planner object.
func NewPlanner() Planner {
return Planner{}
}
// Resolve takes the name of buildpack plan entries that you want to sort, the
// buildpack plan entries that you want to be sorted, and a priority list of
// version-sources where the 0th index is the highest priority. Priorities can
// either be a string, in which case an exact string match with the
// version-source wil be required, or it can be a regular expression. It
// returns the highest priority entry as well as the sorted and filtered list
// of buildpack plan entries that were given. Entries with no given
// version-source are the lowest priority.
//
// If nil is passed for the value of the priority list then the function will
// just return the first filtered entry from the list of the entries that were
// passed into the function initially.
func (p Planner) Resolve(name string, entries []packit.BuildpackPlanEntry, priorities []interface{}) (packit.BuildpackPlanEntry, []packit.BuildpackPlanEntry) {
var filteredEntries []packit.BuildpackPlanEntry
for _, e := range entries {
if e.Name == name {
filteredEntries = append(filteredEntries, e)
}
}
if len(filteredEntries) == 0 {
return packit.BuildpackPlanEntry{}, nil
}
sort.Slice(filteredEntries, func(i, j int) bool {
leftSource := filteredEntries[i].Metadata["version-source"]
left, _ := leftSource.(string)
leftPriority := -1
rightSource := filteredEntries[j].Metadata["version-source"]
right, _ := rightSource.(string)
rightPriority := -1
for index, match := range priorities {
if r, ok := match.(*regexp.Regexp); ok {
if r.MatchString(left) {
leftPriority = len(priorities) - index - 1
}
} else {
if reflect.DeepEqual(match, left) {
leftPriority = len(priorities) - index - 1
}
}
if r, ok := match.(*regexp.Regexp); ok {
if r.MatchString(right) {
rightPriority = len(priorities) - index - 1
}
} else {
if reflect.DeepEqual(match, right) {
rightPriority = len(priorities) - index - 1
}
}
}
return leftPriority > rightPriority
})
return filteredEntries[0], filteredEntries
}
// MergeLayerTypes takes the name of buildpack plan entries that you want and
// the list buildpack plan entries you want merged layered types from. It
// returns the OR result of the launch and build keys for all of the buildpack
// plan entries with the specified name. The first return is the value of the
// OR launch the second return value is OR build.
func (p Planner) MergeLayerTypes(name string, entries []packit.BuildpackPlanEntry) (bool, bool) {
var launch, build bool
for _, e := range entries {
if e.Name == name {
for _, phase := range []string{"build", "launch"} {
if e.Metadata[phase] == true {
switch phase {
case "build":
build = true
case "launch":
launch = true
}
}
}
}
}
return launch, build
}