mirror of https://github.com/k3s-io/k3s
implement sorting of managedFields
parent
822c0da844
commit
9ac127408d
|
@ -8,6 +8,7 @@ go_library(
|
||||||
"gvkparser.go",
|
"gvkparser.go",
|
||||||
"managedfields.go",
|
"managedfields.go",
|
||||||
"pathelement.go",
|
"pathelement.go",
|
||||||
|
"sort.go",
|
||||||
"typeconverter.go",
|
"typeconverter.go",
|
||||||
"versionconverter.go",
|
"versionconverter.go",
|
||||||
],
|
],
|
||||||
|
|
|
@ -150,6 +150,24 @@ func encodeManagedFields(managedFields fieldpath.ManagedFields) (encodedManagedF
|
||||||
}
|
}
|
||||||
|
|
||||||
func sortEncodedManagedFields(encodedManagedFields []metav1.ManagedFieldsEntry) (sortedManagedFields []metav1.ManagedFieldsEntry, err error) {
|
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
|
return encodedManagedFields, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,10 @@ limitations under the License.
|
||||||
package internal
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
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
|
// (api format) to the format used by sigs.k8s.io/structured-merge-diff and back
|
||||||
func TestRoundTripManagedFields(t *testing.T) {
|
func TestRoundTripManagedFields(t *testing.T) {
|
||||||
tests := []string{
|
tests := []string{
|
||||||
`- apiVersion: v1
|
`- apiVersion: v1beta1
|
||||||
|
fields:
|
||||||
|
i:5:
|
||||||
|
f:i: {}
|
||||||
|
manager: foo
|
||||||
|
operation: Update
|
||||||
|
time: "2011-12-13T14:15:16Z"
|
||||||
|
- apiVersion: v1
|
||||||
fields:
|
fields:
|
||||||
v:3:
|
v:3:
|
||||||
f:alsoPi: {}
|
f:alsoPi: {}
|
||||||
|
@ -40,13 +49,6 @@ func TestRoundTripManagedFields(t *testing.T) {
|
||||||
manager: foo
|
manager: foo
|
||||||
operation: Update
|
operation: Update
|
||||||
time: "2001-02-03T04:05:06Z"
|
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
|
`- apiVersion: v1
|
||||||
fields:
|
fields:
|
||||||
|
@ -205,13 +207,85 @@ func TestSortEncodedManagedFields(t *testing.T) {
|
||||||
managedFields []metav1.ManagedFieldsEntry
|
managedFields []metav1.ManagedFieldsEntry
|
||||||
expected []metav1.ManagedFieldsEntry
|
expected []metav1.ManagedFieldsEntry
|
||||||
}{
|
}{
|
||||||
|
{
|
||||||
|
name: "empty",
|
||||||
|
managedFields: []metav1.ManagedFieldsEntry{},
|
||||||
|
expected: []metav1.ManagedFieldsEntry{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "nil",
|
||||||
|
managedFields: nil,
|
||||||
|
expected: nil,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "remains untouched",
|
name: "remains untouched",
|
||||||
managedFields: []metav1.ManagedFieldsEntry{
|
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{
|
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