UPdate vendor/sigs.k8s.io/structured-merge-diff

This commit is contained in:
Antoine Pelisse
2019-01-22 16:00:09 -08:00
parent f7c4f0433f
commit 611587ffe2
22 changed files with 389 additions and 200 deletions

10
Godeps/Godeps.json generated
View File

@@ -4111,23 +4111,23 @@
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/fieldpath",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/merge",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/schema",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/typed",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/value",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/yaml",

View File

@@ -2596,23 +2596,23 @@
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/fieldpath",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/merge",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/schema",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/typed",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/value",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/yaml",

View File

@@ -180,23 +180,23 @@
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/fieldpath",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/merge",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/schema",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/typed",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/value",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/yaml",

View File

@@ -2088,23 +2088,23 @@
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/fieldpath",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/merge",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/schema",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/typed",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/value",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/yaml",

View File

@@ -620,23 +620,23 @@
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/fieldpath",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/merge",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/schema",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/typed",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/value",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/yaml",

View File

@@ -620,23 +620,23 @@
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/fieldpath",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/merge",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/schema",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/typed",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/value",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/yaml",

View File

@@ -976,23 +976,23 @@
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/fieldpath",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/merge",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/schema",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/typed",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/value",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/yaml",

View File

@@ -560,23 +560,23 @@
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/fieldpath",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/merge",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/schema",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/typed",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/value",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/yaml",

View File

@@ -1872,23 +1872,23 @@
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/fieldpath",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/merge",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/schema",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/typed",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/value",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/yaml",

View File

@@ -532,23 +532,23 @@
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/fieldpath",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/merge",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/schema",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/typed",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/value",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/yaml",

View File

@@ -560,23 +560,23 @@
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/fieldpath",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/merge",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/schema",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/typed",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/value",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/yaml",

View File

@@ -1824,23 +1824,23 @@
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/fieldpath",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/merge",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/schema",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/typed",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/value",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/yaml",

View File

@@ -584,23 +584,23 @@
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/fieldpath",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/merge",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/schema",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/typed",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/value",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/yaml",

View File

