mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 12:43:23 +00:00
Address PR comments
This commit is contained in:
parent
df5fc7a2df
commit
32e16d09b3
@ -76,33 +76,6 @@ type FieldMeta interface {
|
|||||||
GetFieldType() string
|
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
|
// FieldMetaImpl implements FieldMeta
|
||||||
type FieldMetaImpl struct {
|
type FieldMetaImpl struct {
|
||||||
// The type of merge strategy to use for this field
|
// 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
|
// PrimitiveListItem represents a single value in a slice of primitives
|
||||||
type PrimitiveListItem struct {
|
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{}
|
Value interface{}
|
||||||
|
|
||||||
RawElementData
|
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
|
// 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.
|
// Otherwise append a new item to the list with the recorded value.
|
||||||
func (s *CombinedPrimitiveSlice) UpsertRecorded(l interface{}) {
|
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
|
// 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
|
// 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.
|
// Otherwise append a new item to the list with the local value.
|
||||||
func (s *CombinedPrimitiveSlice) UpsertLocal(l interface{}) {
|
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
|
// 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
|
// 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.
|
// Otherwise append a new item to the list with the remote value.
|
||||||
func (s *CombinedPrimitiveSlice) UpsertRemote(l interface{}) {
|
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
|
// 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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
item.Recorded = l
|
item.recorded = l
|
||||||
|
item.recordedSet = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,7 +291,8 @@ func (s *CombinedMapSlice) UpsertLocal(key MergeKeys, l interface{}) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
item.Local = l
|
item.local = l
|
||||||
|
item.localSet = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -323,7 +304,8 @@ func (s *CombinedMapSlice) UpsertRemote(key MergeKeys, l interface{}) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
item.Remote = l
|
item.remote = l
|
||||||
|
item.remoteSet = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,29 +327,97 @@ func IsAdd(e Element) bool {
|
|||||||
return e.HasLocal() && !e.HasRemote()
|
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
|
// RawElementData contains the raw recorded, local and remote data
|
||||||
|
// and metadata about whethere or not each was set
|
||||||
type RawElementData struct {
|
type RawElementData struct {
|
||||||
// recorded contains the value of the field from the recorded object
|
HasElementData
|
||||||
Recorded interface{}
|
|
||||||
|
|
||||||
// Local contains the value of the field from the recorded object
|
recorded interface{}
|
||||||
Local interface{}
|
local interface{}
|
||||||
|
remote interface{}
|
||||||
|
}
|
||||||
|
|
||||||
// Remote contains the value of the field from the recorded object
|
// SetRecorded sets the recorded value
|
||||||
Remote interface{}
|
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
|
// GetRecorded implements Element.GetRecorded
|
||||||
func (e RawElementData) GetRecorded() interface{} {
|
func (b RawElementData) GetRecorded() interface{} {
|
||||||
return e.Recorded
|
// https://golang.org/doc/faq#nil_error
|
||||||
|
if b.recorded == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return b.recorded
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLocal implements Element.GetLocal
|
// GetLocal implements Element.GetLocal
|
||||||
func (e RawElementData) GetLocal() interface{} {
|
func (b RawElementData) GetLocal() interface{} {
|
||||||
return e.Local
|
// https://golang.org/doc/faq#nil_error
|
||||||
|
if b.local == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return b.local
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRemote implements Element.GetRemote
|
// GetRemote implements Element.GetRemote
|
||||||
func (e RawElementData) GetRemote() interface{} {
|
func (b RawElementData) GetRemote() interface{} {
|
||||||
return e.Remote
|
// 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 contains metadata about the field from openapi
|
||||||
FieldMetaImpl
|
FieldMetaImpl
|
||||||
|
|
||||||
// HasElementData contains whether the field was set
|
|
||||||
HasElementData
|
|
||||||
|
|
||||||
// ListElementData contains the value a field was set to
|
|
||||||
ListElementData
|
ListElementData
|
||||||
|
|
||||||
// Values contains the combined recorded-local-remote value of each item in the list
|
// 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
|
// ListElementData contains the recorded, local and remote data for a list
|
||||||
type ListElementData struct {
|
type ListElementData struct {
|
||||||
// recorded contains the value of the field from the recorded object
|
RawElementData
|
||||||
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{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRecorded implements Element.GetRecorded
|
// GetRecordedList returns the Recorded value as a list
|
||||||
func (e ListElementData) GetRecorded() interface{} {
|
func (e ListElementData) GetRecordedList() []interface{} {
|
||||||
// https://golang.org/doc/faq#nil_error
|
return sliceCast(e.recorded)
|
||||||
if e.Recorded == nil {
|
}
|
||||||
|
|
||||||
|
// 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 nil
|
||||||
}
|
}
|
||||||
return e.Recorded
|
return i.([]interface{})
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
|
@ -22,9 +22,6 @@ type MapElement struct {
|
|||||||
// FieldMetaImpl contains metadata about the field from openapi
|
// FieldMetaImpl contains metadata about the field from openapi
|
||||||
FieldMetaImpl
|
FieldMetaImpl
|
||||||
|
|
||||||
// HasElementData contains whether the field was set
|
|
||||||
HasElementData
|
|
||||||
|
|
||||||
// MapElementData contains the value a field was set to
|
// MapElementData contains the value a field was set to
|
||||||
MapElementData
|
MapElementData
|
||||||
|
|
||||||
@ -48,39 +45,28 @@ var _ Element = &MapElement{}
|
|||||||
|
|
||||||
// MapElementData contains the recorded, local and remote data for a map or type
|
// MapElementData contains the recorded, local and remote data for a map or type
|
||||||
type MapElementData struct {
|
type MapElementData struct {
|
||||||
// recorded contains the value of the field from the recorded object
|
RawElementData
|
||||||
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{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRecorded implements Element.GetRecorded
|
// GetRecordedMap returns the Recorded value as a map
|
||||||
func (e MapElementData) GetRecorded() interface{} {
|
func (e MapElementData) GetRecordedMap() map[string]interface{} {
|
||||||
// https://golang.org/doc/faq#nil_error
|
return mapCast(e.recorded)
|
||||||
if e.Recorded == nil {
|
}
|
||||||
|
|
||||||
|
// 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 nil
|
||||||
}
|
}
|
||||||
return e.Recorded
|
return i.(map[string]interface{})
|
||||||
}
|
|
||||||
|
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
|
@ -48,14 +48,9 @@ func (b *Factory) CreateElement(recorded, local, remote map[string]interface{})
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the item for the type
|
data := apply.NewRawElementData(recorded, local, remote)
|
||||||
hasRecorded := recorded != nil
|
|
||||||
hasLocal := local != nil
|
|
||||||
hasRemote := remote != nil
|
|
||||||
fieldName := ""
|
fieldName := ""
|
||||||
item, err := visitor.getItem(oapiKind, fieldName,
|
item, err := visitor.getItem(oapiKind, fieldName, data)
|
||||||
apply.RawElementData{recorded, local, remote},
|
|
||||||
apply.HasElementData{hasRecorded, hasLocal, hasRemote})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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
|
// getItem returns the appropriate Item based on the underlying type of the arguments
|
||||||
func (v *ElementBuildingVisitor) getItem(s openapi.Schema, name string,
|
func (v *ElementBuildingVisitor) getItem(s openapi.Schema, name string, data apply.RawElementData) (Item, error) {
|
||||||
data apply.RawElementData,
|
kind, err := getType(data.GetRecorded(), data.GetLocal(), data.GetRemote())
|
||||||
isSet apply.HasElementData) (Item, error) {
|
|
||||||
kind, err := getType(data.Recorded, data.Local, data.Remote)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -86,38 +79,23 @@ func (v *ElementBuildingVisitor) getItem(s openapi.Schema, name string,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("expected openapi Primitive, was %T for %v", s, kind)
|
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:
|
case reflect.Array, reflect.Slice:
|
||||||
a, err := getArray(s)
|
a, err := getArray(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("expected openapi Array, was %T for %v", s, kind)
|
return nil, fmt.Errorf("expected openapi Array, was %T for %v", s, kind)
|
||||||
}
|
}
|
||||||
return &listItem{name, a, isSet,
|
return &listItem{name, a, apply.ListElementData{data}}, nil
|
||||||
apply.ListElementData{
|
|
||||||
sliceCast(data.Recorded),
|
|
||||||
sliceCast(data.Local),
|
|
||||||
sliceCast(data.Remote),
|
|
||||||
}}, nil
|
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
if k, err := getKind(s); err == nil {
|
if k, err := getKind(s); err == nil {
|
||||||
return &typeItem{name, k, isSet,
|
return &typeItem{name, k, apply.MapElementData{data}}, nil
|
||||||
apply.MapElementData{
|
|
||||||
mapCast(data.Recorded),
|
|
||||||
mapCast(data.Local),
|
|
||||||
mapCast(data.Remote),
|
|
||||||
}}, nil
|
|
||||||
}
|
}
|
||||||
// If it looks like a map, and no openapi type is found, default to mapItem
|
// If it looks like a map, and no openapi type is found, default to mapItem
|
||||||
m, err := getMap(s)
|
m, err := getMap(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("expected openapi Kind or Map, was %T for %v", s, kind)
|
return nil, fmt.Errorf("expected openapi Kind or Map, was %T for %v", s, kind)
|
||||||
}
|
}
|
||||||
return &mapItem{name, m, isSet,
|
return &mapItem{name, m, apply.MapElementData{data}}, nil
|
||||||
apply.MapElementData{
|
|
||||||
mapCast(data.Recorded),
|
|
||||||
mapCast(data.Local),
|
|
||||||
mapCast(data.Remote),
|
|
||||||
}}, nil
|
|
||||||
}
|
}
|
||||||
return nil, fmt.Errorf("unsupported type type %v", kind)
|
return nil, fmt.Errorf("unsupported type type %v", kind)
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,6 @@ type primitiveItem struct {
|
|||||||
Name string
|
Name string
|
||||||
Primitive *openapi.Primitive
|
Primitive *openapi.Primitive
|
||||||
|
|
||||||
apply.HasElementData
|
|
||||||
apply.RawElementData
|
apply.RawElementData
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -54,7 +53,6 @@ type listItem struct {
|
|||||||
Name string
|
Name string
|
||||||
Array *openapi.Array
|
Array *openapi.Array
|
||||||
|
|
||||||
apply.HasElementData
|
|
||||||
apply.ListElementData
|
apply.ListElementData
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +73,6 @@ type mapItem struct {
|
|||||||
Name string
|
Name string
|
||||||
Map *openapi.Map
|
Map *openapi.Map
|
||||||
|
|
||||||
apply.HasElementData
|
|
||||||
apply.MapElementData
|
apply.MapElementData
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +93,6 @@ type typeItem struct {
|
|||||||
Name string
|
Name string
|
||||||
Type *openapi.Kind
|
Type *openapi.Kind
|
||||||
|
|
||||||
apply.HasElementData
|
|
||||||
apply.MapElementData
|
apply.MapElementData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,6 @@ func (v ElementBuildingVisitor) doPrimitiveList(meta apply.FieldMetaImpl, item *
|
|||||||
MergeType: "merge",
|
MergeType: "merge",
|
||||||
Name: item.Name,
|
Name: item.Name,
|
||||||
},
|
},
|
||||||
HasElementData: item.HasElementData,
|
|
||||||
ListElementData: item.ListElementData,
|
ListElementData: item.ListElementData,
|
||||||
Values: []apply.Element{},
|
Values: []apply.Element{},
|
||||||
}
|
}
|
||||||
@ -57,32 +56,26 @@ func (v ElementBuildingVisitor) doPrimitiveList(meta apply.FieldMetaImpl, item *
|
|||||||
|
|
||||||
// Locally defined items come first and retain their order
|
// Locally defined items come first and retain their order
|
||||||
// as defined locally
|
// as defined locally
|
||||||
for _, l := range item.Local {
|
for _, l := range item.GetLocalList() {
|
||||||
orderedKeys.UpsertLocal(l)
|
orderedKeys.UpsertLocal(l)
|
||||||
}
|
}
|
||||||
// Mixin remote values, adding any that are not present locally
|
// Mixin remote values, adding any that are not present locally
|
||||||
for _, l := range item.Remote {
|
for _, l := range item.GetRemoteList() {
|
||||||
orderedKeys.UpsertRemote(l)
|
orderedKeys.UpsertRemote(l)
|
||||||
}
|
}
|
||||||
// Mixin recorded values, adding any that are not present locally
|
// Mixin recorded values, adding any that are not present locally
|
||||||
// or remotely
|
// or remotely
|
||||||
for _, l := range item.Recorded {
|
for _, l := range item.GetRecordedList() {
|
||||||
orderedKeys.UpsertRecorded(l)
|
orderedKeys.UpsertRecorded(l)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, l := range orderedKeys.Items {
|
for i, l := range orderedKeys.Items {
|
||||||
recordedSet := l.Recorded != nil
|
|
||||||
localSet := l.Local != nil
|
|
||||||
remoteSet := l.Remote != nil
|
|
||||||
|
|
||||||
var s openapi.Schema
|
var s openapi.Schema
|
||||||
if item.Array != nil && item.Array.SubType != nil {
|
if item.Array != nil && item.Array.SubType != nil {
|
||||||
s = item.Array.SubType
|
s = item.Array.SubType
|
||||||
}
|
}
|
||||||
|
|
||||||
subitem, err := v.getItem(s, fmt.Sprintf("%d", i),
|
subitem, err := v.getItem(s, fmt.Sprintf("%d", i), l.RawElementData)
|
||||||
l.RawElementData,
|
|
||||||
apply.HasElementData{recordedSet, localSet, remoteSet})
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -111,7 +104,6 @@ func (v ElementBuildingVisitor) doMapList(meta apply.FieldMetaImpl, item *listIt
|
|||||||
MergeKeys: key,
|
MergeKeys: key,
|
||||||
Name: item.Name,
|
Name: item.Name,
|
||||||
},
|
},
|
||||||
HasElementData: item.HasElementData,
|
|
||||||
ListElementData: item.ListElementData,
|
ListElementData: item.ListElementData,
|
||||||
Values: []apply.Element{},
|
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
|
// Locally defined items come first and retain their order
|
||||||
// as defined locally
|
// as defined locally
|
||||||
for _, l := range item.Local {
|
for _, l := range item.GetLocalList() {
|
||||||
orderedKeys.UpsertLocal(key, l)
|
orderedKeys.UpsertLocal(key, l)
|
||||||
}
|
}
|
||||||
// Mixin remote values, adding any that are not present locally
|
// Mixin remote values, adding any that are not present locally
|
||||||
for _, l := range item.Remote {
|
for _, l := range item.GetRemoteList() {
|
||||||
orderedKeys.UpsertRemote(key, l)
|
orderedKeys.UpsertRemote(key, l)
|
||||||
}
|
}
|
||||||
// Mixin recorded values, adding any that are not present locally
|
// Mixin recorded values, adding any that are not present locally
|
||||||
// or remotely
|
// or remotely
|
||||||
for _, l := range item.Recorded {
|
for _, l := range item.GetRecordedList() {
|
||||||
orderedKeys.UpsertRecorded(key, l)
|
orderedKeys.UpsertRecorded(key, l)
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, l := range orderedKeys.Items {
|
for i, l := range orderedKeys.Items {
|
||||||
recordedSet := l.Recorded != nil
|
|
||||||
localSet := l.Local != nil
|
|
||||||
remoteSet := l.Remote != nil
|
|
||||||
|
|
||||||
var s openapi.Schema
|
var s openapi.Schema
|
||||||
if item.Array != nil && item.Array.SubType != nil {
|
if item.Array != nil && item.Array.SubType != nil {
|
||||||
s = item.Array.SubType
|
s = item.Array.SubType
|
||||||
}
|
}
|
||||||
subitem, err := v.getItem(s, fmt.Sprintf("%d", i),
|
subitem, err := v.getItem(s, fmt.Sprintf("%d", i), l.RawElementData)
|
||||||
l.RawElementData,
|
|
||||||
apply.HasElementData{recordedSet, localSet, remoteSet})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -166,30 +152,30 @@ func (v ElementBuildingVisitor) doMapList(meta apply.FieldMetaImpl, item *listIt
|
|||||||
// replaceListElement builds a new ListElement from a listItem
|
// replaceListElement builds a new ListElement from a listItem
|
||||||
// Uses the "replace" strategy and identify "same" elements across lists by their index
|
// 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) {
|
func (v ElementBuildingVisitor) replaceListElement(meta apply.FieldMetaImpl, item *listItem) (*apply.ListElement, error) {
|
||||||
result := &apply.ListElement{
|
meta.Name = item.Name
|
||||||
FieldMetaImpl: meta,
|
result := &apply.ListElement{meta, item.ListElementData, []apply.Element{}}
|
||||||
ListElementData: item.ListElementData,
|
|
||||||
HasElementData: item.HasElementData,
|
|
||||||
Values: []apply.Element{},
|
|
||||||
}
|
|
||||||
result.Name = item.Name
|
|
||||||
|
|
||||||
// Use the max length to iterate over the slices
|
// 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
|
// Lookup the item from each list
|
||||||
recorded, recordedSet := boundsSafeLookup(i, item.Recorded)
|
data := apply.RawElementData{}
|
||||||
local, localSet := boundsSafeLookup(i, item.Local)
|
if recorded, recordedSet := boundsSafeLookup(i, item.GetRecordedList()); recordedSet {
|
||||||
remote, remoteSet := boundsSafeLookup(i, item.Remote)
|
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
|
// Create the Item
|
||||||
var s openapi.Schema
|
var s openapi.Schema
|
||||||
if item.Array != nil && item.Array.SubType != nil {
|
if item.Array != nil && item.Array.SubType != nil {
|
||||||
s = item.Array.SubType
|
s = item.Array.SubType
|
||||||
}
|
}
|
||||||
subitem, err := v.getItem(s, fmt.Sprintf("%d", i),
|
subitem, err := v.getItem(s, fmt.Sprintf("%d", i), data)
|
||||||
apply.RawElementData{recorded, local, remote},
|
|
||||||
apply.HasElementData{recordedSet, localSet, remoteSet})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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
|
// 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the result
|
// Return the result
|
||||||
return &apply.MapElement{
|
return &apply.MapElement{meta, item.MapElementData, values}, nil
|
||||||
FieldMetaImpl: meta,
|
|
||||||
HasElementData: item.HasElementData,
|
|
||||||
MapElementData: item.MapElementData,
|
|
||||||
Values: values,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// schemaFn returns the schema for a field or map value based on its name or key
|
// 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(
|
func (v ElementBuildingVisitor) createMapValues(
|
||||||
schemaFn schemaFn,
|
schemaFn schemaFn,
|
||||||
meta apply.FieldMetaImpl,
|
meta apply.FieldMetaImpl,
|
||||||
hasData apply.HasElementData,
|
|
||||||
data apply.MapElementData) (map[string]apply.Element, error) {
|
data apply.MapElementData) (map[string]apply.Element, error) {
|
||||||
|
|
||||||
// Collate each key in the map
|
// Collate each key in the map
|
||||||
values := map[string]apply.Element{}
|
values := map[string]apply.Element{}
|
||||||
for _, key := range keysUnion(data.Recorded, data.Local, data.Remote) {
|
for _, key := range keysUnion(data.GetRecordedMap(), data.GetLocalMap(), data.GetRemoteMap()) {
|
||||||
recorded, recordedSet := nilSafeLookup(key, data.Recorded)
|
combined := apply.RawElementData{}
|
||||||
local, localSet := nilSafeLookup(key, data.Local)
|
if recorded, recordedSet := nilSafeLookup(key, data.GetRecordedMap()); recordedSet {
|
||||||
remote, remoteSet := nilSafeLookup(key, data.Remote)
|
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
|
// Create an item for the field
|
||||||
field, err := v.getItem(schemaFn(key), key,
|
field, err := v.getItem(schemaFn(key), key, combined)
|
||||||
apply.RawElementData{recorded, local, remote},
|
|
||||||
apply.HasElementData{recordedSet, localSet, remoteSet})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -20,11 +20,6 @@ import "k8s.io/kubernetes/pkg/kubectl/apply"
|
|||||||
|
|
||||||
// primitiveElement builds a new primitiveElement from a PrimitiveItem
|
// primitiveElement builds a new primitiveElement from a PrimitiveItem
|
||||||
func (v ElementBuildingVisitor) primitiveElement(item *primitiveItem) (*apply.PrimitiveElement, error) {
|
func (v ElementBuildingVisitor) primitiveElement(item *primitiveItem) (*apply.PrimitiveElement, error) {
|
||||||
result := &apply.PrimitiveElement{
|
meta := apply.FieldMetaImpl{Name: item.Name}
|
||||||
HasElementData: item.HasElementData,
|
return &apply.PrimitiveElement{meta, item.RawElementData}, nil
|
||||||
RawElementData: item.RawElementData,
|
|
||||||
}
|
|
||||||
result.Name = item.Name
|
|
||||||
|
|
||||||
return result, 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
|
// 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the result
|
// Return the result
|
||||||
return &apply.TypeElement{
|
return &apply.TypeElement{meta, item.MapElementData, values}, nil
|
||||||
FieldMetaImpl: meta,
|
|
||||||
HasElementData: item.HasElementData,
|
|
||||||
MapElementData: item.MapElementData,
|
|
||||||
Values: values,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
@ -95,22 +95,6 @@ func getType(args ...interface{}) (reflect.Type, error) {
|
|||||||
return reflect.TypeOf(last), nil
|
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
|
// getFieldMeta parses the metadata about the field from the openapi spec
|
||||||
func getFieldMeta(s openapi.Schema, name string) (apply.FieldMetaImpl, error) {
|
func getFieldMeta(s openapi.Schema, name string) (apply.FieldMetaImpl, error) {
|
||||||
m := apply.FieldMetaImpl{}
|
m := apply.FieldMetaImpl{}
|
||||||
|
@ -16,19 +16,12 @@ limitations under the License.
|
|||||||
|
|
||||||
package apply
|
package apply
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
// PrimitiveElement contains the recorded, local and remote values for a field
|
// PrimitiveElement contains the recorded, local and remote values for a field
|
||||||
// of type primitive
|
// of type primitive
|
||||||
type PrimitiveElement struct {
|
type PrimitiveElement struct {
|
||||||
// FieldMetaImpl contains metadata about the field from openapi
|
// FieldMetaImpl contains metadata about the field from openapi
|
||||||
FieldMetaImpl
|
FieldMetaImpl
|
||||||
|
|
||||||
// HasElementData contains whether the field was set
|
|
||||||
HasElementData
|
|
||||||
|
|
||||||
// RawElementData contains the values the field was set to
|
// RawElementData contains the values the field was set to
|
||||||
RawElementData
|
RawElementData
|
||||||
}
|
}
|
||||||
@ -38,9 +31,4 @@ func (e PrimitiveElement) Merge(v Strategy) (Result, error) {
|
|||||||
return v.MergePrimitive(e)
|
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{}
|
var _ Element = &PrimitiveElement{}
|
||||||
|
@ -20,32 +20,14 @@ import "k8s.io/kubernetes/pkg/kubectl/apply"
|
|||||||
|
|
||||||
// Options controls how a merge will be executed
|
// Options controls how a merge will be executed
|
||||||
type Options struct {
|
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.
|
// 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
|
// e.g. primitive values, list values with replace strategy, and map values with do
|
||||||
// strategy
|
// strategy
|
||||||
FailOnConflict bool
|
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
|
// Create returns a new apply.Visitor for merging multiple objects together
|
||||||
func Create(options Options) apply.Strategy {
|
func Create(options Options) apply.Strategy {
|
||||||
return createDelegatingStrategy(options)
|
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{}{}
|
merged := []interface{}{}
|
||||||
for _, value := range e.Values {
|
for _, value := range e.Values {
|
||||||
// Recursively merge the list element before adding the value to the list
|
// 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 {
|
if err != nil {
|
||||||
return apply.Result{}, err
|
return apply.Result{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch result.Operation {
|
fmt.Printf("\nResult %+v\n%+v\n", m.MergedResult, value)
|
||||||
|
switch m.Operation {
|
||||||
case apply.SET:
|
case apply.SET:
|
||||||
// Keep the list item value
|
// Keep the list item value
|
||||||
merged = append(merged, result.MergedResult)
|
merged = append(merged, m.MergedResult)
|
||||||
case apply.DROP:
|
case apply.DROP:
|
||||||
// Drop the list item value
|
// Drop the list item value
|
||||||
default:
|
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 contains metadata about the field from openapi
|
||||||
FieldMetaImpl
|
FieldMetaImpl
|
||||||
|
|
||||||
// HasElementData contains whether the field was set
|
|
||||||
HasElementData
|
|
||||||
|
|
||||||
// ListElementData contains the value a field was set to
|
|
||||||
MapElementData
|
MapElementData
|
||||||
|
|
||||||
// Values contains the combined recorded-local-remote value of each field in the type
|
// Values contains the combined recorded-local-remote value of each field in the type
|
||||||
|
Loading…
Reference in New Issue
Block a user