From 774560085ebf9129a23eefa8c7d1a705db1aa4c0 Mon Sep 17 00:00:00 2001 From: "Dr. Stefan Schimanski" Date: Wed, 5 Jul 2017 17:56:00 +0200 Subject: [PATCH] bump(k8s.io/gengo): 712a17394a0980fabbcf3d968972e185d80c0fa4 --- Godeps/Godeps.json | 21 +- .../deepcopy-gen/generators/deepcopy.go | 329 ++++++++++++------ .../defaulter-gen/generators/defaulter.go | 51 ++- vendor/k8s.io/gengo/types/types.go | 15 + 4 files changed, 295 insertions(+), 121 deletions(-) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 89904f1a9b6..7d6b2a7721b 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -2231,7 +2231,6 @@ }, { "ImportPath": "github.com/pelletier/go-buffruneio", - "Comment": "v0.1.0", "Rev": "df1e16fde7fc330a0ca68167c23bf7ed6ac31d6d" }, { @@ -2985,43 +2984,43 @@ }, { "ImportPath": "k8s.io/gengo/args", - "Rev": "c79c13d131b0a8f42d05faa6491c12e94ccc6f30" + "Rev": "712a17394a0980fabbcf3d968972e185d80c0fa4" }, { "ImportPath": "k8s.io/gengo/examples/deepcopy-gen/generators", - "Rev": "c79c13d131b0a8f42d05faa6491c12e94ccc6f30" + "Rev": "712a17394a0980fabbcf3d968972e185d80c0fa4" }, { "ImportPath": "k8s.io/gengo/examples/defaulter-gen/generators", - "Rev": "c79c13d131b0a8f42d05faa6491c12e94ccc6f30" + "Rev": "712a17394a0980fabbcf3d968972e185d80c0fa4" }, { "ImportPath": "k8s.io/gengo/examples/import-boss/generators", - "Rev": "c79c13d131b0a8f42d05faa6491c12e94ccc6f30" + "Rev": "712a17394a0980fabbcf3d968972e185d80c0fa4" }, { "ImportPath": "k8s.io/gengo/examples/set-gen/generators", - "Rev": "c79c13d131b0a8f42d05faa6491c12e94ccc6f30" + "Rev": "712a17394a0980fabbcf3d968972e185d80c0fa4" }, { "ImportPath": "k8s.io/gengo/examples/set-gen/sets", - "Rev": "c79c13d131b0a8f42d05faa6491c12e94ccc6f30" + "Rev": "712a17394a0980fabbcf3d968972e185d80c0fa4" }, { "ImportPath": "k8s.io/gengo/generator", - "Rev": "c79c13d131b0a8f42d05faa6491c12e94ccc6f30" + "Rev": "712a17394a0980fabbcf3d968972e185d80c0fa4" }, { "ImportPath": "k8s.io/gengo/namer", - "Rev": "c79c13d131b0a8f42d05faa6491c12e94ccc6f30" + "Rev": "712a17394a0980fabbcf3d968972e185d80c0fa4" }, { "ImportPath": "k8s.io/gengo/parser", - "Rev": "c79c13d131b0a8f42d05faa6491c12e94ccc6f30" + "Rev": "712a17394a0980fabbcf3d968972e185d80c0fa4" }, { "ImportPath": "k8s.io/gengo/types", - "Rev": "c79c13d131b0a8f42d05faa6491c12e94ccc6f30" + "Rev": "712a17394a0980fabbcf3d968972e185d80c0fa4" }, { "ImportPath": "k8s.io/heapster/metrics/api/v1/types", diff --git a/vendor/k8s.io/gengo/examples/deepcopy-gen/generators/deepcopy.go b/vendor/k8s.io/gengo/examples/deepcopy-gen/generators/deepcopy.go index 68be1fc45bf..b1295f24785 100644 --- a/vendor/k8s.io/gengo/examples/deepcopy-gen/generators/deepcopy.go +++ b/vendor/k8s.io/gengo/examples/deepcopy-gen/generators/deepcopy.go @@ -20,6 +20,7 @@ import ( "fmt" "io" "path/filepath" + "sort" "strings" "k8s.io/gengo/args" @@ -38,7 +39,11 @@ type CustomArgs struct { } // This is the comment tag that carries parameters for deep-copy generation. -const tagName = "k8s:deepcopy-gen" +const ( + tagName = "k8s:deepcopy-gen" + interfacesTagName = tagName + ":interfaces" + interfacesNonPointerTagName = tagName + ":nonpointer-interfaces" // attach the DeepCopy methods to the +) // Known values for the comment tag. const tagValuePackage = "package" @@ -217,11 +222,6 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat return packages } -const ( - conversionPackagePath = "k8s.io/apimachinery/pkg/conversion" - runtimePackagePath = "k8s.io/apimachinery/pkg/runtime" -) - // genDeepCopy produces a file with autogenerated deep-copy functions. type genDeepCopy struct { generator.DefaultGen @@ -251,11 +251,6 @@ func (g *genDeepCopy) Namers(c *generator.Context) namer.NameSystems { // Have the raw namer for this file track what it imports. return namer.NameSystems{ "raw": namer.NewRawNamer(g.targetPackage, g.imports), - "dcFnName": &dcFnNamer{ - public: deepCopyNamer(), - tracker: g.imports, - myPackage: g.targetPackage, - }, } } @@ -297,7 +292,7 @@ func (g *genDeepCopy) copyableAndInBounds(t *types.Type) bool { // for a type T is: // func (t T) DeepCopy() T // or: -// func (t *T) DeepCopyt() T +// func (t *T) DeepCopy() T func hasDeepCopyMethod(t *types.Type) bool { for mn, mt := range t.Methods { if mn != "DeepCopy" { @@ -363,47 +358,47 @@ func (g *genDeepCopy) Imports(c *generator.Context) (imports []string) { return importLines } -func argsFromType(t *types.Type) generator.Args { - return generator.Args{ - "type": t, +func argsFromType(ts ...*types.Type) generator.Args { + a := generator.Args{ + "type": ts[0], } -} - -type dcFnNamer struct { - public namer.Namer - tracker namer.ImportTracker - myPackage string -} - -func (n *dcFnNamer) Name(t *types.Type) string { - pubName := n.public.Name(t) - n.tracker.AddType(t) - if t.Name.Package == n.myPackage { - return "DeepCopy_" + pubName + for i, t := range ts { + a[fmt.Sprintf("type%d", i+1)] = t } - return fmt.Sprintf("%s.DeepCopy_%s", n.tracker.LocalNameOf(t.Name.Package), pubName) + return a } func (g *genDeepCopy) Init(c *generator.Context, w io.Writer) error { + glog.V(5).Infof("Registering types in pkg %q", g.targetPackage) + + // the legacy restration will go away when the cloner is removed from Kubernetes, replaced + // with static function calls to the DeepCopy methods. + return g.legacyRegistration(c, w) +} + +func (g *genDeepCopy) legacyRegistration(c *generator.Context, w io.Writer) error { + conversionPackagePath := "k8s.io/apimachinery/pkg/conversion" + runtimePackagePath := "k8s.io/apimachinery/pkg/runtime" + cloner := c.Universe.Type(types.Name{Package: conversionPackagePath, Name: "Cloner"}) g.imports.AddType(cloner) if !g.registerTypes { sw := generator.NewSnippetWriter(w, c, "$", "$") - sw.Do("// GetGeneratedDeepCopyFuncs returns the generated funcs, since we aren't registering them.\n", nil) + sw.Do("// Deprecated: GetGeneratedDeepCopyFuncs returns the generated funcs, since we aren't registering them.\n", nil) sw.Do("func GetGeneratedDeepCopyFuncs() []conversion.GeneratedDeepCopyFunc{\n", nil) sw.Do("return []conversion.GeneratedDeepCopyFunc{\n", nil) for _, t := range g.typesForInit { args := argsFromType(t). With("typeof", c.Universe.Package("reflect").Function("TypeOf")) - sw.Do("{Fn: $.type|dcFnName$, InType: $.typeof|raw$(&$.type|raw${})},\n", args) + sw.Do("{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {in.(*$.type|raw$).DeepCopyInto(out.(*$.type|raw$)); return nil}, InType: $.typeof|raw$(&$.type|raw${})},\n", args) } sw.Do("}\n", nil) sw.Do("}\n\n", nil) return sw.Error() } - glog.V(5).Infof("Registering types in pkg %q", g.targetPackage) sw := generator.NewSnippetWriter(w, c, "$", "$") + sw.Do("// Deprecated: register deep-copy functions.\n", nil) sw.Do("func init() {\n", nil) sw.Do("SchemeBuilder.Register(RegisterDeepCopies)\n", nil) sw.Do("}\n\n", nil) @@ -413,14 +408,14 @@ func (g *genDeepCopy) Init(c *generator.Context, w io.Writer) error { Kind: types.Pointer, Elem: scheme, } - sw.Do("// RegisterDeepCopies adds deep-copy functions to the given scheme. Public\n", nil) + sw.Do("// Deprecated: RegisterDeepCopies adds deep-copy functions to the given scheme. Public\n", nil) sw.Do("// to allow building arbitrary schemes.\n", nil) sw.Do("func RegisterDeepCopies(scheme $.|raw$) error {\n", schemePtr) sw.Do("return scheme.AddGeneratedDeepCopyFuncs(\n", nil) for _, t := range g.typesForInit { args := argsFromType(t). With("typeof", c.Universe.Package("reflect").Function("TypeOf")) - sw.Do("conversion.GeneratedDeepCopyFunc{Fn: $.type|dcFnName$, InType: $.typeof|raw$(&$.type|raw${})},\n", args) + sw.Do("conversion.GeneratedDeepCopyFunc{Fn: func(in interface{}, out interface{}, c *conversion.Cloner) error {in.(*$.type|raw$).DeepCopyInto(out.(*$.type|raw$)); return nil}, InType: $.typeof|raw$(&$.type|raw${})},\n", args) } sw.Do(")\n", nil) sw.Do("}\n\n", nil) @@ -449,6 +444,97 @@ func (g *genDeepCopy) needsGeneration(t *types.Type) bool { return true } +func extractInterfacesTag(comments []string) []string { + var result []string + values := types.ExtractCommentTags("+", comments)[interfacesTagName] + for _, v := range values { + if len(v) == 0 { + continue + } + intfs := strings.Split(v, ",") + for _, intf := range intfs { + if intf == "" { + continue + } + result = append(result, intf) + } + } + return result +} + +func extractNonPointerInterfaces(comments []string) (bool, error) { + values := types.ExtractCommentTags("+", comments)[interfacesNonPointerTagName] + if len(values) == 0 { + return false, nil + } + result := values[0] == "true" + for _, v := range values { + if v == "true" != result { + return false, fmt.Errorf("contradicting %v value %q found to previous value %v", interfacesNonPointerTagName, v, result) + } + } + return result, nil +} + +func (g *genDeepCopy) deepCopyableInterfaces(c *generator.Context, t *types.Type) ([]*types.Type, error) { + if t.Kind != types.Struct { + return nil, nil + } + + intfs := extractInterfacesTag(append(t.SecondClosestCommentLines, t.CommentLines...)) + + var ts []*types.Type + for _, intf := range intfs { + t := types.ParseFullyQualifiedName(intf) + c.AddDir(t.Package) + intfT := c.Universe.Type(t) + if intfT == nil { + return nil, fmt.Errorf("unknown type %q in %s tag of type %s", intf, interfacesTagName, intfT) + } + if intfT.Kind != types.Interface { + return nil, fmt.Errorf("type %q in %s tag of type %s is not an interface, but: %q", intf, interfacesTagName, t, intfT.Kind) + } + g.imports.AddType(intfT) + ts = append(ts, intfT) + } + + return ts, nil +} + +// DeepCopyableInterfaces returns the interface types to implement and whether they apply to a non-pointer receiver. +func (g *genDeepCopy) DeepCopyableInterfaces(c *generator.Context, t *types.Type) ([]*types.Type, bool, error) { + ts, err := g.deepCopyableInterfaces(c, t) + if err != nil { + return nil, false, err + } + + set := map[string]*types.Type{} + for _, t := range ts { + set[t.String()] = t + } + + result := []*types.Type{} + for _, t := range set { + result = append(result, t) + } + + TypeSlice(result).Sort() // we need a stable sorting because it determines the order in generation + + nonPointerReceiver, err := extractNonPointerInterfaces(append(t.SecondClosestCommentLines, t.CommentLines...)) + if err != nil { + return nil, false, err + } + + return result, nonPointerReceiver, nil +} + +type TypeSlice []*types.Type + +func (s TypeSlice) Len() int { return len(s) } +func (s TypeSlice) Less(i, j int) bool { return s[i].String() < s[j].String() } +func (s TypeSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s TypeSlice) Sort() { sort.Sort(s) } + func (g *genDeepCopy) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { if !g.needsGeneration(t) { return nil @@ -456,14 +542,58 @@ func (g *genDeepCopy) GenerateType(c *generator.Context, t *types.Type, w io.Wri glog.V(5).Infof("Generating deepcopy function for type %v", t) sw := generator.NewSnippetWriter(w, c, "$", "$") - args := argsFromType(t). - With("clonerType", types.Ref(conversionPackagePath, "Cloner")) - sw.Do("// $.type|dcFnName$ is an autogenerated deepcopy function.\n", args) - sw.Do("func $.type|dcFnName$(in interface{}, out interface{}, c *$.clonerType|raw$) error {{\n", args) - sw.Do("in := in.(*$.type|raw$)\nout := out.(*$.type|raw$)\n", argsFromType(t)) - g.generateFor(t, sw) - sw.Do("return nil\n", nil) - sw.Do("}}\n\n", nil) + args := argsFromType(t) + + _, foundDeepCopyInto := t.Methods["DeepCopyInto"] + _, foundDeepCopy := t.Methods["DeepCopy"] + if !foundDeepCopyInto { + sw.Do("// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\n", args) + sw.Do("func (in *$.type|raw$) DeepCopyInto(out *$.type|raw$) {\n", args) + if foundDeepCopy { + if t.Methods["DeepCopy"].Signature.Receiver.Kind == types.Pointer { + sw.Do("clone := in.DeepCopy()\n", nil) + sw.Do("*out = *clone\n", nil) + } else { + sw.Do("*out = in.DeepCopy()\n", nil) + } + sw.Do("return\n", nil) + } else { + g.generateFor(t, sw) + sw.Do("return\n", nil) + } + sw.Do("}\n\n", nil) + } + + if !foundDeepCopy { + sw.Do("// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, creating a new $.type|raw$.\n", args) + sw.Do("func (x *$.type|raw$) DeepCopy() *$.type|raw$ {\n", args) + sw.Do("if x == nil { return nil }\n", nil) + sw.Do("out := new($.type|raw$)\n", args) + sw.Do("x.DeepCopyInto(out)\n", nil) + sw.Do("return out\n", nil) + sw.Do("}\n\n", nil) + } + + intfs, nonPointerReceiver, err := g.DeepCopyableInterfaces(c, t) + if err != nil { + return err + } + for _, intf := range intfs { + sw.Do(fmt.Sprintf("// DeepCopy%s is an autogenerated deepcopy function, copying the receiver, creating a new $.type2|raw$.\n", intf.Name.Name), argsFromType(t, intf)) + if nonPointerReceiver { + sw.Do(fmt.Sprintf("func (x $.type|raw$) DeepCopy%s() $.type2|raw$ {\n", intf.Name.Name), argsFromType(t, intf)) + sw.Do("return *x.DeepCopy()", nil) + sw.Do("}\n\n", nil) + } else { + sw.Do(fmt.Sprintf("func (x *$.type|raw$) DeepCopy%s() $.type2|raw$ {\n", intf.Name.Name), argsFromType(t, intf)) + sw.Do("if c := x.DeepCopy(); c != nil {\n", nil) + sw.Do("return c\n", nil) + sw.Do("} else {\n", nil) + sw.Do("return nil\n", nil) + sw.Do("}}\n\n", nil) + } + } + return sw.Error() } @@ -498,7 +628,7 @@ func (g *genDeepCopy) doBuiltin(t *types.Type, sw *generator.SnippetWriter) { } func (g *genDeepCopy) doMap(t *types.Type, sw *generator.SnippetWriter) { - sw.Do("*out = make($.|raw$)\n", t) + sw.Do("*out = make($.|raw$, len(*in))\n", t) if t.Key.IsAssignable() { switch { case hasDeepCopyMethod(t.Elem): @@ -513,20 +643,32 @@ func (g *genDeepCopy) doMap(t *types.Type, sw *generator.SnippetWriter) { sw.Do("for key, val := range *in {\n", nil) sw.Do("(*out)[key] = val\n", nil) sw.Do("}\n", nil) + case t.Elem.Kind == types.Interface: + sw.Do("for key, val := range *in {\n", nil) + sw.Do("if val == nil {(*out)[key]=nil} else {\n", nil) + sw.Do(fmt.Sprintf("(*out)[key] = val.DeepCopy%s()\n", t.Elem.Name.Name), t) + sw.Do("}}\n", nil) default: sw.Do("for key, val := range *in {\n", nil) if g.copyableAndInBounds(t.Elem) { sw.Do("newVal := new($.|raw$)\n", t.Elem) - sw.Do("if err := $.type|dcFnName$(&val, newVal, c); err != nil {\n", argsFromType(t.Elem)) - sw.Do("return err\n", nil) - sw.Do("}\n", nil) + sw.Do("val.DeepCopyInto(newVal)\n", nil) sw.Do("(*out)[key] = *newVal\n", nil) - } else { - sw.Do("if newVal, err := c.DeepCopy(&val); err != nil {\n", nil) - sw.Do("return err\n", nil) - sw.Do("} else {\n", nil) - sw.Do("(*out)[key] = *newVal.(*$.|raw$)\n", t.Elem) + } else if t.Elem.Kind == types.Slice && t.Elem.Elem.Kind == types.Builtin { + sw.Do("if val==nil { (*out)[key]=nil } else {\n", nil) + sw.Do("(*out)[key] = make($.|raw$, len(val))\n", t.Elem) + sw.Do("copy((*out)[key], val)\n", nil) sw.Do("}\n", nil) + } else if t.Elem.Kind == types.Alias && t.Elem.Underlying.Kind == types.Slice && t.Elem.Underlying.Elem.Kind == types.Builtin { + sw.Do("(*out)[key] = make($.|raw$, len(val))\n", t.Elem) + sw.Do("copy((*out)[key], val)\n", nil) + } else if t.Elem.Kind == types.Pointer { + sw.Do("if val==nil { (*out)[key]=nil } else {\n", nil) + sw.Do("(*out)[key] = new($.Elem|raw$)\n", t.Elem) + sw.Do("val.DeepCopyInto((*out)[key])\n", nil) + sw.Do("}\n", nil) + } else { + sw.Do("(*out)[key] = *val.DeepCopy()\n", t.Elem) } sw.Do("}\n", nil) } @@ -558,16 +700,24 @@ func (g *genDeepCopy) doSlice(t *types.Type, sw *generator.SnippetWriter) { sw.Do("in, out := &(*in)[i], &(*out)[i]\n", nil) g.generateFor(t.Elem, sw) sw.Do("}\n", nil) - } else if g.copyableAndInBounds(t.Elem) { - sw.Do("if err := $.type|dcFnName$(&(*in)[i], &(*out)[i], c); err != nil {\n", argsFromType(t.Elem)) - sw.Do("return err\n", nil) + } else if hasDeepCopyMethod(t.Elem) { + sw.Do("(*out)[i] = (*in)[i].DeepCopy()\n", nil) + // REVISIT(sttts): the following is removed in master + //} else if t.Elem.IsAssignable() { + // sw.Do("(*out)[i] = (*in)[i]\n", nil) + } else if t.Elem.Kind == types.Interface { + sw.Do("if (*in)[i] == nil {(*out)[i]=nil} else {\n", nil) + sw.Do(fmt.Sprintf("(*out)[i] = (*in)[i].DeepCopy%s()\n", t.Elem.Name.Name), t) sw.Do("}\n", nil) + } else if t.Elem.Kind == types.Pointer { + sw.Do("if (*in)[i]==nil { (*out)[i]=nil } else {\n", nil) + sw.Do("(*out)[i] = new($.Elem|raw$)\n", t.Elem) + sw.Do("(*in)[i].DeepCopyInto((*out)[i])\n", nil) + sw.Do("}\n", nil) + } else if t.Elem.Kind == types.Struct { + sw.Do("(*in)[i].DeepCopyInto(&(*out)[i])\n", nil) } else { - sw.Do("if newVal, err := c.DeepCopy(&(*in)[i]); err != nil {\n", nil) - sw.Do("return err\n", nil) - sw.Do("} else {\n", nil) - sw.Do("(*out)[i] = *newVal.(*$.|raw$)\n", t.Elem) - sw.Do("}\n", nil) + sw.Do("(*out)[i] = (*in)[i].DeepCopy()\n", nil) } sw.Do("}\n", nil) } @@ -601,6 +751,7 @@ func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) { if hasMethod { sw.Do("out.$.name$ = in.$.name$.DeepCopy()\n", args) } + // the initial *out = *in was enough case types.Map, types.Slice, types.Pointer: if hasMethod { sw.Do("if in.$.name$ != nil {\n", args) @@ -617,39 +768,16 @@ func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) { if hasMethod { sw.Do("out.$.name$ = in.$.name$.DeepCopy()\n", args) } else if t.IsAssignable() { - // Nothing else needed. - } else if g.copyableAndInBounds(t) { - // Not assignable but should have a deepcopy function. - // TODO: do a topological sort of packages and ensure that this works, else inline it. - sw.Do("if err := $.type|dcFnName$(&in.$.name$, &out.$.name$, c); err != nil {\n", args) - sw.Do("return err\n", nil) - sw.Do("}\n", nil) + sw.Do("out.$.name$ = in.$.name$\n", args) } else { - // Fall back on the slow-path and hope it works. - // TODO: don't depend on kubernetes code for this - sw.Do("if newVal, err := c.DeepCopy(&in.$.name$); err != nil {\n", args) - sw.Do("return err\n", nil) - sw.Do("} else {\n", nil) - sw.Do("out.$.name$ = *newVal.(*$.type|raw$)\n", args) - sw.Do("}\n", nil) + sw.Do("in.$.name$.DeepCopyInto(&out.$.name$)\n", args) } + case types.Interface: + sw.Do("if in.$.name$ == nil {out.$.name$=nil} else {\n", args) + sw.Do(fmt.Sprintf("out.$.name$ = in.$.name$.DeepCopy%s()\n", t.Name.Name), args) + sw.Do("}\n", nil) default: - // Interfaces, Arrays, and other Kinds we don't understand. - sw.Do("// in.$.name$ is kind '$.kind$'\n", args) - if hasMethod { - sw.Do("if in.$.name$ != nil {\n", args) - sw.Do("out.$.name$ = in.$.name$.DeepCopy()\n", args) - sw.Do("}\n", args) - } else { - // TODO: don't depend on kubernetes code for this - sw.Do("if in.$.name$ != nil {\n", args) - sw.Do("if newVal, err := c.DeepCopy(&in.$.name$); err != nil {\n", args) - sw.Do("return err\n", nil) - sw.Do("} else {\n", nil) - sw.Do("out.$.name$ = *newVal.(*$.type|raw$)\n", args) - sw.Do("}\n", nil) - sw.Do("}\n", nil) - } + sw.Do("out.$.name$ = in.$.name$.DeepCopy()\n", args) } } } @@ -660,24 +788,27 @@ func (g *genDeepCopy) doInterface(t *types.Type, sw *generator.SnippetWriter) { } func (g *genDeepCopy) doPointer(t *types.Type, sw *generator.SnippetWriter) { + sw.Do("if *in == nil { *out = nil } else {\n", t) if hasDeepCopyMethod(t.Elem) { sw.Do("*out = new($.Elem|raw$)\n", t) sw.Do("**out = (*in).DeepCopy()\n", nil) } else if t.Elem.IsAssignable() { sw.Do("*out = new($.Elem|raw$)\n", t) sw.Do("**out = **in", nil) - } else if g.copyableAndInBounds(t.Elem) { - sw.Do("*out = new($.Elem|raw$)\n", t) - sw.Do("if err := $.type|dcFnName$(*in, *out, c); err != nil {\n", argsFromType(t.Elem)) - sw.Do("return err\n", nil) - sw.Do("}\n", nil) } else { - sw.Do("if newVal, err := c.DeepCopy(*in); err != nil {\n", nil) - sw.Do("return err\n", nil) - sw.Do("} else {\n", nil) - sw.Do("*out = newVal.(*$.|raw$)\n", t.Elem) - sw.Do("}\n", nil) + switch t.Elem.Kind { + case types.Map, types.Slice: + sw.Do("*out = new($.Elem|raw$)\n", t) + sw.Do("if **in != nil {\n", t) + sw.Do("in, out := *in, *out\n", nil) + g.generateFor(t.Elem, sw) + sw.Do("}\n", nil) + default: + sw.Do("*out = new($.Elem|raw$)\n", t) + sw.Do("(*in).DeepCopyInto(*out)\n", nil) + } } + sw.Do("}", t) } func (g *genDeepCopy) doAlias(t *types.Type, sw *generator.SnippetWriter) { diff --git a/vendor/k8s.io/gengo/examples/defaulter-gen/generators/defaulter.go b/vendor/k8s.io/gengo/examples/defaulter-gen/generators/defaulter.go index 02241828457..da6268639ef 100644 --- a/vendor/k8s.io/gengo/examples/defaulter-gen/generators/defaulter.go +++ b/vendor/k8s.io/gengo/examples/defaulter-gen/generators/defaulter.go @@ -320,7 +320,7 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat if d.object != nil { continue } - if buildCallTreeForType(t, true, existingDefaulters, newDefaulters) != nil { + if newCallTreeForType(existingDefaulters, newDefaulters).build(t, true) != nil { args := defaultingArgsFromType(t) sw.Do("$.inType|objectdefaultfn$", args) newDefaulters[t] = defaults{ @@ -387,7 +387,22 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat return packages } -// buildCallTreeForType creates a tree of paths to fields (based on how they would be accessed in Go - pointer, elem, +// callTreeForType contains fields necessary to build a tree for types. +type callTreeForType struct { + existingDefaulters defaulterFuncMap + newDefaulters defaulterFuncMap + currentlyBuildingTypes map[*types.Type]bool +} + +func newCallTreeForType(existingDefaulters, newDefaulters defaulterFuncMap) *callTreeForType { + return &callTreeForType{ + existingDefaulters: existingDefaulters, + newDefaulters: newDefaulters, + currentlyBuildingTypes: make(map[*types.Type]bool), + } +} + +// build creates a tree of paths to fields (based on how they would be accessed in Go - pointer, elem, // slice, or key) and the functions that should be invoked on each field. An in-order traversal of the resulting tree // can be used to generate a Go function that invokes each nested function on the appropriate type. The return // value may be nil if there are no functions to call on type or the type is a primitive (Defaulters can only be @@ -396,7 +411,7 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat // that could be or will be generated. If newDefaulters has an entry for a type, but the 'object' field is nil, // this function skips adding that defaulter - this allows us to avoid generating object defaulter functions for // list types that call empty defaulters. -func buildCallTreeForType(t *types.Type, root bool, existingDefaulters, newDefaulters defaulterFuncMap) *callNode { +func (c *callTreeForType) build(t *types.Type, root bool) *callNode { parent := &callNode{} if root { @@ -404,8 +419,8 @@ func buildCallTreeForType(t *types.Type, root bool, existingDefaulters, newDefau parent.elem = true } - defaults, _ := existingDefaulters[t] - newDefaults, generated := newDefaulters[t] + defaults, _ := c.existingDefaulters[t] + newDefaults, generated := c.newDefaulters[t] switch { case !root && generated && newDefaults.object != nil: parent.call = append(parent.call, newDefaults.object) @@ -432,19 +447,33 @@ func buildCallTreeForType(t *types.Type, root bool, existingDefaulters, newDefau // base has been added already, now add any additional defaulters defined for this object parent.call = append(parent.call, defaults.additional...) + // if the type already exists, don't build the tree for it and don't generate anything. + // This is used to avoid recursion for nested recursive types. + if c.currentlyBuildingTypes[t] { + return nil + } + // if type doesn't exist, mark it as existing + c.currentlyBuildingTypes[t] = true + + defer func() { + // The type will now acts as a parent, not a nested recursive type. + // We can now build the tree for it safely. + c.currentlyBuildingTypes[t] = false + }() + switch t.Kind { case types.Pointer: - if child := buildCallTreeForType(t.Elem, false, existingDefaulters, newDefaulters); child != nil { + if child := c.build(t.Elem, false); child != nil { child.elem = true parent.children = append(parent.children, *child) } case types.Slice, types.Array: - if child := buildCallTreeForType(t.Elem, false, existingDefaulters, newDefaulters); child != nil { + if child := c.build(t.Elem, false); child != nil { child.index = true parent.children = append(parent.children, *child) } case types.Map: - if child := buildCallTreeForType(t.Elem, false, existingDefaulters, newDefaulters); child != nil { + if child := c.build(t.Elem, false); child != nil { child.key = true parent.children = append(parent.children, *child) } @@ -458,13 +487,13 @@ func buildCallTreeForType(t *types.Type, root bool, existingDefaulters, newDefau name = field.Type.Name.Name } } - if child := buildCallTreeForType(field.Type, false, existingDefaulters, newDefaulters); child != nil { + if child := c.build(field.Type, false); child != nil { child.field = name parent.children = append(parent.children, *child) } } case types.Alias: - if child := buildCallTreeForType(t.Underlying, false, existingDefaulters, newDefaulters); child != nil { + if child := c.build(t.Underlying, false); child != nil { parent.children = append(parent.children, *child) } } @@ -571,7 +600,7 @@ func (g *genDefaulter) GenerateType(c *generator.Context, t *types.Type, w io.Wr glog.V(5).Infof("generating for type %v", t) - callTree := buildCallTreeForType(t, true, g.existingDefaulters, g.newDefaulters) + callTree := newCallTreeForType(g.existingDefaulters, g.newDefaulters).build(t, true) if callTree == nil { glog.V(5).Infof(" no defaulters defined") return nil diff --git a/vendor/k8s.io/gengo/types/types.go b/vendor/k8s.io/gengo/types/types.go index 12cfdd132d5..aa3b7128e94 100644 --- a/vendor/k8s.io/gengo/types/types.go +++ b/vendor/k8s.io/gengo/types/types.go @@ -16,6 +16,8 @@ limitations under the License. package types +import "strings" + // Ref makes a reference to the given type. It can only be used for e.g. // passing to namers. func Ref(packageName, typeName string) *Type { @@ -44,6 +46,19 @@ func (n Name) String() string { return n.Package + "." + n.Name } +// ParseFullyQualifiedName parses a name like k8s.io/kubernetes/pkg/api.Pod into a Name. +func ParseFullyQualifiedName(fqn string) Name { + cs := strings.Split(fqn, ".") + pkg := "" + if len(cs) > 1 { + pkg = strings.Join(cs[0:len(cs) - 1], ".") + } + return Name{ + Name: cs[len(cs) - 1], + Package: pkg, + } +} + // The possible classes of types. type Kind string