@@ -1180,23 +1180,23 @@
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/fieldpath",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/merge",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/schema",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/typed",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/structured-merge-diff/value",
"Rev": "3e9f406ec0132f60af296ad1fbd1ca05bdc0138d"
"Rev": "302c24c1a693093a6d7552298f86d75cf9852e1d"
},
{
"ImportPath": "sigs.k8s.io/yaml",

View File

@@ -35,6 +35,12 @@ func (fp Path) String() string {
return strings.Join(strs, "")
}
func (fp Path) Copy() Path {
new := make(Path, len(fp))
copy(new, fp)
return new
}
// MakePath constructs a Path. The parts may be PathElements, ints, strings.
func MakePath(parts ...interface{}) (Path, error) {
var fp Path

View File

@@ -127,18 +127,18 @@ func (s *Updater) Update(liveObject, newObject typed.TypedValue, version fieldpa
func (s *Updater) Apply(liveObject, configObject typed.TypedValue, version fieldpath.APIVersion, managers fieldpath.ManagedFields, manager string, force bool) (typed.TypedValue, fieldpath.ManagedFields, error) {
newObject, err := liveObject.Merge(configObject)
if err != nil {
return typed.TypedValue{}, fieldpath.ManagedFields{}, fmt.Errorf("failed to merge config: %v", err)
return nil, fieldpath.ManagedFields{}, fmt.Errorf("failed to merge config: %v", err)
}
managers, err = s.update(liveObject, newObject, version, managers, manager, force)
if err != nil {
return typed.TypedValue{}, fieldpath.ManagedFields{}, err
return nil, fieldpath.ManagedFields{}, err
}
// TODO: Remove unconflicting removed fields
set, err := configObject.ToFieldSet()
if err != nil {
return typed.TypedValue{}, fieldpath.ManagedFields{}, fmt.Errorf("failed to get field set: %v", err)
return nil, fieldpath.ManagedFields{}, fmt.Errorf("failed to get field set: %v", err)
}
managers[manager] = &fieldpath.VersionedSet{
Set: set,

View File

@@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"deduced.go",
"doc.go",
"helpers.go",
"merge.go",

View File

@@ -0,0 +1,172 @@
/*
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 typed
import (
"reflect"
"sigs.k8s.io/structured-merge-diff/value"
"sigs.k8s.io/structured-merge-diff/fieldpath"
)
// deducedTypedValue holds a value and guesses what it is and what to
// do with it.
type deducedTypedValue struct {
value value.Value
}
// AsTypedDeduced is going to generate it's own type definition based on
// the content of the object. This is useful for CRDs that don't have a
// validation field.
func AsTypedDeduced(v value.Value) TypedValue {
return deducedTypedValue{value: v}
}
func (dv deducedTypedValue) AsValue() *value.Value {
return &dv.value
}
func (deducedTypedValue) Validate() error {
return nil
}
func (dv deducedTypedValue) ToFieldSet() (*fieldpath.Set, error) {
set := fieldpath.NewSet()
fieldsetDeduced(dv.value, fieldpath.Path{}, set)
return set, nil
}
func fieldsetDeduced(v value.Value, path fieldpath.Path, set *fieldpath.Set) {
if v.MapValue == nil {
set.Insert(path)
return
}
// We have a map.
// copy the existing path, append each item, and recursively call.
for i := range v.MapValue.Items {
child := v.MapValue.Items[i]
np := path.Copy()
np = append(np, fieldpath.PathElement{FieldName: &child.Name})
fieldsetDeduced(child.Value, np, set)
}
}
func (dv deducedTypedValue) Merge(pso TypedValue) (TypedValue, error) {
tpso, ok := pso.(deducedTypedValue)
if !ok {
return nil, errorFormatter{}.
errorf("can't merge deducedTypedValue with %T", tpso)
}
return AsTypedDeduced(mergeDeduced(dv.value, tpso.value)), nil
}
func mergeDeduced(lhs, rhs value.Value) value.Value {
// If both sides are maps, merge them, otherwise return right
// side.
if rhs.MapValue == nil || lhs.MapValue == nil {
return rhs
}
v := value.Value{MapValue: &value.Map{}}
for i := range lhs.MapValue.Items {
child := lhs.MapValue.Items[i]
v.MapValue.Set(child.Name, child.Value)
}
for i := range rhs.MapValue.Items {
child := rhs.MapValue.Items[i]
if sub, ok := v.MapValue.Get(child.Name); ok {
new := mergeDeduced(sub.Value, child.Value)
v.MapValue.Set(child.Name, new)
} else {
v.MapValue.Set(child.Name, child.Value)
}
}
return v
}
func (dv deducedTypedValue) Compare(rhs TypedValue) (c *Comparison, err error) {
trhs, ok := rhs.(deducedTypedValue)
if !ok {
return nil, errorFormatter{}.
errorf("can't merge deducedTypedValue with %T", rhs)
}
c = &Comparison{
Removed: fieldpath.NewSet(),
Modified: fieldpath.NewSet(),
Added: fieldpath.NewSet(),
}
added(dv.value, trhs.value, fieldpath.Path{}, c.Added)
added(trhs.value, dv.value, fieldpath.Path{}, c.Removed)
modified(dv.value, trhs.value, fieldpath.Path{}, c.Modified)
merge, err := dv.Merge(rhs)
if err != nil {
return nil, err
}
c.Merged = merge
return c, nil
}
func added(lhs, rhs value.Value, path fieldpath.Path, set *fieldpath.Set) {
if lhs.MapValue == nil && rhs.MapValue == nil {
// Both non-maps, nothing added, do nothing.
} else if lhs.MapValue == nil && rhs.MapValue != nil {
// From leaf to map, add leaf fields of map.
fieldsetDeduced(rhs, path, set)
} else if lhs.MapValue != nil && rhs.MapValue == nil {
// Went from map to field, add field.
set.Insert(path)
} else {
// Both are maps.
for i := range rhs.MapValue.Items {
child := rhs.MapValue.Items[i]
np := path.Copy()
np = append(np, fieldpath.PathElement{FieldName: &child.Name})
if v, ok := lhs.MapValue.Get(child.Name); ok {
added(v.Value, child.Value, np, set)
} else {
fieldsetDeduced(child.Value, np, set)
}
}
}
}
func modified(lhs, rhs value.Value, path fieldpath.Path, set *fieldpath.Set) {
if lhs.MapValue == nil && rhs.MapValue == nil {
if !reflect.DeepEqual(lhs, rhs) {
set.Insert(path)
}
} else if lhs.MapValue != nil && rhs.MapValue != nil {
// Both are maps.
for i := range rhs.MapValue.Items {
child := rhs.MapValue.Items[i]
v, ok := lhs.MapValue.Get(child.Name)
if !ok {
continue
}
np := path.Copy()
np = append(np, fieldpath.PathElement{FieldName: &child.Name})
modified(v.Value, child.Value, np, set)
}
}
}

View File

@@ -100,7 +100,7 @@ func (p *parseableType) IsValid() bool {
func (p *parseableType) FromYAML(object YAMLObject) (TypedValue, error) {
v, err := value.FromYAML([]byte(object))
if err != nil {
return TypedValue{}, err
return nil, err
}
return AsTyped(v, &p.parser.Schema, p.typename)
}
@@ -110,7 +110,7 @@ func (p *parseableType) FromYAML(object YAMLObject) (TypedValue, error) {
func (p *parseableType) FromUnstructured(in interface{}) (TypedValue, error) {
v, err := value.FromUnstructured(in)
if err != nil {
return TypedValue{}, err
return nil, err
}
return AsTyped(v, &p.parser.Schema, p.typename)
}
@@ -131,7 +131,7 @@ func (p DeducedParseableType) IsValid() bool {
func (p DeducedParseableType) FromYAML(object YAMLObject) (TypedValue, error) {
v, err := value.FromYAML([]byte(object))
if err != nil {
return TypedValue{}, err
return nil, err
}
return AsTypedDeduced(v), nil
}
@@ -141,7 +141,7 @@ func (p DeducedParseableType) FromYAML(object YAMLObject) (TypedValue, error) {
func (p DeducedParseableType) FromUnstructured(in interface{}) (TypedValue, error) {
v, err := value.FromUnstructured(in)
if err != nil {
return TypedValue{}, err
return nil, err
}
return AsTypedDeduced(v), nil
}

View File

@@ -25,55 +25,85 @@ import (
"sigs.k8s.io/structured-merge-diff/value"
)
// TypedValue is a value of some specific type.
type TypedValue struct {
value value.Value
typeRef schema.TypeRef
schema *schema.Schema
// TypedValue is a value with an associated type.
type TypedValue interface {
// AsValue removes the type from the TypedValue and only keeps the value.
AsValue() *value.Value
// Validate returns an error with a list of every spec violation.
Validate() error
// ToFieldSet creates a set containing every leaf field mentioned, or
// validation errors, if any were encountered.
ToFieldSet() (*fieldpath.Set, error)
// Merge returns the result of merging tv and pso ("partially specified
// object") together. Of note:
// * No fields can be removed by this operation.
// * If both tv and pso specify a given leaf field, the result will keep pso's
// value.
// * Container typed elements will have their items ordered:
// * like tv, if pso doesn't change anything in the container
// * like pso, if pso does change something in the container.
// tv and pso must both be of the same type (their Schema and TypeRef must
// match), or an error will be returned. Validation errors will be returned if
// the objects don't conform to the schema.
Merge(pso TypedValue) (TypedValue, error)
// Compare compares the two objects. See the comments on the `Comparison`
// struct for details on the return value.
//
// tv and rhs must both be of the same type (their Schema and TypeRef must
// match), or an error will be returned. Validation errors will be returned if
// the objects don't conform to the schema.
Compare(rhs TypedValue) (c *Comparison, err error)
}
// AsTyped accepts a value and a type and returns a TypedValue. 'v' must have
// type 'typeName' in the schema. An error is returned if the v doesn't conform
// to the schema.
func AsTyped(v value.Value, s *schema.Schema, typeName string) (TypedValue, error) {
tv := TypedValue{
tv := typedValue{
value: v,
typeRef: schema.TypeRef{NamedType: &typeName},
schema: s,
}
if err := tv.Validate(); err != nil {
return TypedValue{}, err
return nil, err
}
return tv, nil
}
// AsTypedDeduced is going to generate it's own type definition based on
// the content of the object. This is useful for CRDs that don't have a
// validation field.
func AsTypedDeduced(v value.Value) TypedValue {
return TypedValue{
value: v,
typeRef: schema.TypeRefFromValue(v),
schema: nil,
// AsTypeUnvalidated is just like AsTyped, but doesn't validate that the type
// conforms to the schema, for cases where that has already been checked or
// where you're going to call a method that validates as a side-effect (like
// ToFieldSet).
func AsTypedUnvalidated(v value.Value, s *schema.Schema, typeName string) TypedValue {
tv := typedValue{
value: v,
typeRef: schema.TypeRef{NamedType: &typeName},
schema: s,
}
return tv
}
// AsValue removes the type from the TypedValue and only keeps the value.
func (tv TypedValue) AsValue() *value.Value {
// typedValue is a value of some specific type.
type typedValue struct {
value value.Value
typeRef schema.TypeRef
schema *schema.Schema
}
var _ TypedValue = typedValue{}
func (tv typedValue) AsValue() *value.Value {
return &tv.value
}
// Validate returns an error with a list of every spec violation.
func (tv TypedValue) Validate() error {
func (tv typedValue) Validate() error {
if errs := tv.walker().validate(); len(errs) != 0 {
return errs
}
return nil
}
// ToFieldSet creates a set containing every leaf field mentioned in tv, or
// validation errors, if any were encountered.
func (tv TypedValue) ToFieldSet() (*fieldpath.Set, error) {
func (tv typedValue) ToFieldSet() (*fieldpath.Set, error) {
s := fieldpath.NewSet()
w := tv.walker()
w.leafFieldCallback = func(p fieldpath.Path) { s.Insert(p) }
@@ -83,19 +113,85 @@ func (tv TypedValue) ToFieldSet() (*fieldpath.Set, error) {
return s, nil
}
// Merge returns the result of merging tv and pso ("partially specified
// object") together. Of note:
// * No fields can be removed by this operation.
// * If both tv and pso specify a given leaf field, the result will keep pso's
// value.
// * Container typed elements will have their items ordered:
// * like tv, if pso doesn't change anything in the container
// * like pso, if pso does change something in the container.
// tv and pso must both be of the same type (their Schema and TypeRef must
// match), or an error will be returned. Validation errors will be returned if
// the objects don't conform to the schema.
func (tv TypedValue) Merge(pso TypedValue) (TypedValue, error) {
return merge(tv, pso, ruleKeepRHS, nil)
func (tv typedValue) Merge(pso TypedValue) (TypedValue, error) {
tpso, ok := pso.(typedValue)
if !ok {
return nil, errorFormatter{}.
errorf("can't merge typedValue with %T", pso)
}
return merge(tv, tpso, ruleKeepRHS, nil)
}
func (tv typedValue) Compare(rhs TypedValue) (c *Comparison, err error) {
trhs, ok := rhs.(typedValue)
if !ok {
return nil, errorFormatter{}.
errorf("can't compare typedValue with %T", rhs)
}
c = &Comparison{
Removed: fieldpath.NewSet(),
Modified: fieldpath.NewSet(),
Added: fieldpath.NewSet(),
}
c.Merged, err = merge(tv, trhs, func(w *mergingWalker) {
if w.lhs == nil {
c.Added.Insert(w.path)
} else if w.rhs == nil {
c.Removed.Insert(w.path)
} else if !reflect.DeepEqual(w.rhs, w.lhs) {
// TODO: reflect.DeepEqual is not sufficient for this.
// 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)
} else if w.rhs == nil {
c.Removed.Insert(w.path)
}
})
if err != nil {
return nil, err
}
return c, nil
}
func merge(lhs, rhs typedValue, rule, postRule mergeRule) (TypedValue, error) {
if lhs.schema != rhs.schema {
return nil, errorFormatter{}.
errorf("expected objects with types from the same schema")
}
if !reflect.DeepEqual(lhs.typeRef, rhs.typeRef) {
return nil, errorFormatter{}.
errorf("expected objects of the same type, but got %v and %v", lhs.typeRef, rhs.typeRef)
}
mw := mergingWalker{
lhs: &lhs.value,
rhs: &rhs.value,
schema: lhs.schema,
typeRef: lhs.typeRef,
rule: rule,
postItemHook: postRule,
}
errs := mw.merge()
if len(errs) > 0 {
return nil, errs
}
out := typedValue{
schema: lhs.schema,
typeRef: lhs.typeRef,
}
if mw.out == nil {
out.value = value.Value{Null: true}
} else {
out.value = *mw.out
}
return out, nil
}
// Comparison is the return value of a TypedValue.Compare() operation.
@@ -136,89 +232,3 @@ func (c *Comparison) String() string {
}
return str
}
// Compare compares the two objects. See the comments on the `Comparison`
// struct for details on the return value.
//
// tv and rhs must both be of the same type (their Schema and TypeRef must
// match), or an error will be returned. Validation errors will be returned if
// the objects don't conform to the schema.
func (tv TypedValue) Compare(rhs TypedValue) (c *Comparison, err error) {
c = &Comparison{
Removed: fieldpath.NewSet(),
Modified: fieldpath.NewSet(),
Added: fieldpath.NewSet(),
}
c.Merged, err = merge(tv, rhs, func(w *mergingWalker) {
if w.lhs == nil {
c.Added.Insert(w.path)
} else if w.rhs == nil {
c.Removed.Insert(w.path)
} else if !reflect.DeepEqual(w.rhs, w.lhs) {
// TODO: reflect.DeepEqual is not sufficient for this.
// 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)
} else if w.rhs == nil {
c.Removed.Insert(w.path)
}
})
if err != nil {
return nil, err
}
return c, nil
}
func merge(lhs, rhs TypedValue, rule, postRule mergeRule) (TypedValue, error) {
if lhs.schema != rhs.schema {
return TypedValue{}, errorFormatter{}.
errorf("expected objects with types from the same schema")
}
if !reflect.DeepEqual(lhs.typeRef, rhs.typeRef) {
return TypedValue{}, errorFormatter{}.
errorf("expected objects of the same type, but got %v and %v", lhs.typeRef, rhs.typeRef)
}
mw := mergingWalker{
lhs: &lhs.value,
rhs: &rhs.value,
schema: lhs.schema,
typeRef: lhs.typeRef,
rule: rule,
postItemHook: postRule,
}
errs := mw.merge()
if len(errs) > 0 {
return TypedValue{}, errs
}
out := TypedValue{
schema: lhs.schema,
typeRef: lhs.typeRef,
}
if mw.out == nil {
out.value = value.Value{Null: true}
} else {
out.value = *mw.out
}
return out, nil
}
// AsTypeUnvalidated is just like WithType, but doesn't validate that the type
// conforms to the schema, for cases where that has already been checked or
// where you're going to call a method that validates as a side-effect (like
// ToFieldSet).
func AsTypedUnvalidated(v value.Value, s *schema.Schema, typeName string) TypedValue {
tv := TypedValue{
value: v,
typeRef: schema.TypeRef{NamedType: &typeName},
schema: s,
}
return tv
}

View File

@@ -22,7 +22,7 @@ import (
"sigs.k8s.io/structured-merge-diff/value"
)
func (tv TypedValue) walker() *validatingObjectWalker {
func (tv typedValue) walker() *validatingObjectWalker {
return &validatingObjectWalker{
value: tv.value,
schema: tv.schema,

View File

@@ -31,7 +31,7 @@ import (
func FromYAML(input []byte) (Value, error) {
var decoded interface{}
if len(input) == 0 || (len(input) == 4 && string(input) == "null") {
if len(input) == 4 && string(input) == "null" {
// Special case since the yaml package doesn't accurately
// preserve this.
return Value{Null: true}, nil