diff --git a/go.mod b/go.mod index 52daa35be18..89a44b4442d 100644 --- a/go.mod +++ b/go.mod @@ -559,7 +559,7 @@ replace ( mvdan.cc/lint => mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b mvdan.cc/unparam => mvdan.cc/unparam v0.0.0-20190209190245-fbb59629db34 sigs.k8s.io/kustomize => sigs.k8s.io/kustomize v2.0.3+incompatible - sigs.k8s.io/structured-merge-diff => sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca + sigs.k8s.io/structured-merge-diff => sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 sigs.k8s.io/yaml => sigs.k8s.io/yaml v1.1.0 sourcegraph.com/sqs/pbtypes => sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4 vbom.ml/util => vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc diff --git a/go.sum b/go.sum index c7f3ec9902a..75cd2a858ff 100644 --- a/go.sum +++ b/go.sum @@ -601,8 +601,8 @@ mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jC mvdan.cc/unparam v0.0.0-20190209190245-fbb59629db34/go.mod h1:H6SUd1XjIs+qQCyskXg5OFSrilMRUkD8ePJpHKDPaeY= sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0= sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= -sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca h1:6dsH6AYQWbyZmtttJNe8Gq1cXOeS1BdV3eW37zHilAQ= -sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/staging/src/k8s.io/apiextensions-apiserver/go.sum b/staging/src/k8s.io/apiextensions-apiserver/go.sum index f7709b70069..3620a486d58 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/go.sum +++ b/staging/src/k8s.io/apiextensions-apiserver/go.sum @@ -446,7 +446,7 @@ modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e h1:4Z09Hglb792X0kfOBBJUPFEyvVfQWrYT/l8h5EKA6JQ= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca h1:6dsH6AYQWbyZmtttJNe8Gq1cXOeS1BdV3eW37zHilAQ= -sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/staging/src/k8s.io/apiserver/go.mod b/staging/src/k8s.io/apiserver/go.mod index c6a38dd4074..d3f91ceac62 100644 --- a/staging/src/k8s.io/apiserver/go.mod +++ b/staging/src/k8s.io/apiserver/go.mod @@ -50,7 +50,7 @@ require ( k8s.io/klog v1.0.0 k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a k8s.io/utils v0.0.0-20191030222137-2b95a09bc58d - sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca + sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 sigs.k8s.io/yaml v1.1.0 ) diff --git a/staging/src/k8s.io/apiserver/go.sum b/staging/src/k8s.io/apiserver/go.sum index 6768b1fc7bd..3b1450e5166 100644 --- a/staging/src/k8s.io/apiserver/go.sum +++ b/staging/src/k8s.io/apiserver/go.sum @@ -357,7 +357,7 @@ k8s.io/utils v0.0.0-20191030222137-2b95a09bc58d h1:1P0iBJsBzxRmR+dIFnM+Iu4aLxnoa k8s.io/utils v0.0.0-20191030222137-2b95a09bc58d/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e h1:4Z09Hglb792X0kfOBBJUPFEyvVfQWrYT/l8h5EKA6JQ= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca h1:6dsH6AYQWbyZmtttJNe8Gq1cXOeS1BdV3eW37zHilAQ= -sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/pathelement.go b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/pathelement.go index 62f41507dcf..087b7636a00 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/pathelement.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/fieldmanager/internal/pathelement.go @@ -77,7 +77,7 @@ func NewPathElement(s string) (fieldpath.PathElement, error) { if err != nil { return fieldpath.PathElement{}, err } - fields := []value.Field{} + fields := value.FieldList{} for k, v := range kv { b, err := json.Marshal(v) if err != nil { @@ -94,7 +94,7 @@ func NewPathElement(s string) (fieldpath.PathElement, error) { }) } return fieldpath.PathElement{ - Key: &value.Map{Items: fields}, + Key: &fields, }, nil default: // Ignore unknown key types @@ -109,7 +109,7 @@ func PathElementString(pe fieldpath.PathElement) (string, error) { return Field + Separator + *pe.FieldName, nil case pe.Key != nil: kv := map[string]json.RawMessage{} - for _, k := range pe.Key.Items { + for _, k := range *pe.Key { b, err := k.Value.ToJSON() if err != nil { return "", err diff --git a/staging/src/k8s.io/kube-aggregator/go.sum b/staging/src/k8s.io/kube-aggregator/go.sum index 3408b2ed87e..d53fc8af7d3 100644 --- a/staging/src/k8s.io/kube-aggregator/go.sum +++ b/staging/src/k8s.io/kube-aggregator/go.sum @@ -397,7 +397,7 @@ modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e h1:4Z09Hglb792X0kfOBBJUPFEyvVfQWrYT/l8h5EKA6JQ= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca h1:6dsH6AYQWbyZmtttJNe8Gq1cXOeS1BdV3eW37zHilAQ= -sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/staging/src/k8s.io/legacy-cloud-providers/go.sum b/staging/src/k8s.io/legacy-cloud-providers/go.sum index 9538fbe655c..3a72c96de4f 100644 --- a/staging/src/k8s.io/legacy-cloud-providers/go.sum +++ b/staging/src/k8s.io/legacy-cloud-providers/go.sum @@ -352,6 +352,6 @@ k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKf k8s.io/utils v0.0.0-20191030222137-2b95a09bc58d h1:1P0iBJsBzxRmR+dIFnM+Iu4aLxnoa7lBqozW/0uHbT8= k8s.io/utils v0.0.0-20191030222137-2b95a09bc58d/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/staging/src/k8s.io/sample-apiserver/go.sum b/staging/src/k8s.io/sample-apiserver/go.sum index e5a23c92bbd..52040a5bebc 100644 --- a/staging/src/k8s.io/sample-apiserver/go.sum +++ b/staging/src/k8s.io/sample-apiserver/go.sum @@ -394,7 +394,7 @@ modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e h1:4Z09Hglb792X0kfOBBJUPFEyvVfQWrYT/l8h5EKA6JQ= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= -sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca h1:6dsH6AYQWbyZmtttJNe8Gq1cXOeS1BdV3eW37zHilAQ= -sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU= +sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/vendor/modules.txt b/vendor/modules.txt index 88a3877776c..68133036667 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1929,7 +1929,7 @@ sigs.k8s.io/kustomize/pkg/transformers sigs.k8s.io/kustomize/pkg/transformers/config sigs.k8s.io/kustomize/pkg/transformers/config/defaultconfig sigs.k8s.io/kustomize/pkg/types -# sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca => sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca +# sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 => sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 sigs.k8s.io/structured-merge-diff/fieldpath sigs.k8s.io/structured-merge-diff/merge sigs.k8s.io/structured-merge-diff/schema diff --git a/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/BUILD b/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/BUILD index f04464bba6e..2b8844676b5 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/BUILD +++ b/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/BUILD @@ -8,6 +8,7 @@ go_library( "fromvalue.go", "managers.go", "path.go", + "pathelementmap.go", "serialize.go", "serialize-pe.go", "set.go", diff --git a/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/element.go b/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/element.go index 9783c3bac53..841558a606f 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/element.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/element.go @@ -35,7 +35,7 @@ type PathElement struct { // Key selects the list element which has fields matching those given. // The containing object must be an associative list with map typed // elements. - Key *value.Map + Key *value.FieldList // Value selects the list element with the given value. The containing // object must be an associative list with a primitive typed element @@ -62,7 +62,7 @@ func (e PathElement) Less(rhs PathElement) bool { if rhs.Key == nil { return true } - return e.Key.Less(rhs.Key) + return e.Key.Less(*rhs.Key) } else if rhs.Key != nil { return false } @@ -101,13 +101,11 @@ func (e PathElement) String() string { case e.FieldName != nil: return "." + *e.FieldName case e.Key != nil: - strs := make([]string, len(e.Key.Items)) - for i, k := range e.Key.Items { + strs := make([]string, len(*e.Key)) + for i, k := range *e.Key { strs[i] = fmt.Sprintf("%v=%v", k.Name, k.Value) } - // The order must be canonical, since we use the string value - // in a set structure. - sort.Strings(strs) + // Keys are supposed to be sorted. return "[" + strings.Join(strs, ",") + "]" case e.Value != nil: return fmt.Sprintf("[=%v]", e.Value) @@ -123,18 +121,19 @@ func (e PathElement) String() string { // names (type must be string) with values (type must be value.Value). If these // conditions are not met, KeyByFields will panic--it's intended for static // construction and shouldn't have user-produced values passed to it. -func KeyByFields(nameValues ...interface{}) []value.Field { +func KeyByFields(nameValues ...interface{}) *value.FieldList { if len(nameValues)%2 != 0 { panic("must have a value for every name") } - out := []value.Field{} + out := value.FieldList{} for i := 0; i < len(nameValues)-1; i += 2 { out = append(out, value.Field{ Name: nameValues[i].(string), Value: nameValues[i+1].(value.Value), }) } - return out + out.Sort() + return &out } // PathElementSet is a set of path elements. @@ -143,6 +142,12 @@ type PathElementSet struct { members sortedPathElements } +func MakePathElementSet(size int) PathElementSet { + return PathElementSet{ + members: make(sortedPathElements, 0, size), + } +} + type sortedPathElements []PathElement // Implement the sort interface; this would permit bulk creation, which would diff --git a/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/fromvalue.go b/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/fromvalue.go index 830880fb49d..3f9eaf63dab 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/fromvalue.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/fromvalue.go @@ -104,7 +104,7 @@ func GuessBestListPathElement(index int, item value.Value) PathElement { return PathElement{Index: &index} } - var keys []value.Field + var keys value.FieldList for _, name := range AssociativeListCandidateFieldNames { f, ok := item.MapValue.Get(name) if !ok { @@ -117,7 +117,8 @@ func GuessBestListPathElement(index int, item value.Value) PathElement { keys = append(keys, *f) } if len(keys) > 0 { - return PathElement{Key: &value.Map{Items: keys}} + keys.Sort() + return PathElement{Key: &keys} } return PathElement{Index: &index} } diff --git a/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/path.go b/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/path.go index ca80e7cca79..bdf6ce90fd1 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/path.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/path.go @@ -88,11 +88,11 @@ func MakePath(parts ...interface{}) (Path, error) { fp = append(fp, PathElement{Index: &t}) case string: fp = append(fp, PathElement{FieldName: &t}) - case []value.Field: - if len(t) == 0 { + case *value.FieldList: + if len(*t) == 0 { return nil, fmt.Errorf("associative list key type path elements must have at least one key (got zero)") } - fp = append(fp, PathElement{Key: &value.Map{Items: t}}) + fp = append(fp, PathElement{Key: t}) case value.Value: // TODO: understand schema and verify that this is a set type // TODO: make a copy of t diff --git a/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/pathelementmap.go b/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/pathelementmap.go new file mode 100644 index 00000000000..f35089a1ca5 --- /dev/null +++ b/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/pathelementmap.go @@ -0,0 +1,85 @@ +/* +Copyright 2018 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 fieldpath + +import ( + "sort" + + "sigs.k8s.io/structured-merge-diff/value" +) + +// PathElementValueMap is a map from PathElement to value.Value. +// +// TODO(apelisse): We have multiple very similar implementation of this +// for PathElementSet and SetNodeMap, so we could probably share the +// code. +type PathElementValueMap struct { + members sortedPathElementValues +} + +func MakePathElementValueMap(size int) PathElementValueMap { + return PathElementValueMap{ + members: make(sortedPathElementValues, 0, size), + } +} + +type pathElementValue struct { + PathElement PathElement + Value value.Value +} + +type sortedPathElementValues []pathElementValue + +// Implement the sort interface; this would permit bulk creation, which would +// be faster than doing it one at a time via Insert. +func (spev sortedPathElementValues) Len() int { return len(spev) } +func (spev sortedPathElementValues) Less(i, j int) bool { + return spev[i].PathElement.Less(spev[j].PathElement) +} +func (spev sortedPathElementValues) Swap(i, j int) { spev[i], spev[j] = spev[j], spev[i] } + +// Insert adds the pathelement and associated value in the map. +func (s *PathElementValueMap) Insert(pe PathElement, v value.Value) { + loc := sort.Search(len(s.members), func(i int) bool { + return !s.members[i].PathElement.Less(pe) + }) + if loc == len(s.members) { + s.members = append(s.members, pathElementValue{pe, v}) + return + } + if s.members[loc].PathElement.Equals(pe) { + return + } + s.members = append(s.members, pathElementValue{}) + copy(s.members[loc+1:], s.members[loc:]) + s.members[loc] = pathElementValue{pe, v} +} + +// Get retrieves the value associated with the given PathElement from the map. +// (nil, false) is returned if there is no such PathElement. +func (s *PathElementValueMap) Get(pe PathElement) (value.Value, bool) { + loc := sort.Search(len(s.members), func(i int) bool { + return !s.members[i].PathElement.Less(pe) + }) + if loc == len(s.members) { + return value.Value{}, false + } + if s.members[loc].PathElement.Equals(pe) { + return s.members[loc].Value, true + } + return value.Value{}, false +} diff --git a/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/serialize-pe.go b/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/serialize-pe.go index a0338fa66ef..e491fce1e7d 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/serialize-pe.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/serialize-pe.go @@ -83,14 +83,18 @@ func DeserializePathElement(s string) (PathElement, error) { case peKeySepBytes[0]: iter := readPool.BorrowIterator(b) defer readPool.ReturnIterator(iter) - v, err := value.ReadJSONIter(iter) - if err != nil { - return PathElement{}, err - } - if v.MapValue == nil { - return PathElement{}, fmt.Errorf("expected key value pairs but got %#v", v) - } - return PathElement{Key: v.MapValue}, nil + fields := value.FieldList{} + iter.ReadObjectCB(func(iter *jsoniter.Iterator, key string) bool { + v, err := value.ReadJSONIter(iter) + if err != nil { + iter.Error = err + return false + } + fields = append(fields, value.Field{Name: key, Value: v}) + return true + }) + fields.Sort() + return PathElement{Key: &fields}, iter.Error case peIndexSepBytes[0]: i, err := strconv.Atoi(s[2:]) if err != nil { @@ -129,8 +133,15 @@ func serializePathElementToWriter(w io.Writer, pe PathElement) error { if _, err := stream.Write(peKeySepBytes); err != nil { return err } - v := value.Value{MapValue: pe.Key} - v.WriteJSONStream(stream) + stream.WriteObjectStart() + for i, field := range *pe.Key { + if i > 0 { + stream.WriteMore() + } + stream.WriteObjectField(field.Name) + field.Value.WriteJSONStream(stream) + } + stream.WriteObjectEnd() case pe.Value != nil: if _, err := stream.Write(peValueSepBytes); err != nil { return err diff --git a/vendor/sigs.k8s.io/structured-merge-diff/merge/update.go b/vendor/sigs.k8s.io/structured-merge-diff/merge/update.go index 96c9751ac78..75d599077c9 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/merge/update.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/merge/update.go @@ -41,12 +41,12 @@ func (s *Updater) EnableUnionFeature() { s.enableUnions = true } -func (s *Updater) update(oldObject, newObject *typed.TypedValue, version fieldpath.APIVersion, managers fieldpath.ManagedFields, workflow string, force bool) (fieldpath.ManagedFields, error) { +func (s *Updater) update(oldObject, newObject *typed.TypedValue, version fieldpath.APIVersion, managers fieldpath.ManagedFields, workflow string, force bool) (fieldpath.ManagedFields, *typed.Comparison, error) { conflicts := fieldpath.ManagedFields{} removed := fieldpath.ManagedFields{} compare, err := oldObject.Compare(newObject) if err != nil { - return nil, fmt.Errorf("failed to compare objects: %v", err) + return nil, nil, fmt.Errorf("failed to compare objects: %v", err) } versions := map[fieldpath.APIVersion]*typed.Comparison{ @@ -66,7 +66,7 @@ func (s *Updater) update(oldObject, newObject *typed.TypedValue, version fieldpa delete(managers, manager) continue } - return nil, fmt.Errorf("failed to convert old object: %v", err) + return nil, nil, fmt.Errorf("failed to convert old object: %v", err) } versionedNewObject, err := s.Converter.Convert(newObject, managerSet.APIVersion()) if err != nil { @@ -74,11 +74,11 @@ func (s *Updater) update(oldObject, newObject *typed.TypedValue, version fieldpa delete(managers, manager) continue } - return nil, fmt.Errorf("failed to convert new object: %v", err) + return nil, nil, fmt.Errorf("failed to convert new object: %v", err) } compare, err = versionedOldObject.Compare(versionedNewObject) if err != nil { - return nil, fmt.Errorf("failed to compare objects: %v", err) + return nil, nil, fmt.Errorf("failed to compare objects: %v", err) } versions[managerSet.APIVersion()] = compare } @@ -94,7 +94,7 @@ func (s *Updater) update(oldObject, newObject *typed.TypedValue, version fieldpa } if !force && len(conflicts) != 0 { - return nil, ConflictsFromManagers(conflicts) + return nil, nil, ConflictsFromManagers(conflicts) } for manager, conflictSet := range conflicts { @@ -111,7 +111,7 @@ func (s *Updater) update(oldObject, newObject *typed.TypedValue, version fieldpa } } - return managers, nil + return managers, compare, nil } // Update is the method you should call once you've merged your final @@ -128,14 +128,10 @@ func (s *Updater) Update(liveObject, newObject *typed.TypedValue, version fieldp } } managers = shallowCopyManagers(managers) - managers, err = s.update(liveObject, newObject, version, managers, manager, true) + managers, compare, err := s.update(liveObject, newObject, version, managers, manager, true) if err != nil { return nil, fieldpath.ManagedFields{}, err } - compare, err := liveObject.Compare(newObject) - if err != nil { - return nil, fieldpath.ManagedFields{}, fmt.Errorf("failed to compare live and new objects: %v", err) - } if _, ok := managers[manager]; !ok { managers[manager] = fieldpath.NewVersionedSet(fieldpath.NewSet(), version, false) } @@ -182,7 +178,7 @@ func (s *Updater) Apply(liveObject, configObject *typed.TypedValue, version fiel if err != nil { return nil, fieldpath.ManagedFields{}, fmt.Errorf("failed to prune fields: %v", err) } - managers, err = s.update(liveObject, newObject, version, managers, manager, force) + managers, _, err = s.update(liveObject, newObject, version, managers, manager, force) if err != nil { return nil, fieldpath.ManagedFields{}, err } diff --git a/vendor/sigs.k8s.io/structured-merge-diff/schema/elements.go b/vendor/sigs.k8s.io/structured-merge-diff/schema/elements.go index 4338696aa56..5a2859e455b 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/schema/elements.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/schema/elements.go @@ -16,9 +16,17 @@ limitations under the License. package schema +import "sync" + // Schema is a list of named types. +// +// Schema types are indexed in a map before the first search so this type +// should be considered immutable. type Schema struct { Types []TypeDef `yaml:"types,omitempty"` + + once sync.Once + m map[string]TypeDef } // A TypeSpecifier references a particular type in a schema. @@ -92,6 +100,9 @@ const ( // // Maps may also represent a type which is composed of a number of different fields. // Each field has a name and a type. +// +// Fields are indexed in a map before the first search so this type +// should be considered immutable. type Map struct { // Each struct field appears exactly once in this list. The order in // this list defines the canonical field ordering. @@ -117,6 +128,22 @@ type Map struct { // The default behavior for maps is `separable`; it's permitted to // leave this unset to get the default behavior. ElementRelationship ElementRelationship `yaml:"elementRelationship,omitempty"` + + once sync.Once + m map[string]StructField +} + +// FindField is a convenience function that returns the referenced StructField, +// if it exists, or (nil, false) if it doesn't. +func (m *Map) FindField(name string) (StructField, bool) { + m.once.Do(func() { + m.m = make(map[string]StructField, len(m.Fields)) + for _, field := range m.Fields { + m.m[field.Name] = field + } + }) + sf, ok := m.m[name] + return sf, ok } // UnionFields are mapping between the fields that are part of the union and @@ -204,13 +231,15 @@ type List struct { // FindNamedType is a convenience function that returns the referenced TypeDef, // if it exists, or (nil, false) if it doesn't. -func (s Schema) FindNamedType(name string) (TypeDef, bool) { - for _, t := range s.Types { - if t.Name == name { - return t, true +func (s *Schema) FindNamedType(name string) (TypeDef, bool) { + s.once.Do(func() { + s.m = make(map[string]TypeDef, len(s.Types)) + for _, t := range s.Types { + s.m[t.Name] = t } - } - return TypeDef{}, false + }) + t, ok := s.m[name] + return t, ok } // Resolve is a convenience function which returns the atom referenced, whether diff --git a/vendor/sigs.k8s.io/structured-merge-diff/typed/helpers.go b/vendor/sigs.k8s.io/structured-merge-diff/typed/helpers.go index a7c12ccb001..0911ce0b482 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/typed/helpers.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/typed/helpers.go @@ -97,9 +97,9 @@ func (ef errorFormatter) prefixError(prefix string, err error) ValidationErrors } type atomHandler interface { - doScalar(schema.Scalar) ValidationErrors - doList(schema.List) ValidationErrors - doMap(schema.Map) ValidationErrors + doScalar(*schema.Scalar) ValidationErrors + doList(*schema.List) ValidationErrors + doMap(*schema.Map) ValidationErrors errorf(msg string, args ...interface{}) ValidationErrors } @@ -130,11 +130,11 @@ func deduceAtom(a schema.Atom, v *value.Value) schema.Atom { func handleAtom(a schema.Atom, tr schema.TypeRef, ah atomHandler) ValidationErrors { switch { case a.Map != nil: - return ah.doMap(*a.Map) + return ah.doMap(a.Map) case a.Scalar != nil: - return ah.doScalar(*a.Scalar) + return ah.doScalar(a.Scalar) case a.List != nil: - return ah.doList(*a.List) + return ah.doList(a.List) } name := "inlined" @@ -145,14 +145,14 @@ func handleAtom(a schema.Atom, tr schema.TypeRef, ah atomHandler) ValidationErro return ah.errorf("schema error: invalid atom: %v", name) } -func (ef errorFormatter) validateScalar(t schema.Scalar, v *value.Value, prefix string) (errs ValidationErrors) { +func (ef errorFormatter) validateScalar(t *schema.Scalar, v *value.Value, prefix string) (errs ValidationErrors) { if v == nil { return nil } if v.Null { return nil } - switch t { + switch *t { case schema.Numeric: if v.FloatValue == nil && v.IntValue == nil { // TODO: should the schema separate int and float? @@ -195,7 +195,7 @@ func mapValue(val value.Value) (*value.Map, error) { } } -func keyedAssociativeListItemToPathElement(list schema.List, index int, child value.Value) (fieldpath.PathElement, error) { +func keyedAssociativeListItemToPathElement(list *schema.List, index int, child value.Value) (fieldpath.PathElement, error) { pe := fieldpath.PathElement{} if child.Null { // For now, the keys are required which means that null entries @@ -205,7 +205,7 @@ func keyedAssociativeListItemToPathElement(list schema.List, index int, child va if child.MapValue == nil { return pe, errors.New("associative list with keys may not have non-map elements") } - keyMap := &value.Map{} + keyMap := value.FieldList{} for _, fieldName := range list.Keys { var fieldValue value.Value field, ok := child.MapValue.Get(fieldName) @@ -215,13 +215,14 @@ func keyedAssociativeListItemToPathElement(list schema.List, index int, child va // Treat keys as required. return pe, fmt.Errorf("associative list with keys has an element that omits key field %q", fieldName) } - keyMap.Set(fieldName, fieldValue) + keyMap = append(keyMap, value.Field{Name: fieldName, Value: fieldValue}) } - pe.Key = keyMap + keyMap.Sort() + pe.Key = &keyMap return pe, nil } -func setItemToPathElement(list schema.List, index int, child value.Value) (fieldpath.PathElement, error) { +func setItemToPathElement(list *schema.List, index int, child value.Value) (fieldpath.PathElement, error) { pe := fieldpath.PathElement{} switch { case child.MapValue != nil: @@ -241,7 +242,7 @@ func setItemToPathElement(list schema.List, index int, child value.Value) (field } } -func listItemToPathElement(list schema.List, index int, child value.Value) (fieldpath.PathElement, error) { +func listItemToPathElement(list *schema.List, index int, child value.Value) (fieldpath.PathElement, error) { if list.ElementRelationship == schema.Associative { if len(list.Keys) > 0 { return keyedAssociativeListItemToPathElement(list, index, child) diff --git a/vendor/sigs.k8s.io/structured-merge-diff/typed/merge.go b/vendor/sigs.k8s.io/structured-merge-diff/typed/merge.go index 27bc8b24e37..bb92f84b499 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/typed/merge.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/typed/merge.go @@ -104,7 +104,7 @@ func (w *mergingWalker) doLeaf() { w.rule(w) } -func (w *mergingWalker) doScalar(t schema.Scalar) (errs ValidationErrors) { +func (w *mergingWalker) doScalar(t *schema.Scalar) (errs ValidationErrors) { errs = append(errs, w.validateScalar(t, w.lhs, "lhs: ")...) errs = append(errs, w.validateScalar(t, w.rhs, "rhs: ")...) if len(errs) > 0 { @@ -158,7 +158,7 @@ func (w *mergingWalker) derefMap(prefix string, v *value.Value, dest **value.Map return nil } -func (w *mergingWalker) visitListItems(t schema.List, lhs, rhs *value.List) (errs ValidationErrors) { +func (w *mergingWalker) visitListItems(t *schema.List, lhs, rhs *value.List) (errs ValidationErrors) { out := &value.List{} // TODO: ordering is totally wrong. @@ -168,8 +168,9 @@ func (w *mergingWalker) visitListItems(t schema.List, lhs, rhs *value.List) (err rhsOrder := []fieldpath.PathElement{} // First, collect all RHS children. - observedRHS := map[string]value.Value{} + var observedRHS fieldpath.PathElementValueMap if rhs != nil { + observedRHS = fieldpath.MakePathElementValueMap(len(rhs.Items)) for i, child := range rhs.Items { pe, err := listItemToPathElement(t, i, child) if err != nil { @@ -179,18 +180,18 @@ func (w *mergingWalker) visitListItems(t schema.List, lhs, rhs *value.List) (err // this element. continue } - keyStr := pe.String() - if _, found := observedRHS[keyStr]; found { - errs = append(errs, w.errorf("rhs: duplicate entries for key %v", keyStr)...) + if _, ok := observedRHS.Get(pe); ok { + errs = append(errs, w.errorf("rhs: duplicate entries for key %v", pe.String())...) } - observedRHS[keyStr] = child + observedRHS.Insert(pe, child) rhsOrder = append(rhsOrder, pe) } } // Then merge with LHS children. - observedLHS := map[string]struct{}{} + var observedLHS fieldpath.PathElementSet if lhs != nil { + observedLHS = fieldpath.MakePathElementSet(len(lhs.Items)) for i, child := range lhs.Items { pe, err := listItemToPathElement(t, i, child) if err != nil { @@ -200,15 +201,14 @@ func (w *mergingWalker) visitListItems(t schema.List, lhs, rhs *value.List) (err // this element. continue } - keyStr := pe.String() - if _, found := observedLHS[keyStr]; found { - errs = append(errs, w.errorf("lhs: duplicate entries for key %v", keyStr)...) + if observedLHS.Has(pe) { + errs = append(errs, w.errorf("lhs: duplicate entries for key %v", pe.String())...) continue } - observedLHS[keyStr] = struct{}{} + observedLHS.Insert(pe) w2 := w.prepareDescent(pe, t.ElementType) w2.lhs = &child - if rchild, ok := observedRHS[keyStr]; ok { + if rchild, ok := observedRHS.Get(pe); ok { w2.rhs = &rchild } if newErrs := w2.merge(); len(newErrs) > 0 { @@ -217,22 +217,22 @@ func (w *mergingWalker) visitListItems(t schema.List, lhs, rhs *value.List) (err out.Items = append(out.Items, *w2.out) } w.finishDescent(w2) - // Keep track of children that have been handled - delete(observedRHS, keyStr) } } - for _, rhsToCheck := range rhsOrder { - if unmergedChild, ok := observedRHS[rhsToCheck.String()]; ok { - w2 := w.prepareDescent(rhsToCheck, t.ElementType) - w2.rhs = &unmergedChild - if newErrs := w2.merge(); len(newErrs) > 0 { - errs = append(errs, newErrs...) - } else if w2.out != nil { - out.Items = append(out.Items, *w2.out) - } - w.finishDescent(w2) + for _, pe := range rhsOrder { + if observedLHS.Has(pe) { + continue } + value, _ := observedRHS.Get(pe) + w2 := w.prepareDescent(pe, t.ElementType) + w2.rhs = &value + if newErrs := w2.merge(); len(newErrs) > 0 { + errs = append(errs, newErrs...) + } else if w2.out != nil { + out.Items = append(out.Items, *w2.out) + } + w.finishDescent(w2) } if len(out.Items) > 0 { @@ -255,7 +255,7 @@ func (w *mergingWalker) derefList(prefix string, v *value.Value, dest **value.Li return nil } -func (w *mergingWalker) doList(t schema.List) (errs ValidationErrors) { +func (w *mergingWalker) doList(t *schema.List) (errs ValidationErrors) { var lhs, rhs *value.List w.derefList("lhs: ", w.lhs, &lhs) w.derefList("rhs: ", w.rhs, &rhs) @@ -280,23 +280,15 @@ func (w *mergingWalker) doList(t schema.List) (errs ValidationErrors) { return errs } -func (w *mergingWalker) visitMapItems(t schema.Map, lhs, rhs *value.Map) (errs ValidationErrors) { +func (w *mergingWalker) visitMapItems(t *schema.Map, lhs, rhs *value.Map) (errs ValidationErrors) { out := &value.Map{} - fieldTypes := map[string]schema.TypeRef{} - for i := range t.Fields { - // I don't want to use the loop variable since a reference - // might outlive the loop iteration (in an error message). - f := t.Fields[i] - fieldTypes[f.Name] = f.Type - } - if lhs != nil { for i := range lhs.Items { litem := &lhs.Items[i] fieldType := t.ElementType - if ft, ok := fieldTypes[litem.Name]; ok { - fieldType = ft + if sf, ok := t.FindField(litem.Name); ok { + fieldType = sf.Type } w2 := w.prepareDescent(fieldpath.PathElement{FieldName: &litem.Name}, fieldType) w2.lhs = &litem.Value @@ -324,8 +316,8 @@ func (w *mergingWalker) visitMapItems(t schema.Map, lhs, rhs *value.Map) (errs V } fieldType := t.ElementType - if ft, ok := fieldTypes[ritem.Name]; ok { - fieldType = ft + if sf, ok := t.FindField(ritem.Name); ok { + fieldType = sf.Type } w2 := w.prepareDescent(fieldpath.PathElement{FieldName: &ritem.Name}, fieldType) w2.rhs = &ritem.Value @@ -344,7 +336,7 @@ func (w *mergingWalker) visitMapItems(t schema.Map, lhs, rhs *value.Map) (errs V return errs } -func (w *mergingWalker) doMap(t schema.Map) (errs ValidationErrors) { +func (w *mergingWalker) doMap(t *schema.Map) (errs ValidationErrors) { var lhs, rhs *value.Map w.derefMap("lhs: ", w.lhs, &lhs) w.derefMap("rhs: ", w.rhs, &rhs) diff --git a/vendor/sigs.k8s.io/structured-merge-diff/typed/remove.go b/vendor/sigs.k8s.io/structured-merge-diff/typed/remove.go index 32e4b18b136..a6b748411fb 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/typed/remove.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/typed/remove.go @@ -38,9 +38,9 @@ func removeItemsWithSchema(value *value.Value, toRemove *fieldpath.Set, schema * // will be a descent. It modifies w.inLeaf. func (w *removingWalker) doLeaf() ValidationErrors { return nil } -func (w *removingWalker) doScalar(t schema.Scalar) ValidationErrors { return nil } +func (w *removingWalker) doScalar(t *schema.Scalar) ValidationErrors { return nil } -func (w *removingWalker) doList(t schema.List) (errs ValidationErrors) { +func (w *removingWalker) doList(t *schema.List) (errs ValidationErrors) { l := w.value.ListValue // If list is null, empty, or atomic just return @@ -70,7 +70,7 @@ func (w *removingWalker) doList(t schema.List) (errs ValidationErrors) { return nil } -func (w *removingWalker) doMap(t schema.Map) ValidationErrors { +func (w *removingWalker) doMap(t *schema.Map) ValidationErrors { m := w.value.MapValue // If map is null, empty, or atomic just return diff --git a/vendor/sigs.k8s.io/structured-merge-diff/typed/typed.go b/vendor/sigs.k8s.io/structured-merge-diff/typed/typed.go index 5db5018e5a1..9c61b84505b 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/typed/typed.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/typed/typed.go @@ -18,6 +18,7 @@ package typed import ( "fmt" + "strings" "sync" "sigs.k8s.io/structured-merge-diff/fieldpath" @@ -116,7 +117,7 @@ func (tv TypedValue) Compare(rhs *TypedValue) (c *Comparison, err error) { Modified: fieldpath.NewSet(), Added: fieldpath.NewSet(), } - c.Merged, err = merge(&tv, rhs, func(w *mergingWalker) { + _, err = merge(&tv, rhs, func(w *mergingWalker) { if w.lhs == nil { c.Added.Insert(w.path) } else if w.rhs == nil { @@ -126,8 +127,6 @@ func (tv TypedValue) Compare(rhs *TypedValue) (c *Comparison, err error) { // Need to implement equality check on the value type. c.Modified.Insert(w.path) } - - ruleKeepRHS(w) }, func(w *mergingWalker) { if w.lhs == nil { c.Added.Insert(w.path) @@ -268,10 +267,6 @@ func merge(lhs, rhs *TypedValue, rule, postRule mergeRule) (*TypedValue, error) // No field will appear in more than one of the three fieldsets. If all of the // fieldsets are empty, then the objects must have been equal. type Comparison struct { - // Merged is the result of merging the two objects, as explained in the - // comments on TypedValue.Merge(). - Merged *TypedValue - // Removed contains any fields removed by rhs (the right-hand-side // object in the comparison). Removed *fieldpath.Set @@ -289,15 +284,15 @@ func (c *Comparison) IsSame() bool { // String returns a human readable version of the comparison. func (c *Comparison) String() string { - str := fmt.Sprintf("- Merged Object:\n%v\n", c.Merged.AsValue()) + bld := strings.Builder{} if !c.Modified.Empty() { - str += fmt.Sprintf("- Modified Fields:\n%v\n", c.Modified) + bld.WriteString(fmt.Sprintf("- Modified Fields:\n%v\n", c.Modified)) } if !c.Added.Empty() { - str += fmt.Sprintf("- Added Fields:\n%v\n", c.Added) + bld.WriteString(fmt.Sprintf("- Added Fields:\n%v\n", c.Added)) } if !c.Removed.Empty() { - str += fmt.Sprintf("- Removed Fields:\n%v\n", c.Removed) + bld.WriteString(fmt.Sprintf("- Removed Fields:\n%v\n", c.Removed)) } - return str + return bld.String() } diff --git a/vendor/sigs.k8s.io/structured-merge-diff/typed/validate.go b/vendor/sigs.k8s.io/structured-merge-diff/typed/validate.go index 0a763247308..338c058310b 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/typed/validate.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/typed/validate.go @@ -130,7 +130,7 @@ func (v *validatingObjectWalker) doNode() { } } -func (v *validatingObjectWalker) doScalar(t schema.Scalar) ValidationErrors { +func (v *validatingObjectWalker) doScalar(t *schema.Scalar) ValidationErrors { if errs := v.validateScalar(t, &v.value, ""); len(errs) > 0 { return errs } @@ -141,8 +141,8 @@ func (v *validatingObjectWalker) doScalar(t schema.Scalar) ValidationErrors { return nil } -func (v *validatingObjectWalker) visitListItems(t schema.List, list *value.List) (errs ValidationErrors) { - observedKeys := map[string]struct{}{} +func (v *validatingObjectWalker) visitListItems(t *schema.List, list *value.List) (errs ValidationErrors) { + observedKeys := fieldpath.MakePathElementSet(len(list.Items)) for i, child := range list.Items { pe, err := listItemToPathElement(t, i, child) if err != nil { @@ -152,11 +152,10 @@ func (v *validatingObjectWalker) visitListItems(t schema.List, list *value.List) // this element. continue } - keyStr := pe.String() - if _, found := observedKeys[keyStr]; found { - errs = append(errs, v.errorf("duplicate entries for key %v", keyStr)...) + if observedKeys.Has(pe) { + errs = append(errs, v.errorf("duplicate entries for key %v", pe.String())...) } - observedKeys[keyStr] = struct{}{} + observedKeys.Insert(pe) v2 := v.prepareDescent(pe, t.ElementType) v2.value = child errs = append(errs, v2.validate()...) @@ -167,7 +166,7 @@ func (v *validatingObjectWalker) visitListItems(t schema.List, list *value.List) return errs } -func (v *validatingObjectWalker) doList(t schema.List) (errs ValidationErrors) { +func (v *validatingObjectWalker) doList(t *schema.List) (errs ValidationErrors) { list, err := listValue(v.value) if err != nil { return v.error(err) @@ -186,21 +185,13 @@ func (v *validatingObjectWalker) doList(t schema.List) (errs ValidationErrors) { return errs } -func (v *validatingObjectWalker) visitMapItems(t schema.Map, m *value.Map) (errs ValidationErrors) { - fieldTypes := map[string]schema.TypeRef{} - for i := range t.Fields { - // I don't want to use the loop variable since a reference - // might outlive the loop iteration (in an error message). - f := t.Fields[i] - fieldTypes[f.Name] = f.Type - } - +func (v *validatingObjectWalker) visitMapItems(t *schema.Map, m *value.Map) (errs ValidationErrors) { for i := range m.Items { item := &m.Items[i] pe := fieldpath.PathElement{FieldName: &item.Name} - if tr, ok := fieldTypes[item.Name]; ok { - v2 := v.prepareDescent(pe, tr) + if sf, ok := t.FindField(item.Name); ok { + v2 := v.prepareDescent(pe, sf.Type) v2.value = item.Value errs = append(errs, v2.validate()...) v.finishDescent(v2) @@ -215,7 +206,7 @@ func (v *validatingObjectWalker) visitMapItems(t schema.Map, m *value.Map) (errs return errs } -func (v *validatingObjectWalker) doMap(t schema.Map) (errs ValidationErrors) { +func (v *validatingObjectWalker) doMap(t *schema.Map) (errs ValidationErrors) { m, err := mapValue(v.value) if err != nil { return v.error(err) diff --git a/vendor/sigs.k8s.io/structured-merge-diff/value/value.go b/vendor/sigs.k8s.io/structured-merge-diff/value/value.go index 1ce63e1c970..942d797246a 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/value/value.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/value/value.go @@ -36,86 +36,146 @@ type Value struct { // Equals returns true iff the two values are equal. func (v Value) Equals(rhs Value) bool { - return !v.Less(rhs) && !rhs.Less(v) + if v.FloatValue != nil || rhs.FloatValue != nil { + var lf float64 + if v.FloatValue != nil { + lf = float64(*v.FloatValue) + } else if v.IntValue != nil { + lf = float64(*v.IntValue) + } else { + return false + } + var rf float64 + if rhs.FloatValue != nil { + rf = float64(*rhs.FloatValue) + } else if rhs.IntValue != nil { + rf = float64(*rhs.IntValue) + } else { + return false + } + return lf == rf + } + if v.IntValue != nil { + if rhs.IntValue != nil { + return *v.IntValue == *rhs.IntValue + } + return false + } + if v.StringValue != nil { + if rhs.StringValue != nil { + return *v.StringValue == *rhs.StringValue + } + return false + } + if v.BooleanValue != nil { + if rhs.BooleanValue != nil { + return *v.BooleanValue == *rhs.BooleanValue + } + return false + } + if v.ListValue != nil { + if rhs.ListValue != nil { + return v.ListValue.Equals(rhs.ListValue) + } + return false + } + if v.MapValue != nil { + if rhs.MapValue != nil { + return v.MapValue.Equals(rhs.MapValue) + } + return false + } + if v.Null { + if rhs.Null { + return true + } + return false + } + // No field is set, on either objects. + return true } // Less provides a total ordering for Value (so that they can be sorted, even // if they are of different types). func (v Value) Less(rhs Value) bool { + return v.Compare(rhs) == -1 +} + +// Compare provides a total ordering for Value (so that they can be +// sorted, even if they are of different types). The result will be 0 if +// v==rhs, -1 if v < rhs, and +1 if v > rhs. +func (v Value) Compare(rhs Value) int { if v.FloatValue != nil { if rhs.FloatValue == nil { // Extra: compare floats and ints numerically. if rhs.IntValue != nil { - return float64(*v.FloatValue) < float64(*rhs.IntValue) + return v.FloatValue.Compare(Float(*rhs.IntValue)) } - return true + return -1 } - return *v.FloatValue < *rhs.FloatValue + return v.FloatValue.Compare(*rhs.FloatValue) } else if rhs.FloatValue != nil { // Extra: compare floats and ints numerically. if v.IntValue != nil { - return float64(*v.IntValue) < float64(*rhs.FloatValue) + return Float(*v.IntValue).Compare(*rhs.FloatValue) } - return false + return 1 } if v.IntValue != nil { if rhs.IntValue == nil { - return true + return -1 } - return *v.IntValue < *rhs.IntValue + return v.IntValue.Compare(*rhs.IntValue) } else if rhs.IntValue != nil { - return false + return 1 } if v.StringValue != nil { if rhs.StringValue == nil { - return true + return -1 } - return *v.StringValue < *rhs.StringValue + return strings.Compare(string(*v.StringValue), string(*rhs.StringValue)) } else if rhs.StringValue != nil { - return false + return 1 } if v.BooleanValue != nil { if rhs.BooleanValue == nil { - return true + return -1 } - if *v.BooleanValue == *rhs.BooleanValue { - return false - } - return *v.BooleanValue == false + return v.BooleanValue.Compare(*rhs.BooleanValue) } else if rhs.BooleanValue != nil { - return false + return 1 } if v.ListValue != nil { if rhs.ListValue == nil { - return true + return -1 } - return v.ListValue.Less(rhs.ListValue) + return v.ListValue.Compare(rhs.ListValue) } else if rhs.ListValue != nil { - return false + return 1 } if v.MapValue != nil { if rhs.MapValue == nil { - return true + return -1 } - return v.MapValue.Less(rhs.MapValue) + return v.MapValue.Compare(rhs.MapValue) } else if rhs.MapValue != nil { - return false + return 1 } if v.Null { if !rhs.Null { - return true + return -1 } - return false + return 0 } else if rhs.Null { - return false + return 1 } // Invalid Value-- nothing is set. - return false + return 0 } type Int int64 @@ -123,40 +183,141 @@ type Float float64 type String string type Boolean bool +// Compare compares integers. The result will be 0 if i==rhs, -1 if i < +// rhs, and +1 if i > rhs. +func (i Int) Compare(rhs Int) int { + if i > rhs { + return 1 + } else if i < rhs { + return -1 + } + return 0 +} + +// Compare compares floats. The result will be 0 if f==rhs, -1 if f < +// rhs, and +1 if f > rhs. +func (f Float) Compare(rhs Float) int { + if f > rhs { + return 1 + } else if f < rhs { + return -1 + } + return 0 +} + +// Compare compares booleans. The result will be 0 if b==rhs, -1 if b < +// rhs, and +1 if b > rhs. +func (b Boolean) Compare(rhs Boolean) int { + if b == rhs { + return 0 + } else if b == false { + return -1 + } + return 1 +} + // Field is an individual key-value pair. type Field struct { Name string Value Value } +// FieldList is a list of key-value pairs. Each field is expected to +// have a different name. +type FieldList []Field + +// Sort sorts the field list by Name. +func (f FieldList) Sort() { + if len(f) < 2 { + return + } + if len(f) == 2 { + if f[1].Name < f[0].Name { + f[0], f[1] = f[1], f[0] + } + return + } + sort.SliceStable(f, func(i, j int) bool { + return f[i].Name < f[j].Name + }) +} + +// Less compares two lists lexically. +func (f FieldList) Less(rhs FieldList) bool { + return f.Compare(rhs) == -1 +} + +// Less compares two lists lexically. The result will be 0 if f==rhs, -1 +// if f < rhs, and +1 if f > rhs. +func (f FieldList) Compare(rhs FieldList) int { + i := 0 + for { + if i >= len(f) && i >= len(rhs) { + // Maps are the same length and all items are equal. + return 0 + } + if i >= len(f) { + // F is shorter. + return -1 + } + if i >= len(rhs) { + // RHS is shorter. + return 1 + } + if c := strings.Compare(f[i].Name, rhs[i].Name); c != 0 { + return c + } + if c := f[i].Value.Compare(rhs[i].Value); c != 0 { + return c + } + // The items are equal; continue. + i++ + } +} + // List is a list of items. type List struct { Items []Value } +// Equals compares two lists lexically. +func (l *List) Equals(rhs *List) bool { + if len(l.Items) != len(rhs.Items) { + return false + } + + for i, lv := range l.Items { + if !lv.Equals(rhs.Items[i]) { + return false + } + } + return true +} + // Less compares two lists lexically. func (l *List) Less(rhs *List) bool { + return l.Compare(rhs) == -1 +} + +// Compare compares two lists lexically. The result will be 0 if l==rhs, -1 +// if l < rhs, and +1 if l > rhs. +func (l *List) Compare(rhs *List) int { i := 0 for { if i >= len(l.Items) && i >= len(rhs.Items) { // Lists are the same length and all items are equal. - return false + return 0 } if i >= len(l.Items) { // LHS is shorter. - return true + return -1 } if i >= len(rhs.Items) { // RHS is shorter. - return false + return 1 } - if l.Items[i].Less(rhs.Items[i]) { - // LHS is less; return - return true - } - if rhs.Items[i].Less(l.Items[i]) { - // RHS is less; return - return false + if c := l.Items[i].Compare(rhs.Items[i]); c != 0 { + return c } // The items are equal; continue. i++ @@ -191,8 +352,30 @@ func (m *Map) computeOrder() []int { return m.order } +// Equals compares two maps lexically. +func (m *Map) Equals(rhs *Map) bool { + if len(m.Items) != len(rhs.Items) { + return false + } + for _, lfield := range m.Items { + rfield, ok := rhs.Get(lfield.Name) + if !ok { + return false + } + if !lfield.Value.Equals(rfield.Value) { + return false + } + } + return true +} + // Less compares two maps lexically. func (m *Map) Less(rhs *Map) bool { + return m.Compare(rhs) == -1 +} + +// Compare compares two maps lexically. +func (m *Map) Compare(rhs *Map) int { var noAllocL, noAllocR [2]int var morder, rorder []int @@ -238,28 +421,22 @@ func (m *Map) Less(rhs *Map) bool { for { if i >= len(morder) && i >= len(rorder) { // Maps are the same length and all items are equal. - return false + return 0 } if i >= len(morder) { // LHS is shorter. - return true + return -1 } if i >= len(rorder) { // RHS is shorter. - return false + return 1 } fa, fb := &m.Items[morder[i]], &rhs.Items[rorder[i]] - if fa.Name != fb.Name { - // the map having the field name that sorts lexically less is "less" - return fa.Name < fb.Name + if c := strings.Compare(fa.Name, fb.Name); c != 0 { + return c } - if fa.Value.Less(fb.Value) { - // LHS is less; return - return true - } - if fb.Value.Less(fa.Value) { - // RHS is less; return - return false + if c := fa.Value.Compare(fb.Value); c != 0 { + return c } // The items are equal; continue. i++