ref(kind_sorter): use an in-place sort for sortManifestsByKind, reduce code duplication

Signed-off-by: Matthew Fisher <matt.fisher@microsoft.com>
pull/7499/head
Matthew Fisher 4 years ago
parent 9a2ff7802f
commit 671ceb5514
No known key found for this signature in database
GPG Key ID: 92AA783CBAAE8E3B

@ -103,84 +103,42 @@ var UninstallOrder KindSortOrder = []string{
"Namespace",
}
// sort manifests by kind (out of place sort)
// sort manifests by kind.
//
// Results are sorted by 'ordering', keeping order of items with equal kind/priority
func manifestsSortedByKind(manifests []Manifest, ordering KindSortOrder) []Manifest {
k := make([]string, len(manifests))
for i, h := range manifests {
k[i] = h.Head.Kind
}
ks := newKindSorter(k, ordering)
sort.Stable(ks)
func sortManifestsByKind(manifests []Manifest, ordering KindSortOrder) []Manifest {
sort.SliceStable(manifests, func(i, j int) bool {
return lessByKind(manifests[i], manifests[j], manifests[i].Head.Kind, manifests[j].Head.Kind, ordering)
})
// apply permutation
sorted := make([]Manifest, len(manifests))
for i, p := range ks.permutation {
sorted[i] = manifests[p]
}
return sorted
return manifests
}
// sort hooks by kind (out of place sort)
// sort hooks by kind, using an out-of-place sort to preserve the input parameters.
//
// Results are sorted by 'ordering', keeping order of items with equal kind/priority
func hooksSortedByKind(hooks []*release.Hook, ordering KindSortOrder) []*release.Hook {
k := make([]string, len(hooks))
for i, h := range hooks {
k[i] = h.Kind
}
ks := newKindSorter(k, ordering)
sort.Stable(ks)
// apply permutation
sorted := make([]*release.Hook, len(hooks))
for i, p := range ks.permutation {
sorted[i] = hooks[p]
}
return sorted
}
func sortHooksByKind(hooks []*release.Hook, ordering KindSortOrder) []*release.Hook {
h := hooks
sort.SliceStable(h, func(i, j int) bool {
return lessByKind(h[i], h[j], h[i].Kind, h[j].Kind, ordering)
})
type kindSorter struct {
permutation []int
ordering map[string]int
kinds []string
return h
}
func newKindSorter(kinds []string, s KindSortOrder) *kindSorter {
o := make(map[string]int, len(s))
for v, k := range s {
o[k] = v
func lessByKind(a interface{}, b interface{}, kindA string, kindB string, o KindSortOrder) bool {
ordering := make(map[string]int, len(o))
for v, k := range o {
ordering[k] = v
}
p := make([]int, len(kinds))
for i := range p {
p[i] = i
}
return &kindSorter{
permutation: p,
kinds: kinds,
ordering: o,
}
}
func (k *kindSorter) Len() int { return len(k.kinds) }
func (k *kindSorter) Swap(i, j int) {
k.permutation[i], k.permutation[j] = k.permutation[j], k.permutation[i]
}
func (k *kindSorter) Less(i, j int) bool {
a := k.kinds[k.permutation[i]]
b := k.kinds[k.permutation[j]]
first, aok := k.ordering[a]
second, bok := k.ordering[b]
first, aok := ordering[kindA]
second, bok := ordering[kindB]
if !aok && !bok {
// if both are unknown then sort alphabetically by kind, keep original order if same kind
if a != b {
return a < b
if kindA != kindB {
return kindA < kindB
}
return first < second
}

@ -177,12 +177,18 @@ func TestKindSorter(t *testing.T) {
t.Fatalf("Expected %d names in order, got %d", want, got)
}
defer buf.Reset()
for _, r := range manifestsSortedByKind(manifests, test.order) {
orig := manifests
for _, r := range sortManifestsByKind(manifests, test.order) {
buf.WriteString(r.Name)
}
if got := buf.String(); got != test.expected {
t.Errorf("Expected %q, got %q", test.expected, got)
}
for i, manifest := range orig {
if manifest != manifests[i] {
t.Fatal("Expected input to sortManifestsByKind to stay the same")
}
}
})
}
}
@ -238,7 +244,7 @@ func TestKindSorterKeepOriginalOrder(t *testing.T) {
var buf bytes.Buffer
t.Run(test.description, func(t *testing.T) {
defer buf.Reset()
for _, r := range manifestsSortedByKind(manifests, test.order) {
for _, r := range sortManifestsByKind(manifests, test.order) {
buf.WriteString(r.Name)
}
if got := buf.String(); got != test.expected {
@ -259,7 +265,7 @@ func TestKindSorterNamespaceAgainstUnknown(t *testing.T) {
}
manifests := []Manifest{unknown, namespace}
manifests = manifestsSortedByKind(manifests, InstallOrder)
manifests = sortManifestsByKind(manifests, InstallOrder)
expectedOrder := []Manifest{namespace, unknown}
for i, manifest := range manifests {
@ -269,7 +275,7 @@ func TestKindSorterNamespaceAgainstUnknown(t *testing.T) {
}
}
// test hook sorting with a small subset of kinds, since it uses the same algorithm as manifestsSortedByKind
// test hook sorting with a small subset of kinds, since it uses the same algorithm as sortManifestsByKind
func TestKindSorterForHooks(t *testing.T) {
hooks := []*release.Hook{
{
@ -304,9 +310,15 @@ func TestKindSorterForHooks(t *testing.T) {
t.Fatalf("Expected %d names in order, got %d", want, got)
}
defer buf.Reset()
for _, r := range hooksSortedByKind(hooks, test.order) {
orig := hooks
for _, r := range sortHooksByKind(hooks, test.order) {
buf.WriteString(r.Name)
}
for i, hook := range orig {
if hook != hooks[i] {
t.Fatal("Expected input to sortHooksByKind to stay the same")
}
}
if got := buf.String(); got != test.expected {
t.Errorf("Expected %q, got %q", test.expected, got)
}

@ -108,7 +108,7 @@ func SortManifests(files map[string]string, apis chartutil.VersionSet, ordering
}
}
return hooksSortedByKind(result.hooks, ordering), manifestsSortedByKind(result.generic, ordering), nil
return sortHooksByKind(result.hooks, ordering), sortManifestsByKind(result.generic, ordering), nil
}
// sort takes a manifestFile object which may contain multiple resource definition

@ -219,7 +219,7 @@ metadata:
}
}
sorted = manifestsSortedByKind(sorted, InstallOrder)
sorted = sortManifestsByKind(sorted, InstallOrder)
for i, m := range generic {
if m.Content != sorted[i].Content {
t.Errorf("Expected %q, got %q", m.Content, sorted[i].Content)

Loading…
Cancel
Save