mirror of https://github.com/k3s-io/k3s
implement sorting of managedFields
parent
822c0da844
commit
9ac127408d
|
@ -8,6 +8,7 @@ go_library(
|
|||
"gvkparser.go",
|
||||
"managedfields.go",
|
||||
"pathelement.go",
|
||||
"sort.go",
|
||||
"typeconverter.go",
|
||||
"versionconverter.go",
|
||||
],
|
||||
|
|
|
@ -150,6 +150,24 @@ func encodeManagedFields(managedFields fieldpath.ManagedFields) (encodedManagedF
|
|||
}
|
||||
|
||||
func sortEncodedManagedFields(encodedManagedFields []metav1.ManagedFieldsEntry) (sortedManagedFields []metav1.ManagedFieldsEntry, err error) {
|
||||
operation := func(p, q metav1.ManagedFieldsEntry) bool {
|
||||
return p.Operation < q.Operation
|
||||
}
|
||||
timestamp := func(p, q metav1.ManagedFieldsEntry) bool {
|
||||
if p.Time == nil || q.Time == nil {
|
||||
return false
|
||||
}
|
||||
return q.Time.Before(p.Time)
|
||||
}
|
||||
manager := func(p, q metav1.ManagedFieldsEntry) bool {
|
||||
return p.Manager < q.Manager
|
||||
}
|
||||
|
||||
sorter := &managedFieldsSorter{
|
||||
less: []managedFieldsLessFunc{operation, timestamp, manager},
|
||||
}
|
||||
|
||||
sorter.Sort(encodedManagedFields)
|
||||
return encodedManagedFields, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -17,8 +17,10 @@ limitations under the License.
|
|||
package internal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
|
@ -29,7 +31,14 @@ import (
|
|||
// (api format) to the format used by sigs.k8s.io/structured-merge-diff and back
|
||||
func TestRoundTripManagedFields(t *testing.T) {
|
||||
tests := []string{
|
||||
`- apiVersion: v1
|
||||
`- apiVersion: v1beta1
|
||||
fields:
|
||||
i:5:
|
||||
f:i: {}
|
||||
manager: foo
|
||||
operation: Update
|
||||
time: "2011-12-13T14:15:16Z"
|
||||
- apiVersion: v1
|
||||
fields:
|
||||
v:3:
|
||||
f:alsoPi: {}
|
||||
|
@ -40,13 +49,6 @@ func TestRoundTripManagedFields(t *testing.T) {
|
|||
manager: foo
|
||||
operation: Update
|
||||
time: "2001-02-03T04:05:06Z"
|
||||
- apiVersion: v1beta1
|
||||
fields:
|
||||
i:5:
|
||||
f:i: {}
|
||||
manager: foo
|
||||
operation: Update
|
||||
time: "2011-12-13T14:15:16Z"
|
||||
`,
|
||||
`- apiVersion: v1
|
||||
fields:
|
||||
|
@ -205,13 +207,85 @@ func TestSortEncodedManagedFields(t *testing.T) {
|
|||
managedFields []metav1.ManagedFieldsEntry
|
||||
expected []metav1.ManagedFieldsEntry
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
managedFields: []metav1.ManagedFieldsEntry{},
|
||||
expected: []metav1.ManagedFieldsEntry{},
|
||||
},
|
||||
{
|
||||
name: "nil",
|
||||
managedFields: nil,
|
||||
expected: nil,
|
||||
},
|
||||
{
|
||||
name: "remains untouched",
|
||||
managedFields: []metav1.ManagedFieldsEntry{
|
||||
{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: &metav1.Time{}},
|
||||
{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
|
||||
{Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
|
||||
},
|
||||
expected: []metav1.ManagedFieldsEntry{
|
||||
{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: &metav1.Time{}},
|
||||
{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
|
||||
{Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "apply first",
|
||||
managedFields: []metav1.ManagedFieldsEntry{
|
||||
{Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
|
||||
{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
|
||||
},
|
||||
expected: []metav1.ManagedFieldsEntry{
|
||||
{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
|
||||
{Manager: "a", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "newest first",
|
||||
managedFields: []metav1.ManagedFieldsEntry{
|
||||
{Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
|
||||
{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
|
||||
{Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")},
|
||||
{Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
|
||||
},
|
||||
expected: []metav1.ManagedFieldsEntry{
|
||||
{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
|
||||
{Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
|
||||
{Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")},
|
||||
{Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "manager last",
|
||||
managedFields: []metav1.ManagedFieldsEntry{
|
||||
{Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
|
||||
{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
|
||||
{Manager: "d", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")},
|
||||
{Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
|
||||
},
|
||||
expected: []metav1.ManagedFieldsEntry{
|
||||
{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
|
||||
{Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
|
||||
{Manager: "d", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")},
|
||||
{Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "manager sorted",
|
||||
managedFields: []metav1.ManagedFieldsEntry{
|
||||
{Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
|
||||
{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
|
||||
{Manager: "f", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")},
|
||||
{Manager: "d", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")},
|
||||
{Manager: "e", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")},
|
||||
{Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
|
||||
},
|
||||
expected: []metav1.ManagedFieldsEntry{
|
||||
{Manager: "a", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
|
||||
{Manager: "b", Operation: metav1.ManagedFieldsOperationApply, Time: nil},
|
||||
{Manager: "d", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")},
|
||||
{Manager: "e", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")},
|
||||
{Manager: "f", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2002-01-01T01:00:00Z")},
|
||||
{Manager: "c", Operation: metav1.ManagedFieldsOperationUpdate, Time: parseTimeOrPanic("2001-01-01T01:00:00Z")},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -228,3 +302,11 @@ func TestSortEncodedManagedFields(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func parseTimeOrPanic(s string) *metav1.Time {
|
||||
t, err := time.Parse(time.RFC3339, s)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("failed to parse time %s, got: %v", s, err))
|
||||
}
|
||||
return &metav1.Time{Time: t.UTC()}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
Copyright 2019 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
type managedFieldsLessFunc func(p, q metav1.ManagedFieldsEntry) bool
|
||||
|
||||
type managedFieldsSorter struct {
|
||||
fields []metav1.ManagedFieldsEntry
|
||||
less []managedFieldsLessFunc
|
||||
}
|
||||
|
||||
func (s *managedFieldsSorter) Sort(fields []metav1.ManagedFieldsEntry) {
|
||||
s.fields = fields
|
||||
sort.Sort(s)
|
||||
}
|
||||
|
||||
// Len is the amount of managedFields to sort
|
||||
func (s *managedFieldsSorter) Len() int {
|
||||
return len(s.fields)
|
||||
}
|
||||
|
||||
// Swap is part of sort.Interface.
|
||||
func (s *managedFieldsSorter) Swap(p, q int) {
|
||||
s.fields[p], s.fields[q] = s.fields[q], s.fields[p]
|
||||
}
|
||||
|
||||
// Less is part of sort.Interface
|
||||
func (s *managedFieldsSorter) Less(p, q int) bool {
|
||||
a, b := s.fields[p], s.fields[q]
|
||||
var k int
|
||||
for k = 0; k < len(s.less)-1; k++ {
|
||||
less := s.less[k]
|
||||
switch {
|
||||
case less(a, b):
|
||||
return true
|
||||
case less(b, a):
|
||||
return false
|
||||
}
|
||||
}
|
||||
return s.less[k](a, b)
|
||||
}
|
Loading…
Reference in New Issue