From 74d005f1cfeaf34bf4d18600256425fbf3032376 Mon Sep 17 00:00:00 2001 From: Wojciech Tyczynski Date: Thu, 4 Feb 2016 11:46:03 +0100 Subject: [PATCH] Generate DeepCopies per directory. --- cmd/libs/go2idl/args/args.go | 3 + .../deepcopy-gen/generators/deepcopy.go | 150 +++++++++--------- 2 files changed, 80 insertions(+), 73 deletions(-) diff --git a/cmd/libs/go2idl/args/args.go b/cmd/libs/go2idl/args/args.go index 4e6db325d5a..9ca3497a496 100644 --- a/cmd/libs/go2idl/args/args.go +++ b/cmd/libs/go2idl/args/args.go @@ -93,6 +93,9 @@ func (g *GeneratorArgs) LoadGoBoilerplate() ([]byte, error) { // directories. func (g *GeneratorArgs) NewBuilder() (*parser.Builder, error) { b := parser.New() + // Ignore all auto-generated files. + b.AddBuildTags("ignore_autogenerated") + for _, d := range g.InputDirs { if g.Recursive { if err := b.AddDirRecursive(d); err != nil { diff --git a/cmd/libs/go2idl/deepcopy-gen/generators/deepcopy.go b/cmd/libs/go2idl/deepcopy-gen/generators/deepcopy.go index 1062c57776c..69d16996dc4 100644 --- a/cmd/libs/go2idl/deepcopy-gen/generators/deepcopy.go +++ b/cmd/libs/go2idl/deepcopy-gen/generators/deepcopy.go @@ -26,6 +26,7 @@ import ( "k8s.io/kubernetes/cmd/libs/go2idl/generator" "k8s.io/kubernetes/cmd/libs/go2idl/namer" "k8s.io/kubernetes/cmd/libs/go2idl/types" + "k8s.io/kubernetes/pkg/util/sets" "github.com/golang/glog" ) @@ -55,48 +56,52 @@ func DefaultNameSystem() string { return "public" } -func Packages(_ *generator.Context, arguments *args.GeneratorArgs) generator.Packages { +func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages { boilerplate, err := arguments.LoadGoBoilerplate() if err != nil { glog.Fatalf("Failed loading boilerplate: %v", err) } + inputs := sets.NewString(arguments.InputDirs...) packages := generator.Packages{} - for _, inputDir := range arguments.InputDirs { - packages = append(packages, - &generator.DefaultPackage{ - PackageName: filepath.Base(inputDir), - PackagePath: inputDir, - HeaderText: append(boilerplate, []byte( - ` + header := append([]byte( + ` +// +build !ignore_autogenerated + +`), boilerplate...) + header = append(header, []byte( + ` // This file was autogenerated by deepcopy-gen. Do not edit it manually! -`)...), - GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { - generators = []generator.Generator{} - // TODO: Check whether anything will be generated. - generators = append(generators, NewGenDeepCopy("deep_copy_generated", inputDir)) - return generators - }, - FilterFunc: func(c *generator.Context, t *types.Type) bool { - switch t.Kind { - case types.Func, types.Chan: - // These types can't be copied. - return false - case types.Unknown, types.Unsupported: - // These types are explicitly ignored. - return false - case types.Array: - // We don't support arrays. - return false - } - // Also, filter out private types. - if namer.IsPrivateGoName(t.Name.Name) { - return false - } - return true - }, - }) +`)...) + for _, p := range context.Universe { + copyableType := false + for _, t := range p.Types { + if copyableWithinPackage(t) { + copyableType = true + } + } + if copyableType { + path := p.Path + packages = append(packages, + &generator.DefaultPackage{ + PackageName: filepath.Base(path), + PackagePath: path, + HeaderText: header, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = []generator.Generator{} + generators = append( + generators, NewGenDeepCopy("deep_copy_generated", path, inputs.Has(path))) + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + if t.Name.Package != path { + return false + } + return copyableWithinPackage(t) + }, + }) + } } return packages } @@ -109,19 +114,21 @@ const ( // genDeepCopy produces a file with a set for a single type. type genDeepCopy struct { generator.DefaultGen - targetPackage string - imports namer.ImportTracker - typesForInit []*types.Type + targetPackage string + imports namer.ImportTracker + typesForInit []*types.Type + generateInitFunc bool } -func NewGenDeepCopy(sanitizedName, targetPackage string) generator.Generator { +func NewGenDeepCopy(sanitizedName, targetPackage string, generateInitFunc bool) generator.Generator { return &genDeepCopy{ DefaultGen: generator.DefaultGen{ OptionalName: sanitizedName, }, - targetPackage: targetPackage, - imports: generator.NewImportTracker(), - typesForInit: make([]*types.Type, 0), + targetPackage: targetPackage, + imports: generator.NewImportTracker(), + typesForInit: make([]*types.Type, 0), + generateInitFunc: generateInitFunc, } } @@ -133,21 +140,14 @@ func (g *genDeepCopy) Namers(c *generator.Context) namer.NameSystems { // Filter ignores all but one type because we're making a single file per type. func (g *genDeepCopy) Filter(c *generator.Context, t *types.Type) bool { // Filter out all types not copyable within the package. - copyable := g.copyableWithinPackage(t) + copyable := copyableWithinPackage(t) if copyable { g.typesForInit = append(g.typesForInit, t) } return copyable } -func (g *genDeepCopy) copyableWithinPackage(t *types.Type) bool { - // TODO: We should generate public DeepCopy functions per directory, instead - // of generating everything everywhere. - // This is done that way only to minimize number of changes per PR. - // Once this is done, we should replace HasPrefix with: - //if t.Name.Package != g.targetPackage { - // return false - //} +func copyableWithinPackage(t *types.Type) bool { if !strings.HasPrefix(t.Name.Package, "k8s.io/kubernetes/") { return false } @@ -158,21 +158,9 @@ func (g *genDeepCopy) copyableWithinPackage(t *types.Type) bool { if t.Kind != types.Struct { return false } - // TODO: This should be removed once we start generating public DeepCopy - // functions per directory. - if t.Name.Package != g.targetPackage { - // We won't be able to access private fields. - // Thus, this type cannot have private fields. - for _, member := range t.Members { - if namer.IsPrivateGoName(member.Name) { - return false - } - // TODO: This is a temporary hack, to make avoid generating function - // for conversion.Equalities. We should get rid of it. - if member.Embedded { - return false - } - } + // Also, filter out private types. + if namer.IsPrivateGoName(t.Name.Name) { + return false } return true } @@ -189,7 +177,7 @@ func (g *genDeepCopy) isOtherPackage(pkg string) bool { func (g *genDeepCopy) Imports(c *generator.Context) (imports []string) { importLines := []string{} - if g.isOtherPackage(apiPackagePath) { + if g.isOtherPackage(apiPackagePath) && g.generateInitFunc { importLines = append(importLines, "api \""+apiPackagePath+"\"") } if g.isOtherPackage(conversionPackagePath) { @@ -210,10 +198,21 @@ func argsFromType(t *types.Type) interface{} { } func (g *genDeepCopy) funcNameTmpl(t *types.Type) string { - return "DeepCopy_$.type|public$" + tmpl := "DeepCopy_$.type|public$" + g.imports.AddType(t) + if t.Name.Package != g.targetPackage { + tmpl = g.imports.LocalNameOf(t.Name.Package) + "." + tmpl + } + return tmpl } func (g *genDeepCopy) Init(c *generator.Context, w io.Writer) error { + if !g.generateInitFunc { + // TODO: We should come up with a solution to register all generated + // deep-copy functions. However, for now, to avoid import cycles + // we register only those explicitly requested. + return nil + } sw := generator.NewSnippetWriter(w, c, "$", "$") sw.Do("func init() {\n", nil) if g.targetPackage == apiPackagePath { @@ -236,7 +235,11 @@ func (g *genDeepCopy) Init(c *generator.Context, w io.Writer) error { func (g *genDeepCopy) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { sw := generator.NewSnippetWriter(w, c, "$", "$") funcName := g.funcNameTmpl(t) - sw.Do(fmt.Sprintf("func %s(in $.type|raw$, out *$.type|raw$, c *conversion.Cloner) error {\n", funcName), argsFromType(t)) + if g.targetPackage == conversionPackagePath { + sw.Do(fmt.Sprintf("func %s(in $.type|raw$, out *$.type|raw$, c *Cloner) error {\n", funcName), argsFromType(t)) + } else { + sw.Do(fmt.Sprintf("func %s(in $.type|raw$, out *$.type|raw$, c *conversion.Cloner) error {\n", funcName), argsFromType(t)) + } g.generateFor(t, sw) sw.Do("return nil\n", nil) sw.Do("}\n\n", nil) @@ -275,12 +278,12 @@ 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("for key, val := range in {\n", nil) if t.Key.IsAssignable() { + sw.Do("for key, val := range in {\n", nil) if t.Elem.IsAssignable() { sw.Do("(*out)[key] = val\n", nil) } else { - if g.copyableWithinPackage(t.Elem) { + if copyableWithinPackage(t.Elem) { sw.Do("newVal := new($.|raw$)\n", t.Elem) funcName := g.funcNameTmpl(t.Elem) sw.Do(fmt.Sprintf("if err := %s(val, newVal, c); err != nil {\n", funcName), argsFromType(t.Elem)) @@ -297,6 +300,7 @@ func (g *genDeepCopy) doMap(t *types.Type, sw *generator.SnippetWriter) { } } else { // TODO: Implement it when necessary. + sw.Do("for range in {\n", nil) sw.Do("// FIXME: Copying unassignable keys unsupported $.|raw$\n", t.Key) } sw.Do("}\n", nil) @@ -310,7 +314,7 @@ func (g *genDeepCopy) doSlice(t *types.Type, sw *generator.SnippetWriter) { sw.Do("for i := range in {\n", nil) if t.Elem.IsAssignable() { sw.Do("(*out)[i] = in[i]\n", nil) - } else if g.copyableWithinPackage(t.Elem) { + } else if copyableWithinPackage(t.Elem) { funcName := g.funcNameTmpl(t.Elem) sw.Do(fmt.Sprintf("if err := %s(in[i], &(*out)[i], c); err != nil {\n", funcName), argsFromType(t.Elem)) sw.Do("return err\n", nil) @@ -343,7 +347,7 @@ func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) { sw.Do("out.$.name$ = nil\n", args) sw.Do("}\n", nil) case types.Struct: - if g.copyableWithinPackage(m.Type) { + if copyableWithinPackage(m.Type) { funcName := g.funcNameTmpl(m.Type) sw.Do(fmt.Sprintf("if err := %s(in.$.name$, &out.$.name$, c); err != nil {\n", funcName), args) sw.Do("return err\n", nil) @@ -378,7 +382,7 @@ func (g *genDeepCopy) doPointer(t *types.Type, sw *generator.SnippetWriter) { sw.Do("*out = new($.Elem|raw$)\n", t) if t.Elem.Kind == types.Builtin { sw.Do("**out = *in", nil) - } else if g.copyableWithinPackage(t.Elem) { + } else if copyableWithinPackage(t.Elem) { funcName := g.funcNameTmpl(t.Elem) sw.Do(fmt.Sprintf("if err := %s(*in, *out, c); err != nil {\n", funcName), argsFromType(t.Elem)) sw.Do("return err\n", nil)