mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-24 04:06:03 +00:00
Address PR comments
This commit is contained in:
parent
df5fc7a2df
commit
32e16d09b3
@ -76,33 +76,6 @@ type FieldMeta interface {
|
||||
GetFieldType() string
|
||||
}
|
||||
|
||||
// HasElementData contains whether a field was set in the recorded, local and remote sources
|
||||
type HasElementData struct {
|
||||
// RecordedSet is true if the field was found in the recorded object
|
||||
RecordedSet bool
|
||||
|
||||
// LocalSet is true if the field was found in the local object
|
||||
LocalSet bool
|
||||
|
||||
// RemoteSet is true if the field was found in the remote object
|
||||
RemoteSet bool
|
||||
}
|
||||
|
||||
// HasRecorded implements Element.HasRecorded
|
||||
func (e HasElementData) HasRecorded() bool {
|
||||
return e.RecordedSet
|
||||
}
|
||||
|
||||
// HasLocal implements Element.HasLocal
|
||||
func (e HasElementData) HasLocal() bool {
|
||||
return e.LocalSet
|
||||
}
|
||||
|
||||
// HasRemote implements Element.HasRemote
|
||||
func (e HasElementData) HasRemote() bool {
|
||||
return e.RemoteSet
|
||||
}
|
||||
|
||||
// FieldMetaImpl implements FieldMeta
|
||||
type FieldMetaImpl struct {
|
||||
// The type of merge strategy to use for this field
|
||||
@ -195,7 +168,7 @@ type CombinedPrimitiveSlice struct {
|
||||
|
||||
// PrimitiveListItem represents a single value in a slice of primitives
|
||||
type PrimitiveListItem struct {
|
||||
// Value is the value of the primitive, should match Recorded, Local and Remote
|
||||
// Value is the value of the primitive, should match recorded, local and remote
|
||||
Value interface{}
|
||||
|
||||
RawElementData
|
||||
@ -230,21 +203,27 @@ func (s *CombinedPrimitiveSlice) upsert(l interface{}) *PrimitiveListItem {
|
||||
// slice for either the local or remote, set on that value as the recorded value
|
||||
// Otherwise append a new item to the list with the recorded value.
|
||||
func (s *CombinedPrimitiveSlice) UpsertRecorded(l interface{}) {
|
||||
s.upsert(l).Recorded = l
|
||||
v := s.upsert(l)
|
||||
v.recorded = l
|
||||
v.recordedSet = true
|
||||
}
|
||||
|
||||
// UpsertLocal adds l to the slice. If there is already a value of l in the
|
||||
// slice for either the recorded or remote, set on that value as the local value
|
||||
// Otherwise append a new item to the list with the local value.
|
||||
func (s *CombinedPrimitiveSlice) UpsertLocal(l interface{}) {
|
||||
s.upsert(l).Local = l
|
||||
v := s.upsert(l)
|
||||
v.local = l
|
||||
v.localSet = true
|
||||
}
|
||||
|
||||
// UpsertRemote adds l to the slice. If there is already a value of l in the
|
||||
// slice for either the local or recorded, set on that value as the remote value
|
||||
// Otherwise append a new item to the list with the remote value.
|
||||
func (s *CombinedPrimitiveSlice) UpsertRemote(l interface{}) {
|
||||
s.upsert(l).Recorded = l
|
||||
v := s.upsert(l)
|
||||
v.remote = l
|
||||
v.remoteSet = true
|
||||
}
|
||||
|
||||
// ListItem represents a single value in a slice of maps or types
|
||||
@ -299,7 +278,8 @@ func (s *CombinedMapSlice) UpsertRecorded(key MergeKeys, l interface{}) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
item.Recorded = l
|
||||
item.recorded = l
|
||||
item.recordedSet = true
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -311,7 +291,8 @@ func (s *CombinedMapSlice) UpsertLocal(key MergeKeys, l interface{}) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
item.Local = l
|
||||
item.local = l
|
||||
item.localSet = true
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -323,7 +304,8 @@ func (s *CombinedMapSlice) UpsertRemote(key MergeKeys, l interface{}) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
item.Remote = l
|
||||
item.remote = l
|
||||
item.remoteSet = true
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -345,29 +327,97 @@ func IsAdd(e Element) bool {
|
||||
return e.HasLocal() && !e.HasRemote()
|
||||
}
|
||||
|
||||
// NewRawElementData returns a new RawElementData, setting IsSet to true for
|
||||
// non-nil values, and leaving IsSet false for nil values.
|
||||
// Note: use this only when you want a nil-value to be considered "unspecified"
|
||||
// (ignore) and not "unset" (deleted).
|
||||
func NewRawElementData(recorded, local, remote interface{}) RawElementData {
|
||||
data := RawElementData{}
|
||||
if recorded != nil {
|
||||
data.SetRecorded(recorded)
|
||||
}
|
||||
if local != nil {
|
||||
data.SetLocal(local)
|
||||
}
|
||||
if remote != nil {
|
||||
data.SetRemote(remote)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// RawElementData contains the raw recorded, local and remote data
|
||||
// and metadata about whethere or not each was set
|
||||
type RawElementData struct {
|
||||
// recorded contains the value of the field from the recorded object
|
||||
Recorded interface{}
|
||||
HasElementData
|
||||
|
||||
// Local contains the value of the field from the recorded object
|
||||
Local interface{}
|
||||
recorded interface{}
|
||||
local interface{}
|
||||
remote interface{}
|
||||
}
|
||||
|
||||
// Remote contains the value of the field from the recorded object
|
||||
Remote interface{}
|
||||
// SetRecorded sets the recorded value
|
||||
func (b *RawElementData) SetRecorded(value interface{}) {
|
||||
b.recorded = value
|
||||
b.recordedSet = true
|
||||
}
|
||||
|
||||
// SetLocal sets the recorded value
|
||||
func (b *RawElementData) SetLocal(value interface{}) {
|
||||
b.local = value
|
||||
b.localSet = true
|
||||
}
|
||||
|
||||
// SetRemote sets the recorded value
|
||||
func (b *RawElementData) SetRemote(value interface{}) {
|
||||
b.remote = value
|
||||
b.remoteSet = true
|
||||
}
|
||||
|
||||
// GetRecorded implements Element.GetRecorded
|
||||
func (e RawElementData) GetRecorded() interface{} {
|
||||
return e.Recorded
|
||||
func (b RawElementData) GetRecorded() interface{} {
|
||||
// https://golang.org/doc/faq#nil_error
|
||||
if b.recorded == nil {
|
||||
return nil
|
||||
}
|
||||
return b.recorded
|
||||
}
|
||||
|
||||
// GetLocal implements Element.GetLocal
|
||||
func (e RawElementData) GetLocal() interface{} {
|
||||
return e.Local
|
||||
func (b RawElementData) GetLocal() interface{} {
|
||||
// https://golang.org/doc/faq#nil_error
|
||||
if b.local == nil {
|
||||
return nil
|
||||
}
|
||||
return b.local
|
||||
}
|
||||
|
||||
// GetRemote implements Element.GetRemote
|
||||
func (e RawElementData) GetRemote() interface{} {
|
||||
return e.Remote
|
||||
func (b RawElementData) GetRemote() interface{} {
|
||||
// https://golang.org/doc/faq#nil_error
|
||||
if b.remote == nil {
|
||||
return nil
|
||||
}
|
||||
return b.remote
|
||||
}
|
||||
|
||||
// HasElementData contains whether a field was set in the recorded, local and remote sources
|
||||
type HasElementData struct {
|
||||
recordedSet bool
|
||||
localSet bool
|
||||
remoteSet bool
|
||||
}
|
||||
|
||||
// HasRecorded implements Element.HasRecorded
|
||||
func (e HasElementData) HasRecorded() bool {
|
||||
return e.recordedSet
|
||||
}
|
||||
|
||||
// HasLocal implements Element.HasLocal
|
||||
func (e HasElementData) HasLocal() bool {
|
||||
return e.localSet
|
||||
}
|
||||
|
||||
// HasRemote implements Element.HasRemote
|
||||
func (e HasElementData) HasRemote() bool {
|
||||
return e.remoteSet
|
||||
}
|
||||
|
@ -22,10 +22,6 @@ type ListElement struct {
|
||||
// FieldMetaImpl contains metadata about the field from openapi
|
||||
FieldMetaImpl
|
||||
|
||||
// HasElementData contains whether the field was set
|
||||
HasElementData
|
||||
|
||||
// ListElementData contains the value a field was set to
|
||||
ListElementData
|
||||
|
||||
// Values contains the combined recorded-local-remote value of each item in the list
|
||||
@ -44,39 +40,28 @@ var _ Element = &ListElement{}
|
||||
|
||||
// ListElementData contains the recorded, local and remote data for a list
|
||||
type ListElementData struct {
|
||||
// recorded contains the value of the field from the recorded object
|
||||
Recorded []interface{}
|
||||
|
||||
// Local contains the value of the field from the recorded object
|
||||
Local []interface{}
|
||||
|
||||
// Remote contains the value of the field from the recorded object
|
||||
Remote []interface{}
|
||||
RawElementData
|
||||
}
|
||||
|
||||
// GetRecorded implements Element.GetRecorded
|
||||
func (e ListElementData) GetRecorded() interface{} {
|
||||
// https://golang.org/doc/faq#nil_error
|
||||
if e.Recorded == nil {
|
||||
// GetRecordedList returns the Recorded value as a list
|
||||
func (e ListElementData) GetRecordedList() []interface{} {
|
||||
return sliceCast(e.recorded)
|
||||
}
|
||||
|
||||
// GetLocalList returns the Local value as a list
|
||||
func (e ListElementData) GetLocalList() []interface{} {
|
||||
return sliceCast(e.local)
|
||||
}
|
||||
|
||||
// GetRemoteList returns the Remote value as a list
|
||||
func (e ListElementData) GetRemoteList() []interface{} {
|
||||
return sliceCast(e.remote)
|
||||
}
|
||||
|
||||
// sliceCast casts i to a slice if it is non-nil, otherwise returns nil
|
||||
func sliceCast(i interface{}) []interface{} {
|
||||
if i == nil {
|
||||
return nil
|
||||
}
|
||||
return e.Recorded
|
||||
}
|
||||
|
||||
// GetLocal implements Element.GetLocal
|
||||
func (e ListElementData) GetLocal() interface{} {
|
||||
// https://golang.org/doc/faq#nil_error
|
||||
if e.Local == nil {
|
||||
return nil
|
||||
}
|
||||
return e.Local
|
||||
}
|
||||
|
||||
// GetRemote implements Element.GetRemote
|
||||
func (e ListElementData) GetRemote() interface{} {
|
||||
// https://golang.org/doc/faq#nil_error
|
||||
if e.Remote == nil {
|
||||
return nil
|
||||
}
|
||||
return e.Remote
|
||||
return i.([]interface{})
|
||||
}
|
||||
|
@ -22,9 +22,6 @@ type MapElement struct {
|
||||
// FieldMetaImpl contains metadata about the field from openapi
|
||||
FieldMetaImpl
|
||||
|
||||
// HasElementData contains whether the field was set
|
||||
HasElementData
|
||||
|
||||
// MapElementData contains the value a field was set to
|
||||
MapElementData
|
||||
|
||||
@ -48,39 +45,28 @@ var _ Element = &MapElement{}
|
||||
|
||||
// MapElementData contains the recorded, local and remote data for a map or type
|
||||
type MapElementData struct {
|
||||
// recorded contains the value of the field from the recorded object
|
||||
Recorded map[string]interface{}
|
||||
|
||||
// Local contains the value of the field from the recorded object
|
||||
Local map[string]interface{}
|
||||
|
||||
// Remote contains the value of the field from the recorded object
|
||||
Remote map[string]interface{}
|
||||
RawElementData
|
||||
}
|
||||
|
||||
// GetRecorded implements Element.GetRecorded
|
||||
func (e MapElementData) GetRecorded() interface{} {
|
||||
// https://golang.org/doc/faq#nil_error
|
||||
if e.Recorded == nil {
|
||||
// GetRecordedMap returns the Recorded value as a map
|
||||
func (e MapElementData) GetRecordedMap() map[string]interface{} {
|
||||
return mapCast(e.recorded)
|
||||
}
|
||||
|
||||
// GetLocalMap returns the Local value as a map
|
||||
func (e MapElementData) GetLocalMap() map[string]interface{} {
|
||||
return mapCast(e.local)
|
||||
}
|
||||
|
||||
// GetRemoteMap returns the Remote value as a map
|
||||
func (e MapElementData) GetRemoteMap() map[string]interface{} {
|
||||
return mapCast(e.remote)
|
||||
}
|
||||
|
||||
// mapCast casts i to a map if it is non-nil, otherwise returns nil
|
||||
func mapCast(i interface{}) map[string]interface{} {
|
||||
if i == nil {
|
||||
return nil
|
||||
}
|
||||
return e.Recorded
|
||||
}
|
||||
|
||||
// GetLocal implements Element.GetLocal
|
||||
func (e MapElementData) GetLocal() interface{} {
|
||||
// https://golang.org/doc/faq#nil_error
|
||||
if e.Local == nil {
|
||||
return nil
|
||||
}
|
||||
return e.Local
|
||||
}
|
||||
|
||||
// GetRemote implements Element.GetRemote
|
||||
func (e MapElementData) GetRemote() interface{} {
|
||||
// https://golang.org/doc/faq#nil_error
|
||||
if e.Remote == nil {
|
||||
return nil
|
||||
}
|
||||
return e.Remote
|
||||
return i.(map[string]interface{})
|
||||
}
|
||||
|
@ -48,14 +48,9 @@ func (b *Factory) CreateElement(recorded, local, remote map[string]interface{})
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get the item for the type
|
||||
hasRecorded := recorded != nil
|
||||
hasLocal := local != nil
|
||||
hasRemote := remote != nil
|
||||
data := apply.NewRawElementData(recorded, local, remote)
|
||||
fieldName := ""
|
||||
item, err := visitor.getItem(oapiKind, fieldName,
|
||||
apply.RawElementData{recorded, local, remote},
|
||||
apply.HasElementData{hasRecorded, hasLocal, hasRemote})
|
||||
item, err := visitor.getItem(oapiKind, fieldName, data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -65,10 +60,8 @@ func (b *Factory) CreateElement(recorded, local, remote map[string]interface{})
|
||||
}
|
||||
|
||||
// getItem returns the appropriate Item based on the underlying type of the arguments
|
||||
func (v *ElementBuildingVisitor) getItem(s openapi.Schema, name string,
|
||||
data apply.RawElementData,
|
||||
isSet apply.HasElementData) (Item, error) {
|
||||
kind, err := getType(data.Recorded, data.Local, data.Remote)
|
||||
func (v *ElementBuildingVisitor) getItem(s openapi.Schema, name string, data apply.RawElementData) (Item, error) {
|
||||
kind, err := getType(data.GetRecorded(), data.GetLocal(), data.GetRemote())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -86,38 +79,23 @@ func (v *ElementBuildingVisitor) getItem(s openapi.Schema, name string,
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("expected openapi Primitive, was %T for %v", s, kind)
|
||||
}
|
||||
return &primitiveItem{name, p, isSet, data}, nil
|
||||
return &primitiveItem{name, p, data}, nil
|
||||
case reflect.Array, reflect.Slice:
|
||||
a, err := getArray(s)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("expected openapi Array, was %T for %v", s, kind)
|
||||
}
|
||||
return &listItem{name, a, isSet,
|
||||
apply.ListElementData{
|
||||
sliceCast(data.Recorded),
|
||||
sliceCast(data.Local),
|
||||
sliceCast(data.Remote),
|
||||
}}, nil
|
||||
return &listItem{name, a, apply.ListElementData{data}}, nil
|
||||
case reflect.Map:
|
||||
if k, err := getKind(s); err == nil {
|
||||
return &typeItem{name, k, isSet,
|
||||
apply.MapElementData{
|
||||
mapCast(data.Recorded),
|
||||
mapCast(data.Local),
|
||||
mapCast(data.Remote),
|
||||
}}, nil
|
||||
return &typeItem{name, k, apply.MapElementData{data}}, nil
|
||||
}
|
||||
// If it looks like a map, and no openapi type is found, default to mapItem
|
||||
m, err := getMap(s)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("expected openapi Kind or Map, was %T for %v", s, kind)
|
||||
}
|
||||
return &mapItem{name, m, isSet,
|
||||
apply.MapElementData{
|
||||
mapCast(data.Recorded),
|
||||
mapCast(data.Local),
|
||||
mapCast(data.Remote),
|
||||
}}, nil
|
||||
return &mapItem{name, m, apply.MapElementData{data}}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unsupported type type %v", kind)
|
||||
}
|
||||
|
@ -33,7 +33,6 @@ type primitiveItem struct {
|
||||
Name string
|
||||
Primitive *openapi.Primitive
|
||||
|
||||
apply.HasElementData
|
||||
apply.RawElementData
|
||||
}
|
||||
|
||||
@ -54,7 +53,6 @@ type listItem struct {
|
||||
Name string
|
||||
Array *openapi.Array
|
||||
|
||||
apply.HasElementData
|
||||
apply.ListElementData
|
||||
}
|
||||
|
||||
@ -75,7 +73,6 @@ type mapItem struct {
|
||||
Name string
|
||||
Map *openapi.Map
|
||||
|
||||
apply.HasElementData
|
||||
apply.MapElementData
|
||||
}
|
||||
|
||||
@ -96,7 +93,6 @@ type typeItem struct {
|
||||
Name string
|
||||
Type *openapi.Kind
|
||||
|
||||
apply.HasElementData
|
||||
apply.MapElementData
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,6 @@ func (v ElementBuildingVisitor) doPrimitiveList(meta apply.FieldMetaImpl, item *
|
||||
MergeType: "merge",
|
||||
Name: item.Name,
|
||||
},
|
||||
HasElementData: item.HasElementData,
|
||||
ListElementData: item.ListElementData,
|
||||
Values: []apply.Element{},
|
||||
}
|
||||
@ -57,32 +56,26 @@ func (v ElementBuildingVisitor) doPrimitiveList(meta apply.FieldMetaImpl, item *
|
||||
|
||||
// Locally defined items come first and retain their order
|
||||
// as defined locally
|
||||
for _, l := range item.Local {
|
||||
for _, l := range item.GetLocalList() {
|
||||
orderedKeys.UpsertLocal(l)
|
||||
}
|
||||
// Mixin remote values, adding any that are not present locally
|
||||
for _, l := range item.Remote {
|
||||
for _, l := range item.GetRemoteList() {
|
||||
orderedKeys.UpsertRemote(l)
|
||||
}
|
||||
// Mixin recorded values, adding any that are not present locally
|
||||
// or remotely
|
||||
for _, l := range item.Recorded {
|
||||
for _, l := range item.GetRecordedList() {
|
||||
orderedKeys.UpsertRecorded(l)
|
||||
}
|
||||
|
||||
for i, l := range orderedKeys.Items {
|
||||
recordedSet := l.Recorded != nil
|
||||
localSet := l.Local != nil
|
||||
remoteSet := l.Remote != nil
|
||||
|
||||
var s openapi.Schema
|
||||
if item.Array != nil && item.Array.SubType != nil {
|
||||
s = item.Array.SubType
|
||||
}
|
||||
|
||||
subitem, err := v.getItem(s, fmt.Sprintf("%d", i),
|
||||
l.RawElementData,
|
||||
apply.HasElementData{recordedSet, localSet, remoteSet})
|
||||
subitem, err := v.getItem(s, fmt.Sprintf("%d", i), l.RawElementData)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -111,7 +104,6 @@ func (v ElementBuildingVisitor) doMapList(meta apply.FieldMetaImpl, item *listIt
|
||||
MergeKeys: key,
|
||||
Name: item.Name,
|
||||
},
|
||||
HasElementData: item.HasElementData,
|
||||
ListElementData: item.ListElementData,
|
||||
Values: []apply.Element{},
|
||||
}
|
||||
@ -121,31 +113,25 @@ func (v ElementBuildingVisitor) doMapList(meta apply.FieldMetaImpl, item *listIt
|
||||
|
||||
// Locally defined items come first and retain their order
|
||||
// as defined locally
|
||||
for _, l := range item.Local {
|
||||
for _, l := range item.GetLocalList() {
|
||||
orderedKeys.UpsertLocal(key, l)
|
||||
}
|
||||
// Mixin remote values, adding any that are not present locally
|
||||
for _, l := range item.Remote {
|
||||
for _, l := range item.GetRemoteList() {
|
||||
orderedKeys.UpsertRemote(key, l)
|
||||
}
|
||||
// Mixin recorded values, adding any that are not present locally
|
||||
// or remotely
|
||||
for _, l := range item.Recorded {
|
||||
for _, l := range item.GetRecordedList() {
|
||||
orderedKeys.UpsertRecorded(key, l)
|
||||
}
|
||||
|
||||
for i, l := range orderedKeys.Items {
|
||||
recordedSet := l.Recorded != nil
|
||||
localSet := l.Local != nil
|
||||
remoteSet := l.Remote != nil
|
||||
|
||||
var s openapi.Schema
|
||||
if item.Array != nil && item.Array.SubType != nil {
|
||||
s = item.Array.SubType
|
||||
}
|
||||
subitem, err := v.getItem(s, fmt.Sprintf("%d", i),
|
||||
l.RawElementData,
|
||||
apply.HasElementData{recordedSet, localSet, remoteSet})
|
||||
subitem, err := v.getItem(s, fmt.Sprintf("%d", i), l.RawElementData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -166,30 +152,30 @@ func (v ElementBuildingVisitor) doMapList(meta apply.FieldMetaImpl, item *listIt
|
||||
// replaceListElement builds a new ListElement from a listItem
|
||||
// Uses the "replace" strategy and identify "same" elements across lists by their index
|
||||
func (v ElementBuildingVisitor) replaceListElement(meta apply.FieldMetaImpl, item *listItem) (*apply.ListElement, error) {
|
||||
result := &apply.ListElement{
|
||||
FieldMetaImpl: meta,
|
||||
ListElementData: item.ListElementData,
|
||||
HasElementData: item.HasElementData,
|
||||
Values: []apply.Element{},
|
||||
}
|
||||
result.Name = item.Name
|
||||
meta.Name = item.Name
|
||||
result := &apply.ListElement{meta, item.ListElementData, []apply.Element{}}
|
||||
|
||||
// Use the max length to iterate over the slices
|
||||
for i := 0; i < max(len(item.Recorded), len(item.Local), len(item.Remote)); i++ {
|
||||
for i := 0; i < max(len(item.GetRecordedList()), len(item.GetLocalList()), len(item.GetRemoteList())); i++ {
|
||||
|
||||
// Lookup the item from each list
|
||||
recorded, recordedSet := boundsSafeLookup(i, item.Recorded)
|
||||
local, localSet := boundsSafeLookup(i, item.Local)
|
||||
remote, remoteSet := boundsSafeLookup(i, item.Remote)
|
||||
data := apply.RawElementData{}
|
||||
if recorded, recordedSet := boundsSafeLookup(i, item.GetRecordedList()); recordedSet {
|
||||
data.SetRecorded(recorded)
|
||||
}
|
||||
if local, localSet := boundsSafeLookup(i, item.GetLocalList()); localSet {
|
||||
data.SetLocal(local)
|
||||
}
|
||||
if remote, remoteSet := boundsSafeLookup(i, item.GetRemoteList()); remoteSet {
|
||||
data.SetRemote(remote)
|
||||
}
|
||||
|
||||
// Create the Item
|
||||
var s openapi.Schema
|
||||
if item.Array != nil && item.Array.SubType != nil {
|
||||
s = item.Array.SubType
|
||||
}
|
||||
subitem, err := v.getItem(s, fmt.Sprintf("%d", i),
|
||||
apply.RawElementData{recorded, local, remote},
|
||||
apply.HasElementData{recordedSet, localSet, remoteSet})
|
||||
subitem, err := v.getItem(s, fmt.Sprintf("%d", i), data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -33,18 +33,13 @@ func (v ElementBuildingVisitor) mapElement(meta apply.FieldMetaImpl, item *mapIt
|
||||
}
|
||||
|
||||
// Collect same fields from multiple maps into a map of elements
|
||||
values, err := v.createMapValues(fn, meta, item.HasElementData, item.MapElementData)
|
||||
values, err := v.createMapValues(fn, meta, item.MapElementData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Return the result
|
||||
return &apply.MapElement{
|
||||
FieldMetaImpl: meta,
|
||||
HasElementData: item.HasElementData,
|
||||
MapElementData: item.MapElementData,
|
||||
Values: values,
|
||||
}, nil
|
||||
return &apply.MapElement{meta, item.MapElementData, values}, nil
|
||||
}
|
||||
|
||||
// schemaFn returns the schema for a field or map value based on its name or key
|
||||
@ -55,20 +50,24 @@ type schemaFn func(key string) openapi.Schema
|
||||
func (v ElementBuildingVisitor) createMapValues(
|
||||
schemaFn schemaFn,
|
||||
meta apply.FieldMetaImpl,
|
||||
hasData apply.HasElementData,
|
||||
data apply.MapElementData) (map[string]apply.Element, error) {
|
||||
|
||||
// Collate each key in the map
|
||||
values := map[string]apply.Element{}
|
||||
for _, key := range keysUnion(data.Recorded, data.Local, data.Remote) {
|
||||
recorded, recordedSet := nilSafeLookup(key, data.Recorded)
|
||||
local, localSet := nilSafeLookup(key, data.Local)
|
||||
remote, remoteSet := nilSafeLookup(key, data.Remote)
|
||||
for _, key := range keysUnion(data.GetRecordedMap(), data.GetLocalMap(), data.GetRemoteMap()) {
|
||||
combined := apply.RawElementData{}
|
||||
if recorded, recordedSet := nilSafeLookup(key, data.GetRecordedMap()); recordedSet {
|
||||
combined.SetRecorded(recorded)
|
||||
}
|
||||
if local, localSet := nilSafeLookup(key, data.GetLocalMap()); localSet {
|
||||
combined.SetLocal(local)
|
||||
}
|
||||
if remote, remoteSet := nilSafeLookup(key, data.GetRemoteMap()); remoteSet {
|
||||
combined.SetRemote(remote)
|
||||
}
|
||||
|
||||
// Create an item for the field
|
||||
field, err := v.getItem(schemaFn(key), key,
|
||||
apply.RawElementData{recorded, local, remote},
|
||||
apply.HasElementData{recordedSet, localSet, remoteSet})
|
||||
field, err := v.getItem(schemaFn(key), key, combined)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -20,11 +20,6 @@ import "k8s.io/kubernetes/pkg/kubectl/apply"
|
||||
|
||||
// primitiveElement builds a new primitiveElement from a PrimitiveItem
|
||||
func (v ElementBuildingVisitor) primitiveElement(item *primitiveItem) (*apply.PrimitiveElement, error) {
|
||||
result := &apply.PrimitiveElement{
|
||||
HasElementData: item.HasElementData,
|
||||
RawElementData: item.RawElementData,
|
||||
}
|
||||
result.Name = item.Name
|
||||
|
||||
return result, nil
|
||||
meta := apply.FieldMetaImpl{Name: item.Name}
|
||||
return &apply.PrimitiveElement{meta, item.RawElementData}, nil
|
||||
}
|
||||
|
@ -32,16 +32,11 @@ func (v ElementBuildingVisitor) typeElement(meta apply.FieldMetaImpl, item *type
|
||||
}
|
||||
|
||||
// Collect same fields from multiple maps into a map of elements
|
||||
values, err := v.createMapValues(fn, meta, item.HasElementData, item.MapElementData)
|
||||
values, err := v.createMapValues(fn, meta, item.MapElementData)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Return the result
|
||||
return &apply.TypeElement{
|
||||
FieldMetaImpl: meta,
|
||||
HasElementData: item.HasElementData,
|
||||
MapElementData: item.MapElementData,
|
||||
Values: values,
|
||||
}, nil
|
||||
return &apply.TypeElement{meta, item.MapElementData, values}, nil
|
||||
}
|
||||
|
@ -95,22 +95,6 @@ func getType(args ...interface{}) (reflect.Type, error) {
|
||||
return reflect.TypeOf(last), nil
|
||||
}
|
||||
|
||||
// sliceCast casts i to a slice if it is non-nil, otherwise returns nil
|
||||
func sliceCast(i interface{}) []interface{} {
|
||||
if i == nil {
|
||||
return nil
|
||||
}
|
||||
return i.([]interface{})
|
||||
}
|
||||
|
||||
// mapCast casts i to a map if it is non-nil, otherwise returns nil
|
||||
func mapCast(i interface{}) map[string]interface{} {
|
||||
if i == nil {
|
||||
return nil
|
||||
}
|
||||
return i.(map[string]interface{})
|
||||
}
|
||||
|
||||
// getFieldMeta parses the metadata about the field from the openapi spec
|
||||
func getFieldMeta(s openapi.Schema, name string) (apply.FieldMetaImpl, error) {
|
||||
m := apply.FieldMetaImpl{}
|
||||
|
@ -16,19 +16,12 @@ limitations under the License.
|
||||
|
||||
package apply
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// PrimitiveElement contains the recorded, local and remote values for a field
|
||||
// of type primitive
|
||||
type PrimitiveElement struct {
|
||||
// FieldMetaImpl contains metadata about the field from openapi
|
||||
FieldMetaImpl
|
||||
|
||||
// HasElementData contains whether the field was set
|
||||
HasElementData
|
||||
|
||||
// RawElementData contains the values the field was set to
|
||||
RawElementData
|
||||
}
|
||||
@ -38,9 +31,4 @@ func (e PrimitiveElement) Merge(v Strategy) (Result, error) {
|
||||
return v.MergePrimitive(e)
|
||||
}
|
||||
|
||||
// String returns a string representation of the PrimitiveElement
|
||||
func (e PrimitiveElement) String() string {
|
||||
return fmt.Sprintf("name: %s recorded: %v local: %v remote: %v", e.Name, e.Recorded, e.Local, e.Remote)
|
||||
}
|
||||
|
||||
var _ Element = &PrimitiveElement{}
|
||||
|
@ -20,32 +20,14 @@ import "k8s.io/kubernetes/pkg/kubectl/apply"
|
||||
|
||||
// Options controls how a merge will be executed
|
||||
type Options struct {
|
||||
// FailOnConflict when true will fail patch creation if the Recorded and Remote
|
||||
// FailOnConflict when true will fail patch creation if the recorded and remote
|
||||
// have 2 fields set for the same value that cannot be merged.
|
||||
// e.g. primitive values, list values with replace strategy, and map values with do
|
||||
// strategy
|
||||
FailOnConflict bool
|
||||
|
||||
// ListOrder controls the order of items in a list after it is merged
|
||||
ListOrder ListOrder
|
||||
}
|
||||
|
||||
// Create returns a new apply.Visitor for merging multiple objects together
|
||||
func Create(options Options) apply.Strategy {
|
||||
return createDelegatingStrategy(options)
|
||||
}
|
||||
|
||||
// ListOrder allows the caller to controller how ordering is determined when merging
|
||||
// lists
|
||||
// TODO: Implement this
|
||||
type ListOrder int
|
||||
|
||||
const (
|
||||
// RemoteOnlyLast appends items only appearing in the remote list to the end
|
||||
RemoteOnlyLast ListOrder = iota
|
||||
// RemoteOnlyFirst prepends items only appearing in the remote list to the beginning
|
||||
RemoteOnlyFirst
|
||||
// RemoteCollated will try to preserve the order of elements as much as possible by
|
||||
// interleaving items
|
||||
RemoteCollated
|
||||
)
|
||||
|
@ -46,19 +46,20 @@ func (v mergeStrategy) MergeList(e apply.ListElement) (apply.Result, error) {
|
||||
merged := []interface{}{}
|
||||
for _, value := range e.Values {
|
||||
// Recursively merge the list element before adding the value to the list
|
||||
result, err := value.Merge(v.strategic)
|
||||
m, err := value.Merge(v.strategic)
|
||||
if err != nil {
|
||||
return apply.Result{}, err
|
||||
}
|
||||
|
||||
switch result.Operation {
|
||||
fmt.Printf("\nResult %+v\n%+v\n", m.MergedResult, value)
|
||||
switch m.Operation {
|
||||
case apply.SET:
|
||||
// Keep the list item value
|
||||
merged = append(merged, result.MergedResult)
|
||||
merged = append(merged, m.MergedResult)
|
||||
case apply.DROP:
|
||||
// Drop the list item value
|
||||
default:
|
||||
panic(fmt.Errorf("Unexpected result operation type %+v", result))
|
||||
panic(fmt.Errorf("Unexpected result operation type %+v", m))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,10 +22,6 @@ type TypeElement struct {
|
||||
// FieldMetaImpl contains metadata about the field from openapi
|
||||
FieldMetaImpl
|
||||
|
||||
// HasElementData contains whether the field was set
|
||||
HasElementData
|
||||
|
||||
// ListElementData contains the value a field was set to
|
||||
MapElementData
|
||||
|
||||
// Values contains the combined recorded-local-remote value of each field in the type
|
||||
|
Loading…
Reference in New Issue
Block a user