diff --git a/go.mod b/go.mod index 2a8c5342cf7..abc4677c8dc 100644 --- a/go.mod +++ b/go.mod @@ -467,7 +467,7 @@ replace ( modernc.org/strutil => modernc.org/strutil v1.0.0 modernc.org/xc => modernc.org/xc v1.0.0 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-20190628201129-059502f64143 + sigs.k8s.io/structured-merge-diff => sigs.k8s.io/structured-merge-diff v0.0.0-20190719182312-e94e05bfbbe3 sigs.k8s.io/yaml => sigs.k8s.io/yaml v1.1.0 vbom.ml/util => vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc ) diff --git a/go.sum b/go.sum index f788908c00e..5683b918976 100644 --- a/go.sum +++ b/go.sum @@ -484,8 +484,8 @@ modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I= 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-20190628201129-059502f64143 h1:9df9ZMJ21XLKSCuwZyI+qfbnQl/hDmrM7wjBK85iv8g= -sigs.k8s.io/structured-merge-diff v0.0.0-20190628201129-059502f64143/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v0.0.0-20190719182312-e94e05bfbbe3 h1:yCY9zAYErawYwXdOYmwEBzcGCr/6eIUujYZE2DIQve8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190719182312-e94e05bfbbe3/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= vbom.ml/util v0.0.0-20160121211510-db5cfe13f5cc h1:MksmcCZQWAQJCTA5T0jgI/0sJ51AVm4Z41MrmfczEoc= diff --git a/staging/src/k8s.io/apiextensions-apiserver/go.sum b/staging/src/k8s.io/apiextensions-apiserver/go.sum index bcf6c3871ee..67e4e2d4663 100644 --- a/staging/src/k8s.io/apiextensions-apiserver/go.sum +++ b/staging/src/k8s.io/apiextensions-apiserver/go.sum @@ -310,7 +310,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-20190628201129-059502f64143 h1:9df9ZMJ21XLKSCuwZyI+qfbnQl/hDmrM7wjBK85iv8g= -sigs.k8s.io/structured-merge-diff v0.0.0-20190628201129-059502f64143/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v0.0.0-20190719182312-e94e05bfbbe3 h1:yCY9zAYErawYwXdOYmwEBzcGCr/6eIUujYZE2DIQve8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190719182312-e94e05bfbbe3/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= 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 139f60c3122..abf23257e04 100644 --- a/staging/src/k8s.io/apiserver/go.mod +++ b/staging/src/k8s.io/apiserver/go.mod @@ -59,7 +59,7 @@ require ( k8s.io/klog v0.3.1 k8s.io/kube-openapi v0.0.0-20190709113604-33be087ad058 k8s.io/utils v0.0.0-20190607212802-c55fbcfc754a - sigs.k8s.io/structured-merge-diff v0.0.0-20190628201129-059502f64143 + sigs.k8s.io/structured-merge-diff v0.0.0-20190719182312-e94e05bfbbe3 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 925a30f4d63..c23ba60c749 100644 --- a/staging/src/k8s.io/apiserver/go.sum +++ b/staging/src/k8s.io/apiserver/go.sum @@ -229,7 +229,7 @@ k8s.io/utils v0.0.0-20190607212802-c55fbcfc754a h1:2jUDc9gJja832Ftp+QbDV0tVhQHMI k8s.io/utils v0.0.0-20190607212802-c55fbcfc754a/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-20190628201129-059502f64143 h1:9df9ZMJ21XLKSCuwZyI+qfbnQl/hDmrM7wjBK85iv8g= -sigs.k8s.io/structured-merge-diff v0.0.0-20190628201129-059502f64143/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v0.0.0-20190719182312-e94e05bfbbe3 h1:yCY9zAYErawYwXdOYmwEBzcGCr/6eIUujYZE2DIQve8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190719182312-e94e05bfbbe3/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= 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/kube-aggregator/go.sum b/staging/src/k8s.io/kube-aggregator/go.sum index 80751104b7b..8ea23ea5491 100644 --- a/staging/src/k8s.io/kube-aggregator/go.sum +++ b/staging/src/k8s.io/kube-aggregator/go.sum @@ -266,7 +266,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-20190628201129-059502f64143 h1:9df9ZMJ21XLKSCuwZyI+qfbnQl/hDmrM7wjBK85iv8g= -sigs.k8s.io/structured-merge-diff v0.0.0-20190628201129-059502f64143/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v0.0.0-20190719182312-e94e05bfbbe3 h1:yCY9zAYErawYwXdOYmwEBzcGCr/6eIUujYZE2DIQve8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190719182312-e94e05bfbbe3/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= 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 1e62cafe87b..75a5768b12e 100644 --- a/staging/src/k8s.io/legacy-cloud-providers/go.sum +++ b/staging/src/k8s.io/legacy-cloud-providers/go.sum @@ -209,6 +209,6 @@ k8s.io/kube-openapi v0.0.0-20190709113604-33be087ad058/go.mod h1:nfDlWeOsu3pUf4y k8s.io/utils v0.0.0-20190607212802-c55fbcfc754a h1:2jUDc9gJja832Ftp+QbDV0tVhQHMISFn01els+2ZAcw= k8s.io/utils v0.0.0-20190607212802-c55fbcfc754a/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-20190628201129-059502f64143/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v0.0.0-20190719182312-e94e05bfbbe3/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= 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 0f2512f79c1..cd1bc8dc903 100644 --- a/staging/src/k8s.io/sample-apiserver/go.sum +++ b/staging/src/k8s.io/sample-apiserver/go.sum @@ -263,7 +263,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-20190628201129-059502f64143 h1:9df9ZMJ21XLKSCuwZyI+qfbnQl/hDmrM7wjBK85iv8g= -sigs.k8s.io/structured-merge-diff v0.0.0-20190628201129-059502f64143/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +sigs.k8s.io/structured-merge-diff v0.0.0-20190719182312-e94e05bfbbe3 h1:yCY9zAYErawYwXdOYmwEBzcGCr/6eIUujYZE2DIQve8= +sigs.k8s.io/structured-merge-diff v0.0.0-20190719182312-e94e05bfbbe3/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= 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 a6518c76540..97cef717de2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1752,7 +1752,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-20190628201129-059502f64143 => sigs.k8s.io/structured-merge-diff v0.0.0-20190628201129-059502f64143 +# sigs.k8s.io/structured-merge-diff v0.0.0-20190719182312-e94e05bfbbe3 => sigs.k8s.io/structured-merge-diff v0.0.0-20190719182312-e94e05bfbbe3 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/element.go b/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/element.go index fb706a662b4..9783c3bac53 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.Field + Key *value.Map // Value selects the list element with the given value. The containing // object must be an associative list with a primitive typed element @@ -47,14 +47,62 @@ type PathElement struct { Index *int } +// Less provides an order for path elements. +func (e PathElement) Less(rhs PathElement) bool { + if e.FieldName != nil { + if rhs.FieldName == nil { + return true + } + return *e.FieldName < *rhs.FieldName + } else if rhs.FieldName != nil { + return false + } + + if e.Key != nil { + if rhs.Key == nil { + return true + } + return e.Key.Less(rhs.Key) + } else if rhs.Key != nil { + return false + } + + if e.Value != nil { + if rhs.Value == nil { + return true + } + return e.Value.Less(*rhs.Value) + } else if rhs.Value != nil { + return false + } + + if e.Index != nil { + if rhs.Index == nil { + return true + } + return *e.Index < *rhs.Index + } else if rhs.Index != nil { + // Yes, I know the next statement is the same. But this way + // the obvious way of extending the function wil be bug-free. + return false + } + + return false +} + +// Equals returns true if both path elements are equal. +func (e PathElement) Equals(rhs PathElement) bool { + return !e.Less(rhs) && !rhs.Less(e) +} + // String presents the path element as a human-readable string. func (e PathElement) String() string { switch { case e.FieldName != nil: return "." + *e.FieldName - case len(e.Key) > 0: - strs := make([]string, len(e.Key)) - for i, k := range e.Key { + case e.Key != nil: + strs := make([]string, len(e.Key.Items)) + for i, k := range e.Key.Items { strs[i] = fmt.Sprintf("%v=%v", k.Name, k.Value) } // The order must be canonical, since we use the string value @@ -92,62 +140,100 @@ func KeyByFields(nameValues ...interface{}) []value.Field { // PathElementSet is a set of path elements. // TODO: serialize as a list. type PathElementSet struct { - // The strange construction is because there's no way to test - // PathElements for equality (it can't be used as a key for a map). - members map[string]PathElement + members sortedPathElements } +type sortedPathElements []PathElement + +// Implement the sort interface; this would permit bulk creation, which would +// be faster than doing it one at a time via Insert. +func (spe sortedPathElements) Len() int { return len(spe) } +func (spe sortedPathElements) Less(i, j int) bool { return spe[i].Less(spe[j]) } +func (spe sortedPathElements) Swap(i, j int) { spe[i], spe[j] = spe[j], spe[i] } + // Insert adds pe to the set. func (s *PathElementSet) Insert(pe PathElement) { - serialized := pe.String() - if s.members == nil { - s.members = map[string]PathElement{ - serialized: pe, - } + loc := sort.Search(len(s.members), func(i int) bool { + return !s.members[i].Less(pe) + }) + if loc == len(s.members) { + s.members = append(s.members, pe) return } - if _, ok := s.members[serialized]; !ok { - s.members[serialized] = pe + if s.members[loc].Equals(pe) { + return } + s.members = append(s.members, PathElement{}) + copy(s.members[loc+1:], s.members[loc:]) + s.members[loc] = pe } // Union returns a set containing elements that appear in either s or s2. func (s *PathElementSet) Union(s2 *PathElementSet) *PathElementSet { - out := &PathElementSet{ - members: map[string]PathElement{}, + out := &PathElementSet{} + + i, j := 0, 0 + for i < len(s.members) && j < len(s2.members) { + if s.members[i].Less(s2.members[j]) { + out.members = append(out.members, s.members[i]) + i++ + } else { + out.members = append(out.members, s2.members[j]) + if !s2.members[j].Less(s.members[i]) { + i++ + } + j++ + } } - for k, v := range s.members { - out.members[k] = v + + if i < len(s.members) { + out.members = append(out.members, s.members[i:]...) } - for k, v := range s2.members { - out.members[k] = v + if j < len(s2.members) { + out.members = append(out.members, s2.members[j:]...) } return out } // Intersection returns a set containing elements which appear in both s and s2. func (s *PathElementSet) Intersection(s2 *PathElementSet) *PathElementSet { - out := &PathElementSet{ - members: map[string]PathElement{}, - } - for k, v := range s.members { - if _, ok := s2.members[k]; ok { - out.members[k] = v + out := &PathElementSet{} + + i, j := 0, 0 + for i < len(s.members) && j < len(s2.members) { + if s.members[i].Less(s2.members[j]) { + i++ + } else { + if !s2.members[j].Less(s.members[i]) { + out.members = append(out.members, s.members[i]) + i++ + } + j++ } } + return out } // Difference returns a set containing elements which appear in s but not in s2. func (s *PathElementSet) Difference(s2 *PathElementSet) *PathElementSet { - out := &PathElementSet{ - members: map[string]PathElement{}, - } - for k, v := range s.members { - if _, ok := s2.members[k]; !ok { - out.members[k] = v + out := &PathElementSet{} + + i, j := 0, 0 + for i < len(s.members) && j < len(s2.members) { + if s.members[i].Less(s2.members[j]) { + out.members = append(out.members, s.members[i]) + i++ + } else { + if !s2.members[j].Less(s.members[i]) { + i++ + } + j++ } } + if i < len(s.members) { + out.members = append(out.members, s.members[i:]...) + } return out } @@ -156,11 +242,16 @@ func (s *PathElementSet) Size() int { return len(s.members) } // Has returns true if pe is a member of the set. func (s *PathElementSet) Has(pe PathElement) bool { - if s.members == nil { + loc := sort.Search(len(s.members), func(i int) bool { + return !s.members[i].Less(pe) + }) + if loc == len(s.members) { return false } - _, ok := s.members[pe.String()] - return ok + if s.members[loc].Equals(pe) { + return true + } + return false } // Equals returns true if s and s2 have exactly the same members. @@ -169,14 +260,14 @@ func (s *PathElementSet) Equals(s2 *PathElementSet) bool { return false } for k := range s.members { - if _, ok := s2.members[k]; !ok { + if !s.members[k].Equals(s2.members[k]) { return false } } return true } -// Iterate calls f for each PathElement in the set. +// Iterate calls f for each PathElement in the set. The order is deterministic. func (s *PathElementSet) Iterate(f func(PathElement)) { for _, pe := range s.members { f(pe) 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 a4b054fc7aa..830880fb49d 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/fromvalue.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/fromvalue.go @@ -117,7 +117,7 @@ func GuessBestListPathElement(index int, item value.Value) PathElement { keys = append(keys, *f) } if len(keys) > 0 { - return PathElement{Key: keys} + return PathElement{Key: &value.Map{Items: 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 c11c7f28a5b..ca80e7cca79 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/path.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/path.go @@ -35,6 +35,40 @@ func (fp Path) String() string { return strings.Join(strs, "") } +// Equals returns true if the two paths are equivalent. +func (fp Path) Equals(fp2 Path) bool { + return !fp.Less(fp2) && !fp2.Less(fp) +} + +// Less provides a lexical order for Paths. +func (fp Path) Less(rhs Path) bool { + i := 0 + for { + if i >= len(fp) && i >= len(rhs) { + // Paths are the same length and all items are equal. + return false + } + if i >= len(fp) { + // LHS is shorter. + return true + } + if i >= len(rhs) { + // RHS is shorter. + return false + } + if fp[i].Less(rhs[i]) { + // LHS is less; return + return true + } + if rhs[i].Less(fp[i]) { + // RHS is less; return + return false + } + // The items are equal; continue. + i++ + } +} + func (fp Path) Copy() Path { new := make(Path, len(fp)) copy(new, fp) @@ -58,7 +92,7 @@ func MakePath(parts ...interface{}) (Path, error) { 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: t}) + fp = append(fp, PathElement{Key: &value.Map{Items: 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/set.go b/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/set.go index e561093b6e6..b3aebfefcb0 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/set.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/fieldpath/set.go @@ -17,6 +17,7 @@ limitations under the License. package fieldpath import ( + "sort" "strings" ) @@ -172,24 +173,25 @@ type setNode struct { // SetNodeMap is a map of PathElement to subset. type SetNodeMap struct { - members map[string]setNode + members []setNode } // Descend adds pe to the set if necessary, returning the associated subset. func (s *SetNodeMap) Descend(pe PathElement) *Set { - serialized := pe.String() - if s.members == nil { - s.members = map[string]setNode{} + 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, setNode{pathElement: pe, set: &Set{}}) + return s.members[loc].set } - if n, ok := s.members[serialized]; ok { - return n.set + if s.members[loc].pathElement.Equals(pe) { + return s.members[loc].set } - ss := &Set{} - s.members[serialized] = setNode{ - pathElement: pe, - set: ss, - } - return ss + s.members = append(s.members, setNode{}) + copy(s.members[loc+1:], s.members[loc:]) + s.members[loc] = setNode{pathElement: pe, set: &Set{}} + return s.members[loc].set } // Size returns the sum of the number of members of all subsets. @@ -213,12 +215,14 @@ func (s *SetNodeMap) Empty() bool { // Get returns (the associated set, true) or (nil, false) if there is none. func (s *SetNodeMap) Get(pe PathElement) (*Set, bool) { - if s.members == nil { + loc := sort.Search(len(s.members), func(i int) bool { + return !s.members[i].pathElement.Less(pe) + }) + if loc == len(s.members) { return nil, false } - serialized := pe.String() - if n, ok := s.members[serialized]; ok { - return n.set, true + if s.members[loc].pathElement.Equals(pe) { + return s.members[loc].set, true } return nil, false } @@ -229,12 +233,11 @@ func (s *SetNodeMap) Equals(s2 *SetNodeMap) bool { if len(s.members) != len(s2.members) { return false } - for k, v := range s.members { - v2, ok := s2.members[k] - if !ok { + for i := range s.members { + if !s.members[i].pathElement.Equals(s2.members[i].pathElement) { return false } - if !v.set.Equals(v2.set) { + if !s.members[i].set.Equals(s2.members[i].set) { return false } } @@ -244,21 +247,28 @@ func (s *SetNodeMap) Equals(s2 *SetNodeMap) bool { // Union returns a SetNodeMap with members that appear in either s or s2. func (s *SetNodeMap) Union(s2 *SetNodeMap) *SetNodeMap { out := &SetNodeMap{} - for k, sn := range s.members { - pe := sn.pathElement - if sn2, ok := s2.members[k]; ok { - *out.Descend(pe) = *sn.set.Union(sn2.set) + + i, j := 0, 0 + for i < len(s.members) && j < len(s2.members) { + if s.members[i].pathElement.Less(s2.members[j].pathElement) { + out.members = append(out.members, s.members[i]) + i++ } else { - *out.Descend(pe) = *sn.set + if !s2.members[j].pathElement.Less(s.members[i].pathElement) { + out.members = append(out.members, setNode{pathElement: s.members[i].pathElement, set: s.members[i].set.Union(s2.members[j].set)}) + i++ + } else { + out.members = append(out.members, s2.members[j]) + } + j++ } } - for k, sn2 := range s2.members { - pe := sn2.pathElement - if _, ok := s.members[k]; ok { - // already handled - continue - } - *out.Descend(pe) = *sn2.set + + if i < len(s.members) { + out.members = append(out.members, s.members[i:]...) + } + if j < len(s2.members) { + out.members = append(out.members, s2.members[j:]...) } return out } @@ -266,13 +276,20 @@ func (s *SetNodeMap) Union(s2 *SetNodeMap) *SetNodeMap { // Intersection returns a SetNodeMap with members that appear in both s and s2. func (s *SetNodeMap) Intersection(s2 *SetNodeMap) *SetNodeMap { out := &SetNodeMap{} - for k, sn := range s.members { - pe := sn.pathElement - if sn2, ok := s2.members[k]; ok { - i := *sn.set.Intersection(sn2.set) - if !i.Empty() { - *out.Descend(pe) = i + + i, j := 0, 0 + for i < len(s.members) && j < len(s2.members) { + if s.members[i].pathElement.Less(s2.members[j].pathElement) { + i++ + } else { + if !s2.members[j].pathElement.Less(s.members[i].pathElement) { + res := s.members[i].set.Intersection(s2.members[j].set) + if !res.Empty() { + out.members = append(out.members, setNode{pathElement: s.members[i].pathElement, set: res}) + } + i++ } + j++ } } return out @@ -281,18 +298,30 @@ func (s *SetNodeMap) Intersection(s2 *SetNodeMap) *SetNodeMap { // Difference returns a SetNodeMap with members that appear in s but not in s2. func (s *SetNodeMap) Difference(s2 *Set) *SetNodeMap { out := &SetNodeMap{} - for k, sn := range s.members { - pe := sn.pathElement - if sn2, ok := s2.Children.members[k]; ok { - diff := *sn.set.Difference(sn2.set) - // We aren't permitted to add nodes with no elements. - if !diff.Empty() { - *out.Descend(pe) = diff - } + + i, j := 0, 0 + for i < len(s.members) && j < len(s2.Children.members) { + if s.members[i].pathElement.Less(s2.Children.members[j].pathElement) { + out.members = append(out.members, setNode{pathElement: s.members[i].pathElement, set: s.members[i].set}) + i++ } else { - *out.Descend(pe) = *sn.set + if !s2.Children.members[j].pathElement.Less(s.members[i].pathElement) { + + diff := s.members[i].set.Difference(s2.Children.members[j].set) + // We aren't permitted to add nodes with no elements. + if !diff.Empty() { + out.members = append(out.members, setNode{pathElement: s.members[i].pathElement, set: diff}) + } + + i++ + } + j++ } } + + if i < len(s.members) { + out.members = append(out.members, s.members[i:]...) + } return out } diff --git a/vendor/sigs.k8s.io/structured-merge-diff/merge/conflict.go b/vendor/sigs.k8s.io/structured-merge-diff/merge/conflict.go index aeef5ce25e0..34477f7d796 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/merge/conflict.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/merge/conflict.go @@ -40,6 +40,14 @@ func (c Conflict) Error() string { return fmt.Sprintf("conflict with %q: %v", c.Manager, c.Path) } +// Equals returns true if c == c2 +func (c Conflict) Equals(c2 Conflict) bool { + if c.Manager != c2.Manager { + return false + } + return c.Path.Equals(c2.Path) +} + // Conflicts accumulates multiple conflicts and aggregates them by managers. type Conflicts []Conflict @@ -74,6 +82,19 @@ func (conflicts Conflicts) Error() string { return strings.Join(messages, "\n") } +// Equals returns true if the lists of conflicts are the same. +func (c Conflicts) Equals(c2 Conflicts) bool { + if len(c) != len(c2) { + return false + } + for i := range c { + if !c[i].Equals(c2[i]) { + return false + } + } + return true +} + // ConflictsFromManagers creates a list of conflicts given Managers sets. func ConflictsFromManagers(sets fieldpath.ManagedFields) Conflicts { conflicts := []Conflict{} 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 67774e58ac2..ef856144f85 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/typed/helpers.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/typed/helpers.go @@ -197,6 +197,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{} for _, fieldName := range list.Keys { var fieldValue value.Value field, ok := child.MapValue.Get(fieldName) @@ -206,11 +207,9 @@ 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) } - pe.Key = append(pe.Key, value.Field{ - Name: fieldName, - Value: fieldValue, - }) + keyMap.Set(fieldName, fieldValue) } + pe.Key = keyMap return pe, nil } 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 d1c6d344b4a..a4e0f0b847a 100644 --- a/vendor/sigs.k8s.io/structured-merge-diff/value/value.go +++ b/vendor/sigs.k8s.io/structured-merge-diff/value/value.go @@ -18,6 +18,7 @@ package value import ( "fmt" + "sort" "strings" ) @@ -33,6 +34,85 @@ type Value struct { Null bool // represents an explicit `"foo" = null` } +// 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 { + 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 true + } + return *v.FloatValue < *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 false + } + + if v.IntValue != nil { + if rhs.IntValue == nil { + return true + } + return *v.IntValue < *rhs.IntValue + } else if rhs.IntValue != nil { + return false + } + + if v.StringValue != nil { + if rhs.StringValue == nil { + return true + } + return *v.StringValue < *rhs.StringValue + } else if rhs.StringValue != nil { + return false + } + + if v.BooleanValue != nil { + if rhs.BooleanValue == nil { + return true + } + if *v.BooleanValue == *rhs.BooleanValue { + return false + } + return *v.BooleanValue == false + } else if rhs.BooleanValue != nil { + return false + } + + if v.ListValue != nil { + if rhs.ListValue == nil { + return true + } + return v.ListValue.Less(rhs.ListValue) + } else if rhs.ListValue != nil { + return false + } + if v.MapValue != nil { + if rhs.MapValue == nil { + return true + } + return v.MapValue.Less(rhs.MapValue) + } else if rhs.MapValue != nil { + return false + } + if v.Null { + if !rhs.Null { + return true + } + return false + } else if rhs.Null { + return false + } + + // Invalid Value-- nothing is set. + return false +} + type Int int64 type Float float64 type String string @@ -49,6 +129,35 @@ type List struct { Items []Value } +// Less compares two lists lexically. +func (l *List) Less(rhs *List) bool { + i := 0 + for { + if i >= len(l.Items) && i >= len(rhs.Items) { + // Lists are the same length and all items are equal. + return false + } + if i >= len(l.Items) { + // LHS is shorter. + return true + } + if i >= len(rhs.Items) { + // RHS is shorter. + return false + } + 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 + } + // The items are equal; continue. + i++ + } +} + // Map is a map of key-value pairs. It represents both structs and maps. We use // a list and a go-language map to preserve order. // @@ -59,6 +168,58 @@ type Map struct { // may be nil; lazily constructed. // TODO: Direct modifications to Items above will cause serious problems. index map[string]*Field + // may be empty; lazily constructed. + // TODO: Direct modifications to Items above will cause serious problems. + order []int +} + +func (m *Map) computeOrder() { + if len(m.order) != len(m.Items) { + m.order = make([]int, len(m.Items)) + for i := range m.order { + m.order[i] = i + } + sort.SliceStable(m.order, func(i, j int) bool { + return m.Items[m.order[i]].Name < m.Items[m.order[j]].Name + }) + } +} + +// Less compares two maps lexically. +func (m *Map) Less(rhs *Map) bool { + m.computeOrder() + rhs.computeOrder() + + i := 0 + for { + if i >= len(m.order) && i >= len(rhs.order) { + // Maps are the same length and all items are equal. + return false + } + if i >= len(m.order) { + // LHS is shorter. + return true + } + if i >= len(rhs.order) { + // RHS is shorter. + return false + } + fa, fb := &m.Items[m.order[i]], &rhs.Items[rhs.order[i]] + if fa.Name != fb.Name { + // the map having the field name that sorts lexically less is "less" + return fa.Name < fb.Name + } + if fa.Value.Less(fb.Value) { + // LHS is less; return + return true + } + if fb.Value.Less(fa.Value) { + // RHS is less; return + return false + } + // The items are equal; continue. + i++ + } } // Get returns the (Field, true) or (nil, false) if it is not present @@ -82,6 +243,7 @@ func (m *Map) Set(key string, value Value) { } m.Items = append(m.Items, Field{Name: key, Value: value}) m.index = nil // Since the append might have reallocated + m.order = nil } // Delete removes the key from the set. @@ -94,6 +256,7 @@ func (m *Map) Delete(key string) { } m.Items = items m.index = nil // Since the list has changed + m.order = nil } // StringValue returns s as a scalar string Value.