From f1c21c8fdf4a2a05c3f8444e6774e48c24ea9a63 Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Fri, 21 Nov 2014 22:49:50 -0800 Subject: [PATCH 1/2] add boilerplate reduction struct field copier --- pkg/conversion/converter.go | 170 ++++++++++++++++++++++++------- pkg/conversion/converter_test.go | 92 +++++++++++++++++ pkg/conversion/scheme.go | 8 ++ 3 files changed, 235 insertions(+), 35 deletions(-) diff --git a/pkg/conversion/converter.go b/pkg/conversion/converter.go index f66c866d804..920bf3e7afd 100644 --- a/pkg/conversion/converter.go +++ b/pkg/conversion/converter.go @@ -26,6 +26,11 @@ type typePair struct { dest reflect.Type } +type typeNamePair struct { + fieldType reflect.Type + fieldName string +} + // DebugLogger allows you to get debugging messages if necessary. type DebugLogger interface { Logf(format string, args ...interface{}) @@ -37,6 +42,15 @@ type Converter struct { // do the conversion. funcs map[typePair]reflect.Value + // This is a map from a source field type and name, to a list of destination + // field type and name. + structFieldDests map[typeNamePair][]typeNamePair + + // Allows for the opposite lookup of structFieldDests. So that SourceFromDest + // copy flag also works. So this is a map of destination field name, to potential + // source field name and type to look for. + structFieldSources map[typeNamePair][]typeNamePair + // If non-nil, will be called to print helpful debugging info. Quite verbose. Debug DebugLogger @@ -49,8 +63,10 @@ type Converter struct { // NewConverter creates a new Converter object. func NewConverter() *Converter { return &Converter{ - funcs: map[typePair]reflect.Value{}, - NameFunc: func(t reflect.Type) string { return t.Name() }, + funcs: map[typePair]reflect.Value{}, + NameFunc: func(t reflect.Type) string { return t.Name() }, + structFieldDests: map[typeNamePair][]typeNamePair{}, + structFieldSources: map[typeNamePair][]typeNamePair{}, } } @@ -177,6 +193,22 @@ func (c *Converter) Register(conversionFunc interface{}) error { return nil } +// SetStructFieldCopy registers a correspondence. Whenever a struct field is encountered +// which has a type and name matching srcFieldType and srcFieldName, it wil be copied +// into the field in the destination struct matching destFieldType & Name, if such a +// field exists. +// May be called multiple times, even for the same source field & type--all applicable +// copies will be performed. +func (c *Converter) SetStructFieldCopy(srcFieldType interface{}, srcFieldName string, destFieldType interface{}, destFieldName string) error { + st := reflect.TypeOf(srcFieldType) + dt := reflect.TypeOf(destFieldType) + srcKey := typeNamePair{st, srcFieldName} + destKey := typeNamePair{dt, destFieldName} + c.structFieldDests[srcKey] = append(c.structFieldDests[srcKey], destKey) + c.structFieldSources[destKey] = append(c.structFieldSources[destKey], srcKey) + return nil +} + // FieldMatchingFlags contains a list of ways in which struct fields could be // copied. These constants may be | combined. type FieldMatchingFlags int @@ -201,6 +233,10 @@ const ( // IsSet returns true if the given flag or combination of flags is set. func (f FieldMatchingFlags) IsSet(flag FieldMatchingFlags) bool { + if flag == DestFromSource { + // The bit logic doesn't work on the default value. + return f&SourceToDest != SourceToDest + } return f&flag == flag } @@ -274,39 +310,7 @@ func (c *Converter) convert(sv, dv reflect.Value, scope *scope) error { switch dv.Kind() { case reflect.Struct: - listType := dt - if scope.flags.IsSet(SourceToDest) { - listType = st - } - for i := 0; i < listType.NumField(); i++ { - f := listType.Field(i) - df := dv.FieldByName(f.Name) - sf := sv.FieldByName(f.Name) - if sf.IsValid() { - // No need to check error, since we know it's valid. - field, _ := st.FieldByName(f.Name) - scope.setSrcTag(field.Tag) - } - if df.IsValid() { - field, _ := dt.FieldByName(f.Name) - scope.setDestTag(field.Tag) - } - // TODO: set top level of scope.src/destTagStack with these field tags here. - if !df.IsValid() || !sf.IsValid() { - switch { - case scope.flags.IsSet(IgnoreMissingFields): - // No error. - case scope.flags.IsSet(SourceToDest): - return fmt.Errorf("%v not present in dest (%v to %v)", f.Name, st, dt) - default: - return fmt.Errorf("%v not present in src (%v to %v)", f.Name, st, dt) - } - continue - } - if err := c.convert(sf, df, scope); err != nil { - return err - } - } + return c.convertStruct(sv, dv, scope) case reflect.Slice: if sv.IsNil() { // Don't make a zero-length slice. @@ -350,3 +354,99 @@ func (c *Converter) convert(sv, dv reflect.Value, scope *scope) error { } return nil } + +func (c *Converter) convertStruct(sv, dv reflect.Value, scope *scope) error { + dt, st := dv.Type(), sv.Type() + + listType := dt + if scope.flags.IsSet(SourceToDest) { + listType = st + } + for i := 0; i < listType.NumField(); i++ { + f := listType.Field(i) + if found, err := c.checkStructField(f.Name, sv, dv, scope); found { + if err != nil { + return err + } + continue + } + df := dv.FieldByName(f.Name) + sf := sv.FieldByName(f.Name) + if sf.IsValid() { + // No need to check error, since we know it's valid. + field, _ := st.FieldByName(f.Name) + scope.setSrcTag(field.Tag) + } + if df.IsValid() { + field, _ := dt.FieldByName(f.Name) + scope.setDestTag(field.Tag) + } + // TODO: set top level of scope.src/destTagStack with these field tags here. + if !df.IsValid() || !sf.IsValid() { + switch { + case scope.flags.IsSet(IgnoreMissingFields): + // No error. + case scope.flags.IsSet(SourceToDest): + return fmt.Errorf("%v not present in dest (%v to %v)", f.Name, st, dt) + default: + return fmt.Errorf("%v not present in src (%v to %v)", f.Name, st, dt) + } + continue + } + if err := c.convert(sf, df, scope); err != nil { + return err + } + } + return nil +} + +// checkStructField returns true if the field name matches any of the struct +// field copying rules. The error should be ignored if it returns false. +func (c *Converter) checkStructField(fieldName string, sv, dv reflect.Value, scope *scope) (bool, error) { + replacementMade := false + if scope.flags.IsSet(DestFromSource) { + df := dv.FieldByName(fieldName) + if !df.IsValid() { + return false, nil + } + destKey := typeNamePair{df.Type(), fieldName} + // Check each of the potential source (type, name) pairs to see if they're + // present in sv. + for _, potentialSourceKey := range c.structFieldSources[destKey] { + sf := sv.FieldByName(potentialSourceKey.fieldName) + if !sf.IsValid() { + continue + } + if sf.Type() == potentialSourceKey.fieldType { + // Both the source's name and type matched, so copy. + if err := c.convert(sf, df, scope); err != nil { + return true, err + } + replacementMade = true + } + } + return replacementMade, nil + } + + sf := sv.FieldByName(fieldName) + if !sf.IsValid() { + return false, nil + } + srcKey := typeNamePair{sf.Type(), fieldName} + // Check each of the potential dest (type, name) pairs to see if they're + // present in dv. + for _, potentialDestKey := range c.structFieldDests[srcKey] { + df := dv.FieldByName(potentialDestKey.fieldName) + if !df.IsValid() { + continue + } + if df.Type() == potentialDestKey.fieldType { + // Both the dest's name and type matched, so copy. + if err := c.convert(sf, df, scope); err != nil { + return true, err + } + replacementMade = true + } + } + return replacementMade, nil +} diff --git a/pkg/conversion/converter_test.go b/pkg/conversion/converter_test.go index 573c9791ded..8fd45a66c31 100644 --- a/pkg/conversion/converter_test.go +++ b/pkg/conversion/converter_test.go @@ -290,3 +290,95 @@ func TestConverter_flags(t *testing.T) { } } } + +func TestConverter_FieldRename(t *testing.T) { + type WeirdMeta struct { + Name string + Type string + } + type NameMeta struct { + Name string + } + type TypeMeta struct { + Type string + } + type A struct { + WeirdMeta + } + type B struct { + TypeMeta + NameMeta + } + + c := NewConverter() + err := c.SetStructFieldCopy(WeirdMeta{}, "WeirdMeta", TypeMeta{}, "TypeMeta") + if err != nil { + t.Fatalf("unexpected error %v", err) + } + err = c.SetStructFieldCopy(WeirdMeta{}, "WeirdMeta", NameMeta{}, "NameMeta") + if err != nil { + t.Fatalf("unexpected error %v", err) + } + err = c.SetStructFieldCopy(TypeMeta{}, "TypeMeta", WeirdMeta{}, "WeirdMeta") + if err != nil { + t.Fatalf("unexpected error %v", err) + } + err = c.SetStructFieldCopy(NameMeta{}, "NameMeta", WeirdMeta{}, "WeirdMeta") + if err != nil { + t.Fatalf("unexpected error %v", err) + } + c.Debug = t + + aVal := &A{ + WeirdMeta: WeirdMeta{ + Name: "Foo", + Type: "Bar", + }, + } + + bVal := &B{ + TypeMeta: TypeMeta{"Bar"}, + NameMeta: NameMeta{"Foo"}, + } + + table := map[string]struct { + from, to, expect interface{} + flags FieldMatchingFlags + }{ + "to": { + aVal, + &B{}, + bVal, + AllowDifferentFieldTypeNames | SourceToDest | IgnoreMissingFields, + }, + "from": { + bVal, + &A{}, + aVal, + AllowDifferentFieldTypeNames | SourceToDest, + }, + "toDestFirst": { + aVal, + &B{}, + bVal, + AllowDifferentFieldTypeNames, + }, + "fromDestFirst": { + bVal, + &A{}, + aVal, + AllowDifferentFieldTypeNames | IgnoreMissingFields, + }, + } + + for name, item := range table { + err := c.Convert(item.from, item.to, item.flags, nil) + if err != nil { + t.Errorf("%v: unexpected error: %v", name, err) + continue + } + if e, a := item.expect, item.to; !reflect.DeepEqual(e, a) { + t.Errorf("%v: unexpected diff: %v", name, objDiff(e, a)) + } + } +} diff --git a/pkg/conversion/scheme.go b/pkg/conversion/scheme.go index f93ef42ca17..a42c83ed32e 100644 --- a/pkg/conversion/scheme.go +++ b/pkg/conversion/scheme.go @@ -193,6 +193,14 @@ func (s *Scheme) AddConversionFuncs(conversionFuncs ...interface{}) error { return nil } +// AddStructFieldConversion allows you to specify a mechanical copy for a moved +// or renamed struct field without writing an entire conversion function. See +// the comment in Converter.SetStructFieldCopy for parameter details. +// Call as many times as needed, even on the same fields. +func (s *Scheme) AddStructFieldConversion(srcFieldType interface{}, srcFieldName string, destFieldType interface{}, destFieldName string) error { + return s.converter.SetStructFieldCopy(srcFieldType, srcFieldName, destFieldType, destFieldName) +} + // Convert will attempt to convert in into out. Both must be pointers. For easy // testing of conversion functions. Returns an error if the conversion isn't // possible. You can call this with types that haven't been registered (for example, From 8d762c996a0f991f69899911dc571d4046be941c Mon Sep 17 00:00:00 2001 From: Daniel Smith Date: Fri, 21 Nov 2014 23:58:12 -0800 Subject: [PATCH 2/2] Remove boilerplate coversion functions --- pkg/api/v1beta1/conversion.go | 314 +------------------------------- pkg/api/v1beta2/conversion.go | 332 +--------------------------------- pkg/runtime/scheme.go | 8 + 3 files changed, 28 insertions(+), 626 deletions(-) diff --git a/pkg/api/v1beta1/conversion.go b/pkg/api/v1beta1/conversion.go index d25942c79c4..e2eba5271c2 100644 --- a/pkg/api/v1beta1/conversion.go +++ b/pkg/api/v1beta1/conversion.go @@ -25,6 +25,15 @@ import ( ) func init() { + // Our TypeMeta was split into two different structs. + newer.Scheme.AddStructFieldConversion(TypeMeta{}, "TypeMeta", newer.TypeMeta{}, "TypeMeta") + newer.Scheme.AddStructFieldConversion(TypeMeta{}, "TypeMeta", newer.ObjectMeta{}, "ObjectMeta") + newer.Scheme.AddStructFieldConversion(TypeMeta{}, "TypeMeta", newer.ListMeta{}, "ListMeta") + + newer.Scheme.AddStructFieldConversion(newer.TypeMeta{}, "TypeMeta", TypeMeta{}, "TypeMeta") + newer.Scheme.AddStructFieldConversion(newer.ObjectMeta{}, "ObjectMeta", TypeMeta{}, "TypeMeta") + newer.Scheme.AddStructFieldConversion(newer.ListMeta{}, "ListMeta", TypeMeta{}, "TypeMeta") + newer.Scheme.AddConversionFuncs( // TypeMeta must be split into two objects func(in *newer.TypeMeta, out *TypeMeta, s conversion.Scope) error { @@ -231,6 +240,7 @@ func init() { if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } + // TODO: Change this to use in.ObjectMeta.Labels. if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil { return err } @@ -388,7 +398,6 @@ func init() { }, func(in *newer.Service, out *Service, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err } @@ -435,62 +444,6 @@ func init() { return nil }, - func(in *newer.Binding, out *Binding, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { - return err - } - - out.PodID = in.PodID - out.Host = in.Host - - return nil - }, - func(in *Binding, out *newer.Binding, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { - return err - } - - out.PodID = in.PodID - out.Host = in.Host - - return nil - }, - - func(in *newer.Status, out *Status, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { - return err - } - - out.Code = in.Code - out.Message = in.Message - out.Reason = StatusReason(in.Reason) - out.Status = in.Status - return s.Convert(&in.Details, &out.Details, 0) - }, - func(in *Status, out *newer.Status, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { - return err - } - - out.Code = in.Code - out.Message = in.Message - out.Reason = newer.StatusReason(in.Reason) - out.Status = in.Status - return s.Convert(&in.Details, &out.Details, 0) - }, - func(in *newer.Minion, out *Minion, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err @@ -520,253 +473,6 @@ func init() { return s.Convert(&in.NodeResources.Capacity, &out.Spec.Capacity, 0) }, - func(in *newer.BoundPod, out *BoundPod, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { - return err - } - - return s.Convert(&in.Spec, &out.Spec, 0) - }, - func(in *BoundPod, out *newer.BoundPod, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { - return err - } - - return s.Convert(&in.Spec, &out.Spec, 0) - }, - - func(in *newer.BoundPods, out *BoundPods, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { - return err - } - out.Host = in.Host - return s.Convert(&in.Items, &out.Items, 0) - }, - func(in *BoundPods, out *newer.BoundPods, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { - return err - } - out.Host = in.Host - return s.Convert(&in.Items, &out.Items, 0) - }, - - func(in *newer.Endpoints, out *Endpoints, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { - return err - } - - return s.Convert(&in.Endpoints, &out.Endpoints, 0) - }, - func(in *Endpoints, out *newer.Endpoints, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { - return err - } - - return s.Convert(&in.Endpoints, &out.Endpoints, 0) - }, - - func(in *newer.ServerOp, out *ServerOp, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { - return err - } - return nil - }, - func(in *ServerOp, out *newer.ServerOp, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { - return err - } - return nil - }, - - func(in *newer.Event, out *Event, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { - return err - } - - out.Message = in.Message - out.Reason = in.Reason - out.Source = in.Source - out.Status = in.Status - out.Timestamp = in.Timestamp - return s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0) - }, - func(in *Event, out *newer.Event, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { - return err - } - - out.Message = in.Message - out.Reason = in.Reason - out.Source = in.Source - out.Status = in.Status - out.Timestamp = in.Timestamp - return s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0) - }, - - // Convert all the standard lists - func(in *newer.PodList, out *PodList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ListMeta, &out.TypeMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - func(in *PodList, out *newer.PodList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ListMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - - func(in *newer.ReplicationControllerList, out *ReplicationControllerList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ListMeta, &out.TypeMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - func(in *ReplicationControllerList, out *newer.ReplicationControllerList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ListMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - - func(in *newer.ServiceList, out *ServiceList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ListMeta, &out.TypeMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - func(in *ServiceList, out *newer.ServiceList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ListMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - - func(in *newer.EndpointsList, out *EndpointsList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ListMeta, &out.TypeMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - func(in *EndpointsList, out *newer.EndpointsList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ListMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - - func(in *newer.EventList, out *EventList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ListMeta, &out.TypeMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - func(in *EventList, out *newer.EventList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ListMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - - func(in *newer.ServerOpList, out *ServerOpList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ListMeta, &out.TypeMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - func(in *ServerOpList, out *newer.ServerOpList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ListMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - - func(in *newer.ContainerManifestList, out *ContainerManifestList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ListMeta, &out.TypeMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - func(in *ContainerManifestList, out *newer.ContainerManifestList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ListMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - // Object ID <-> Name // TODO: amend the conversion package to allow overriding specific fields. func(in *ObjectReference, out *newer.ObjectReference, s conversion.Scope) error { diff --git a/pkg/api/v1beta2/conversion.go b/pkg/api/v1beta2/conversion.go index e0fabcc9249..3db6cd02213 100644 --- a/pkg/api/v1beta2/conversion.go +++ b/pkg/api/v1beta2/conversion.go @@ -25,6 +25,15 @@ import ( ) func init() { + // Our TypeMeta was split into two different structs. + newer.Scheme.AddStructFieldConversion(TypeMeta{}, "TypeMeta", newer.TypeMeta{}, "TypeMeta") + newer.Scheme.AddStructFieldConversion(TypeMeta{}, "TypeMeta", newer.ObjectMeta{}, "ObjectMeta") + newer.Scheme.AddStructFieldConversion(TypeMeta{}, "TypeMeta", newer.ListMeta{}, "ListMeta") + + newer.Scheme.AddStructFieldConversion(newer.TypeMeta{}, "TypeMeta", TypeMeta{}, "TypeMeta") + newer.Scheme.AddStructFieldConversion(newer.ObjectMeta{}, "ObjectMeta", TypeMeta{}, "TypeMeta") + newer.Scheme.AddStructFieldConversion(newer.ListMeta{}, "ListMeta", TypeMeta{}, "TypeMeta") + newer.Scheme.AddConversionFuncs( // TypeMeta must be split into two objects func(in *newer.TypeMeta, out *TypeMeta, s conversion.Scope) error { @@ -135,6 +144,7 @@ func init() { if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { return err } + // TODO: Change this to use in.ObjectMeta.Labels. if err := s.Convert(&in.Labels, &out.Labels, 0); err != nil { return err } @@ -364,62 +374,6 @@ func init() { return nil }, - func(in *newer.Binding, out *Binding, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { - return err - } - - out.PodID = in.PodID - out.Host = in.Host - - return nil - }, - func(in *Binding, out *newer.Binding, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { - return err - } - - out.PodID = in.PodID - out.Host = in.Host - - return nil - }, - - func(in *newer.Status, out *Status, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { - return err - } - - out.Code = in.Code - out.Message = in.Message - out.Reason = StatusReason(in.Reason) - out.Status = in.Status - return s.Convert(&in.Details, &out.Details, 0) - }, - func(in *Status, out *newer.Status, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { - return err - } - - out.Code = in.Code - out.Message = in.Message - out.Reason = newer.StatusReason(in.Reason) - out.Status = in.Status - return s.Convert(&in.Details, &out.Details, 0) - }, - func(in *newer.Minion, out *Minion, s conversion.Scope) error { if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { return err @@ -449,272 +403,6 @@ func init() { return s.Convert(&in.NodeResources.Capacity, &out.Spec.Capacity, 0) }, - func(in *newer.BoundPod, out *BoundPod, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { - return err - } - - return s.Convert(&in.Spec, &out.Spec, 0) - }, - func(in *BoundPod, out *newer.BoundPod, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { - return err - } - - return s.Convert(&in.Spec, &out.Spec, 0) - }, - - func(in *newer.BoundPods, out *BoundPods, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { - return err - } - out.Host = in.Host - return s.Convert(&in.Items, &out.Items, 0) - }, - func(in *BoundPods, out *newer.BoundPods, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { - return err - } - out.Host = in.Host - return s.Convert(&in.Items, &out.Items, 0) - }, - - func(in *newer.Endpoints, out *Endpoints, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { - return err - } - - return s.Convert(&in.Endpoints, &out.Endpoints, 0) - }, - func(in *Endpoints, out *newer.Endpoints, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { - return err - } - - return s.Convert(&in.Endpoints, &out.Endpoints, 0) - }, - - func(in *newer.ServerOp, out *ServerOp, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { - return err - } - return nil - }, - func(in *ServerOp, out *newer.ServerOp, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { - return err - } - return nil - }, - - func(in *newer.Event, out *Event, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ObjectMeta, &out.TypeMeta, 0); err != nil { - return err - } - - out.Message = in.Message - out.Reason = in.Reason - out.Source = in.Source - out.Status = in.Status - out.Timestamp = in.Timestamp - return s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0) - }, - func(in *Event, out *newer.Event, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ObjectMeta, 0); err != nil { - return err - } - - out.Message = in.Message - out.Reason = in.Reason - out.Source = in.Source - out.Status = in.Status - out.Timestamp = in.Timestamp - return s.Convert(&in.InvolvedObject, &out.InvolvedObject, 0) - }, - - // Convert all the standard lists - func(in *newer.PodList, out *PodList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ListMeta, &out.TypeMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - func(in *PodList, out *newer.PodList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ListMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - - func(in *newer.ReplicationControllerList, out *ReplicationControllerList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ListMeta, &out.TypeMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - func(in *ReplicationControllerList, out *newer.ReplicationControllerList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ListMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - - func(in *newer.ServiceList, out *ServiceList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ListMeta, &out.TypeMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - func(in *ServiceList, out *newer.ServiceList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ListMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - - func(in *newer.EndpointsList, out *EndpointsList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ListMeta, &out.TypeMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - func(in *EndpointsList, out *newer.EndpointsList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ListMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - - func(in *newer.EventList, out *EventList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ListMeta, &out.TypeMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - func(in *EventList, out *newer.EventList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ListMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - - func(in *newer.MinionList, out *MinionList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ListMeta, &out.TypeMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - func(in *MinionList, out *newer.MinionList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ListMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - - func(in *newer.ServerOpList, out *ServerOpList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ListMeta, &out.TypeMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - func(in *ServerOpList, out *newer.ServerOpList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ListMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - - func(in *newer.ContainerManifestList, out *ContainerManifestList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.ListMeta, &out.TypeMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - func(in *ContainerManifestList, out *newer.ContainerManifestList, s conversion.Scope) error { - if err := s.Convert(&in.TypeMeta, &out.TypeMeta, 0); err != nil { - return err - } - if err := s.Convert(&in.TypeMeta, &out.ListMeta, 0); err != nil { - return err - } - return s.Convert(&in.Items, &out.Items, 0) - }, - // Object ID <-> Name // TODO: amend the conversion package to allow overriding specific fields. func(in *ObjectReference, out *newer.ObjectReference, s conversion.Scope) error { diff --git a/pkg/runtime/scheme.go b/pkg/runtime/scheme.go index 7e6f26e40ac..2f05401fb78 100644 --- a/pkg/runtime/scheme.go +++ b/pkg/runtime/scheme.go @@ -217,6 +217,14 @@ func (s *Scheme) AddConversionFuncs(conversionFuncs ...interface{}) error { return s.raw.AddConversionFuncs(conversionFuncs...) } +// AddStructFieldConversion allows you to specify a mechanical copy for a moved +// or renamed struct field without writing an entire conversion function. See +// the comment in conversion.Converter.SetStructFieldCopy for parameter details. +// Call as many times as needed, even on the same fields. +func (s *Scheme) AddStructFieldConversion(srcFieldType interface{}, srcFieldName string, destFieldType interface{}, destFieldName string) error { + return s.raw.AddStructFieldConversion(srcFieldType, srcFieldName, destFieldType, destFieldName) +} + // Convert will attempt to convert in into out. Both must be pointers. // For easy testing of conversion functions. Returns an error if the conversion isn't // possible.