diff --git a/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/BUILD b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/BUILD index 74343558358..9fe3cada6ad 100644 --- a/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/BUILD +++ b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/BUILD @@ -27,6 +27,7 @@ go_library( "//vendor/k8s.io/kube-gen/cmd/client-gen/args:go_default_library", "//vendor/k8s.io/kube-gen/cmd/client-gen/generators/fake:go_default_library", "//vendor/k8s.io/kube-gen/cmd/client-gen/generators/scheme:go_default_library", + "//vendor/k8s.io/kube-gen/cmd/client-gen/generators/util:go_default_library", "//vendor/k8s.io/kube-gen/cmd/client-gen/path:go_default_library", "//vendor/k8s.io/kube-gen/cmd/client-gen/types:go_default_library", ], diff --git a/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/client_generator.go b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/client_generator.go index 98503f506d6..de1e5ee8fcb 100644 --- a/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/client_generator.go +++ b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/client_generator.go @@ -29,6 +29,7 @@ import ( clientgenargs "k8s.io/kube-gen/cmd/client-gen/args" "k8s.io/kube-gen/cmd/client-gen/generators/fake" "k8s.io/kube-gen/cmd/client-gen/generators/scheme" + "k8s.io/kube-gen/cmd/client-gen/generators/util" "k8s.io/kube-gen/cmd/client-gen/path" clientgentypes "k8s.io/kube-gen/cmd/client-gen/types" @@ -169,7 +170,7 @@ func packageForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, cli return generators }, FilterFunc: func(c *generator.Context, t *types.Type) bool { - return extractBoolTagOrDie("genclient", t.SecondClosestCommentLines) == true + return util.MustParseClientGenTags(t.SecondClosestCommentLines).GenerateClient }, } } @@ -342,7 +343,7 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat } else { // User has not specified any override for this group version. // filter out types which dont have genclient=true. - if extractBoolTagOrDie("genclient", t.SecondClosestCommentLines) == false { + if tags := util.MustParseClientGenTags(t.SecondClosestCommentLines); !tags.GenerateClient { continue } } diff --git a/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/fake/BUILD b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/fake/BUILD index c39ef73d348..81a5e15d9e1 100644 --- a/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/fake/BUILD +++ b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/fake/BUILD @@ -17,12 +17,12 @@ go_library( ], tags = ["automanaged"], deps = [ - "//vendor/github.com/golang/glog:go_default_library", "//vendor/k8s.io/gengo/generator:go_default_library", "//vendor/k8s.io/gengo/namer:go_default_library", "//vendor/k8s.io/gengo/types:go_default_library", "//vendor/k8s.io/kube-gen/cmd/client-gen/args:go_default_library", "//vendor/k8s.io/kube-gen/cmd/client-gen/generators/scheme:go_default_library", + "//vendor/k8s.io/kube-gen/cmd/client-gen/generators/util:go_default_library", "//vendor/k8s.io/kube-gen/cmd/client-gen/path:go_default_library", "//vendor/k8s.io/kube-gen/cmd/client-gen/types:go_default_library", ], diff --git a/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/fake/fake_client_generator.go b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/fake/fake_client_generator.go index 7b3817fb93c..36e51f411b2 100644 --- a/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/fake/fake_client_generator.go +++ b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/fake/fake_client_generator.go @@ -20,12 +20,12 @@ import ( "path/filepath" "strings" - "github.com/golang/glog" - "k8s.io/gengo/generator" "k8s.io/gengo/types" + clientgenargs "k8s.io/kube-gen/cmd/client-gen/args" scheme "k8s.io/kube-gen/cmd/client-gen/generators/scheme" + "k8s.io/kube-gen/cmd/client-gen/generators/util" clientgentypes "k8s.io/kube-gen/cmd/client-gen/types" ) @@ -78,19 +78,11 @@ func PackageForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, cli return generators }, FilterFunc: func(c *generator.Context, t *types.Type) bool { - return extractBoolTagOrDie("genclient", t.SecondClosestCommentLines) == true + return util.MustParseClientGenTags(t.SecondClosestCommentLines).GenerateClient }, } } -func extractBoolTagOrDie(key string, lines []string) bool { - val, err := types.ExtractSingleBoolCommentTag("+", key, false, lines) - if err != nil { - glog.Fatalf(err.Error()) - } - return val -} - func PackageForClientset(customArgs clientgenargs.Args, fakeClientsetPackage string, boilerplate []byte, generatedBy string) generator.Package { return &generator.DefaultPackage{ // TODO: we'll generate fake clientset for different release in the future. diff --git a/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/fake/generator_fake_for_group.go b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/fake/generator_fake_for_group.go index 0b1409dd750..092321b93bb 100644 --- a/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/fake/generator_fake_for_group.go +++ b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/fake/generator_fake_for_group.go @@ -25,6 +25,8 @@ import ( "k8s.io/gengo/generator" "k8s.io/gengo/namer" "k8s.io/gengo/types" + + "k8s.io/kube-gen/cmd/client-gen/generators/util" ) // genFakeForGroup produces a file for a group client, e.g. ExtensionsClient for the extension group. @@ -70,18 +72,20 @@ func (g *genFakeForGroup) GenerateType(c *generator.Context, t *types.Type, w io sw.Do(groupClientTemplate, m) for _, t := range g.types { + tags, err := util.ParseClientGenTags(t.SecondClosestCommentLines) + if err != nil { + return err + } wrapper := map[string]interface{}{ "type": t, "GroupVersion": namer.IC(g.group) + namer.IC(g.version), "realClientPackage": strings.ToLower(filepath.Base(g.realClientPackage)), } - namespaced := !extractBoolTagOrDie("nonNamespaced", t.SecondClosestCommentLines) - if namespaced { - sw.Do(getterImplNamespaced, wrapper) - } else { + if tags.NonNamespaced { sw.Do(getterImplNonNamespaced, wrapper) - + continue } + sw.Do(getterImplNamespaced, wrapper) } sw.Do(getRESTClient, m) return sw.Error() diff --git a/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/fake/generator_fake_for_type.go b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/fake/generator_fake_for_type.go index b670a15152b..a6660440549 100644 --- a/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/fake/generator_fake_for_type.go +++ b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/fake/generator_fake_for_type.go @@ -17,13 +17,14 @@ limitations under the License. package fake import ( - "fmt" "io" "path/filepath" "k8s.io/gengo/generator" "k8s.io/gengo/namer" "k8s.io/gengo/types" + + "k8s.io/kube-gen/cmd/client-gen/generators/util" "k8s.io/kube-gen/cmd/client-gen/path" ) @@ -66,12 +67,8 @@ func genStatus(t *types.Type) bool { } } - // Allow overriding via a comment on the type - genStatus, err := types.ExtractSingleBoolCommentTag("+", "genclientstatus", hasStatus, t.SecondClosestCommentLines) - if err != nil { - fmt.Printf("error looking up +genclientstatus: %v\n", err) - } - return genStatus + tags := util.MustParseClientGenTags(t.SecondClosestCommentLines) + return hasStatus && !tags.NoStatus } // hasObjectMeta returns true if the type has a ObjectMeta field. @@ -88,7 +85,10 @@ func hasObjectMeta(t *types.Type) bool { func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { sw := generator.NewSnippetWriter(w, c, "$", "$") pkg := filepath.Base(t.Name.Package) - namespaced := !extractBoolTagOrDie("nonNamespaced", t.SecondClosestCommentLines) + tags, err := util.ParseClientGenTags(t.SecondClosestCommentLines) + if err != nil { + return err + } canonicalGroup := g.group if canonicalGroup == "core" { canonicalGroup = "" @@ -110,7 +110,7 @@ func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io. "type": t, "package": pkg, "Package": namer.IC(pkg), - "namespaced": namespaced, + "namespaced": !tags.NonNamespaced, "Group": namer.IC(g.group), "GroupVersion": namer.IC(g.group) + namer.IC(g.version), "group": canonicalGroup, @@ -148,43 +148,48 @@ func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io. "ExtractFromListOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "ExtractFromListOptions"}), } - noMethods := extractBoolTagOrDie("noMethods", t.SecondClosestCommentLines) == true - - readonly := extractBoolTagOrDie("readonly", t.SecondClosestCommentLines) == true - - if namespaced { - sw.Do(structNamespaced, m) - } else { + if tags.NonNamespaced { sw.Do(structNonNamespaced, m) + } else { + sw.Do(structNamespaced, m) } - if !noMethods { - sw.Do(resource, m) - sw.Do(kind, m) + if tags.NoVerbs { + return sw.Error() } + sw.Do(resource, m) + sw.Do(kind, m) - if !noMethods && !readonly { - sw.Do(createTemplate, m) - sw.Do(updateTemplate, m) - // Generate the UpdateStatus method if the type has a status - if genStatus(t) { - sw.Do(updateStatusTemplate, m) - } - sw.Do(deleteTemplate, m) - sw.Do(deleteCollectionTemplate, m) - } - - if !noMethods { + if tags.HasVerb("get") { sw.Do(getTemplate, m) + } + if tags.HasVerb("list") { if hasObjectMeta(t) { sw.Do(listUsingOptionsTemplate, m) } else { sw.Do(listTemplate, m) } + } + if tags.HasVerb("watch") { sw.Do(watchTemplate, m) } - if !noMethods && !readonly { + if tags.HasVerb("create") { + sw.Do(createTemplate, m) + } + if tags.HasVerb("update") { + sw.Do(updateTemplate, m) + } + if tags.HasVerb("updateStatus") && genStatus(t) { + sw.Do(updateStatusTemplate, m) + } + if tags.HasVerb("delete") { + sw.Do(deleteTemplate, m) + } + if tags.HasVerb("deleteCollection") { + sw.Do(deleteCollectionTemplate, m) + } + if tags.HasVerb("patch") { sw.Do(patchTemplate, m) } @@ -217,6 +222,7 @@ var $.type|allLowercasePlural$Kind = $.GroupVersionKind|raw${Group: "$.groupName ` var listTemplate = ` +// List takes label and field selectors, and returns the list of $.type|publicPlural$ that match those selectors. func (c *Fake$.type|publicPlural$) List(opts $.ListOptions|raw$) (result *$.type|raw$List, err error) { obj, err := c.Fake. $if .namespaced$Invokes($.NewListAction|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, c.ns, opts), &$.type|raw$List{}) @@ -229,6 +235,7 @@ func (c *Fake$.type|publicPlural$) List(opts $.ListOptions|raw$) (result *$.type ` var listUsingOptionsTemplate = ` +// List takes label and field selectors, and returns the list of $.type|publicPlural$ that match those selectors. func (c *Fake$.type|publicPlural$) List(opts $.ListOptions|raw$) (result *$.type|raw$List, err error) { obj, err := c.Fake. $if .namespaced$Invokes($.NewListAction|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, c.ns, opts), &$.type|raw$List{}) @@ -252,6 +259,7 @@ func (c *Fake$.type|publicPlural$) List(opts $.ListOptions|raw$) (result *$.type ` var getTemplate = ` +// Get takes name of the $.type|private$, and returns the corresponding $.type|private$ object, and an error if there is any. func (c *Fake$.type|publicPlural$) Get(name string, options $.GetOptions|raw$) (result *$.type|raw$, err error) { obj, err := c.Fake. $if .namespaced$Invokes($.NewGetAction|raw$($.type|allLowercasePlural$Resource, c.ns, name), &$.type|raw${}) @@ -264,6 +272,7 @@ func (c *Fake$.type|publicPlural$) Get(name string, options $.GetOptions|raw$) ( ` var deleteTemplate = ` +// Delete takes name of the $.type|private$ and deletes it. Returns an error if one occurs. func (c *Fake$.type|publicPlural$) Delete(name string, options *$.DeleteOptions|raw$) error { _, err := c.Fake. $if .namespaced$Invokes($.NewDeleteAction|raw$($.type|allLowercasePlural$Resource, c.ns, name), &$.type|raw${}) @@ -273,6 +282,7 @@ func (c *Fake$.type|publicPlural$) Delete(name string, options *$.DeleteOptions| ` var deleteCollectionTemplate = ` +// DeleteCollection deletes a collection of objects. func (c *Fake$.type|publicPlural$) DeleteCollection(options *$.DeleteOptions|raw$, listOptions $.ListOptions|raw$) error { $if .namespaced$action := $.NewDeleteCollectionAction|raw$($.type|allLowercasePlural$Resource, c.ns, listOptions) $else$action := $.NewRootDeleteCollectionAction|raw$($.type|allLowercasePlural$Resource, listOptions) @@ -283,6 +293,7 @@ func (c *Fake$.type|publicPlural$) DeleteCollection(options *$.DeleteOptions|raw ` var createTemplate = ` +// Create takes the representation of a $.type|private$ and creates it. Returns the server's representation of the $.type|private$, and an error, if there is any. func (c *Fake$.type|publicPlural$) Create($.type|private$ *$.type|raw$) (result *$.type|raw$, err error) { obj, err := c.Fake. $if .namespaced$Invokes($.NewCreateAction|raw$($.type|allLowercasePlural$Resource, c.ns, $.type|private$), &$.type|raw${}) @@ -295,6 +306,7 @@ func (c *Fake$.type|publicPlural$) Create($.type|private$ *$.type|raw$) (result ` var updateTemplate = ` +// Update takes the representation of a $.type|private$ and updates it. Returns the server's representation of the $.type|private$, and an error, if there is any. func (c *Fake$.type|publicPlural$) Update($.type|private$ *$.type|raw$) (result *$.type|raw$, err error) { obj, err := c.Fake. $if .namespaced$Invokes($.NewUpdateAction|raw$($.type|allLowercasePlural$Resource, c.ns, $.type|private$), &$.type|raw${}) @@ -307,6 +319,8 @@ func (c *Fake$.type|publicPlural$) Update($.type|private$ *$.type|raw$) (result ` var updateStatusTemplate = ` +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). func (c *Fake$.type|publicPlural$) UpdateStatus($.type|private$ *$.type|raw$) (*$.type|raw$, error) { obj, err := c.Fake. $if .namespaced$Invokes($.NewUpdateSubresourceAction|raw$($.type|allLowercasePlural$Resource, "status", c.ns, $.type|private$), &$.type|raw${}) diff --git a/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/generator_for_group.go b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/generator_for_group.go index c10f13f9f63..213796781a5 100644 --- a/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/generator_for_group.go +++ b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/generator_for_group.go @@ -23,6 +23,8 @@ import ( "k8s.io/gengo/generator" "k8s.io/gengo/namer" "k8s.io/gengo/types" + + "k8s.io/kube-gen/cmd/client-gen/generators/util" "k8s.io/kube-gen/cmd/client-gen/path" ) @@ -101,15 +103,18 @@ func (g *genGroup) GenerateType(c *generator.Context, t *types.Type, w io.Writer sw.Do(groupInterfaceTemplate, m) sw.Do(groupClientTemplate, m) for _, t := range g.types { + tags, err := util.ParseClientGenTags(t.SecondClosestCommentLines) + if err != nil { + return err + } wrapper := map[string]interface{}{ "type": t, "GroupVersion": namer.IC(g.group) + namer.IC(g.version), } - namespaced := !extractBoolTagOrDie("nonNamespaced", t.SecondClosestCommentLines) - if namespaced { - sw.Do(getterImplNamespaced, wrapper) - } else { + if tags.NonNamespaced { sw.Do(getterImplNonNamespaced, wrapper) + } else { + sw.Do(getterImplNamespaced, wrapper) } } sw.Do(newClientForConfigTemplate, m) diff --git a/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/generator_for_type.go b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/generator_for_type.go index be2c9908a7b..8467a0ba4c1 100644 --- a/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/generator_for_type.go +++ b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/generator_for_type.go @@ -17,13 +17,15 @@ limitations under the License. package generators import ( - "fmt" "io" "path/filepath" + "strings" "k8s.io/gengo/generator" "k8s.io/gengo/namer" "k8s.io/gengo/types" + + "k8s.io/kube-gen/cmd/client-gen/generators/util" ) // genClientForType produces a file for each top-level type. @@ -64,25 +66,22 @@ func genStatus(t *types.Type) bool { break } } - - // Allow overriding via a comment on the type - genStatus, err := types.ExtractSingleBoolCommentTag("+", "genclientstatus", hasStatus, t.SecondClosestCommentLines) - if err != nil { - fmt.Printf("error looking up +genclientstatus: %v\n", err) - } - return genStatus + return hasStatus && !util.MustParseClientGenTags(t.SecondClosestCommentLines).NoStatus } // GenerateType makes the body of a file implementing the individual typed client for type t. func (g *genClientForType) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { sw := generator.NewSnippetWriter(w, c, "$", "$") pkg := filepath.Base(t.Name.Package) - namespaced := !extractBoolTagOrDie("nonNamespaced", t.SecondClosestCommentLines) + tags, err := util.ParseClientGenTags(t.SecondClosestCommentLines) + if err != nil { + return err + } m := map[string]interface{}{ "type": t, "package": pkg, "Package": namer.IC(pkg), - "namespaced": namespaced, + "namespaced": !tags.NonNamespaced, "Group": namer.IC(g.group), "GroupVersion": namer.IC(g.group) + namer.IC(g.version), "DeleteOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "DeleteOptions"}), @@ -95,74 +94,100 @@ func (g *genClientForType) GenerateType(c *generator.Context, t *types.Type, w i } sw.Do(getterComment, m) - if namespaced { - sw.Do(getterNamesapced, m) + if tags.NonNamespaced { + sw.Do(getterNonNamespaced, m) } else { - sw.Do(getterNonNamesapced, m) + sw.Do(getterNamespaced, m) } - noMethods := extractBoolTagOrDie("noMethods", t.SecondClosestCommentLines) == true - - readonly := extractBoolTagOrDie("readonly", t.SecondClosestCommentLines) == true sw.Do(interfaceTemplate1, m) - if !noMethods { - if readonly { - sw.Do(interfaceTemplateReadonly, m) - } else { - sw.Do(interfaceTemplate2, m) - // Include the UpdateStatus method if the type has a status - if genStatus(t) { - sw.Do(interfaceUpdateStatusTemplate, m) - } - sw.Do(interfaceTemplate3, m) + if !tags.NoVerbs { + if !genStatus(t) { + tags.SkipVerbs = append(tags.SkipVerbs, "updateStatus") } + sw.Do(generateInterface(tags), m) } sw.Do(interfaceTemplate4, m) - if namespaced { - sw.Do(structNamespaced, m) - sw.Do(newStructNamespaced, m) - } else { + if tags.NonNamespaced { sw.Do(structNonNamespaced, m) sw.Do(newStructNonNamespaced, m) + } else { + sw.Do(structNamespaced, m) + sw.Do(newStructNamespaced, m) } - if !noMethods && !readonly { - sw.Do(createTemplate, m) - sw.Do(updateTemplate, m) - // Generate the UpdateStatus method if the type has a status - if genStatus(t) { - sw.Do(updateStatusTemplate, m) - } - sw.Do(deleteTemplate, m) - sw.Do(deleteCollectionTemplate, m) + if tags.NoVerbs { + return sw.Error() } - if !noMethods { + if tags.HasVerb("get") { sw.Do(getTemplate, m) + } + if tags.HasVerb("list") { sw.Do(listTemplate, m) + } + if tags.HasVerb("watch") { sw.Do(watchTemplate, m) } - if !noMethods && !readonly { + if tags.HasVerb("create") { + sw.Do(createTemplate, m) + } + if tags.HasVerb("update") { + sw.Do(updateTemplate, m) + } + if tags.HasVerb("updateStatus") { + sw.Do(updateStatusTemplate, m) + } + if tags.HasVerb("delete") { + sw.Do(deleteTemplate, m) + } + if tags.HasVerb("deleteCollection") { + sw.Do(deleteCollectionTemplate, m) + } + if tags.HasVerb("patch") { sw.Do(patchTemplate, m) } return sw.Error() } +func generateInterface(tags util.Tags) string { + // need an ordered list here to guarantee order of generated methods. + out := []string{} + for _, m := range util.SupportedVerbs { + if tags.HasVerb(m) { + out = append(out, defaultVerbTemplates[m]) + } + } + return strings.Join(out, "\n") +} + +var defaultVerbTemplates = map[string]string{ + "create": `Create(*$.type|raw$) (*$.type|raw$, error)`, + "update": `Update(*$.type|raw$) (*$.type|raw$, error)`, + "updateStatus": `UpdateStatus(*$.type|raw$) (*$.type|raw$, error)`, + "delete": `Delete(name string, options *$.DeleteOptions|raw$) error`, + "deleteCollection": `DeleteCollection(options *$.DeleteOptions|raw$, listOptions $.ListOptions|raw$) error`, + "get": `Get(name string, options $.GetOptions|raw$) (*$.type|raw$, error)`, + "list": `List(opts $.ListOptions|raw$) (*$.type|raw$List, error)`, + "watch": `Watch(opts $.ListOptions|raw$) ($.watchInterface|raw$, error)`, + "patch": `Patch(name string, pt $.PatchType|raw$, data []byte, subresources ...string) (result *$.type|raw$, err error)`, +} + // group client will implement this interface. var getterComment = ` // $.type|publicPlural$Getter has a method to return a $.type|public$Interface. // A group's client should implement this interface.` -var getterNamesapced = ` +var getterNamespaced = ` type $.type|publicPlural$Getter interface { $.type|publicPlural$(namespace string) $.type|public$Interface } ` -var getterNonNamesapced = ` +var getterNonNamespaced = ` type $.type|publicPlural$Getter interface { $.type|publicPlural$() $.type|public$Interface } @@ -173,27 +198,6 @@ var interfaceTemplate1 = ` // $.type|public$Interface has methods to work with $.type|public$ resources. type $.type|public$Interface interface {` -var interfaceTemplate2 = ` - Create(*$.type|raw$) (*$.type|raw$, error) - Update(*$.type|raw$) (*$.type|raw$, error)` - -var interfaceUpdateStatusTemplate = ` - UpdateStatus(*$.type|raw$) (*$.type|raw$, error)` - -// template for the Interface -var interfaceTemplate3 = ` - Delete(name string, options *$.DeleteOptions|raw$) error - DeleteCollection(options *$.DeleteOptions|raw$, listOptions $.ListOptions|raw$) error - Get(name string, options $.GetOptions|raw$) (*$.type|raw$, error) - List(opts $.ListOptions|raw$) (*$.type|raw$List, error) - Watch(opts $.ListOptions|raw$) ($.watchInterface|raw$, error) - Patch(name string, pt $.PatchType|raw$, data []byte, subresources ...string) (result *$.type|raw$, err error)` - -var interfaceTemplateReadonly = ` - Get(name string, options $.GetOptions|raw$) (*$.type|raw$, error) - List(opts $.ListOptions|raw$) (*$.type|raw$List, error) - Watch(opts $.ListOptions|raw$) ($.watchInterface|raw$, error)` - var interfaceTemplate4 = ` $.type|public$Expansion } @@ -320,7 +324,7 @@ func (c *$.type|privatePlural$) Update($.type|private$ *$.type|raw$) (result *$. var updateStatusTemplate = ` // UpdateStatus was generated because the type contains a Status member. -// Add a +genclientstatus=false comment above the type to avoid generating UpdateStatus(). +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). func (c *$.type|privatePlural$) UpdateStatus($.type|private$ *$.type|raw$) (result *$.type|raw$, err error) { result = &$.type|raw${} diff --git a/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/tags.go b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/tags.go index 063559c09e1..b0040810368 100644 --- a/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/tags.go +++ b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/tags.go @@ -17,21 +17,9 @@ limitations under the License. package generators import ( - "github.com/golang/glog" "k8s.io/gengo/types" ) -// extractBoolTagOrDie gets the comment-tags for the key and asserts that, if -// it exists, the value is boolean. If the tag did not exist, it returns -// false. -func extractBoolTagOrDie(key string, lines []string) bool { - val, err := types.ExtractSingleBoolCommentTag("+", key, false, lines) - if err != nil { - glog.Fatalf(err.Error()) - } - return val -} - // extractTag gets the comment-tags for the key. If the tag did not exist, it // returns the empty string. func extractTag(key string, lines []string) string { diff --git a/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/util/BUILD b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/util/BUILD new file mode 100644 index 00000000000..69f9beeb43a --- /dev/null +++ b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/util/BUILD @@ -0,0 +1,23 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", + "go_test", +) + +go_test( + name = "go_default_test", + srcs = ["tags_test.go"], + library = ":go_default_library", + tags = ["automanaged"], +) + +go_library( + name = "go_default_library", + srcs = ["tags.go"], + tags = ["automanaged"], + deps = ["//vendor/k8s.io/gengo/types:go_default_library"], +) diff --git a/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/util/tags.go b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/util/tags.go new file mode 100644 index 00000000000..38747ec24c6 --- /dev/null +++ b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/util/tags.go @@ -0,0 +1,163 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package util + +import ( + "errors" + "fmt" + "strings" + + "k8s.io/gengo/types" +) + +var supportedTags = []string{ + "genclient", + "genclient:nonNamespaced", + "genclient:noVerbs", + "genclient:onlyVerbs", + "genclient:skipVerbs", + "genclient:noStatus", + "genclient:readonly", +} + +// SupportedVerbs is a list of supported verbs for +onlyVerbs and +skipVerbs. +var SupportedVerbs = []string{ + "create", + "update", + "updateStatus", + "delete", + "deleteCollection", + "get", + "list", + "watch", + "patch", +} + +// ReadonlyVerbs represents a list of read-only verbs. +var ReadonlyVerbs = []string{ + "get", + "list", + "watch", +} + +// Tags represents a genclient configuration for a single type. +type Tags struct { + // +genclient + GenerateClient bool + // +genclient:nonNamespaced + NonNamespaced bool + // +genclient:noStatus + NoStatus bool + // +genclient:noVerbs + NoVerbs bool + // +genclient:skipVerbs=get,update + // +genclient:onlyVerbs=create,delete + SkipVerbs []string +} + +// HasVerb returns true if we should include the given verb in final client interface and +// generate the function for it. +func (t Tags) HasVerb(verb string) bool { + if len(t.SkipVerbs) == 0 { + return true + } + for _, s := range t.SkipVerbs { + if verb == s { + return false + } + } + return true +} + +// MustParseClientGenTags calls ParseClientGenTags but instead of returning error it panics. +func MustParseClientGenTags(lines []string) Tags { + tags, err := ParseClientGenTags(lines) + if err != nil { + panic(err.Error()) + } + return tags +} + +// ParseClientGenTags parse the provided genclient tags and validates that no unknown +// tags are provided. +func ParseClientGenTags(lines []string) (Tags, error) { + ret := Tags{} + values := types.ExtractCommentTags("+", lines) + value := []string{} + value, ret.GenerateClient = values["genclient"] + // Check the old format and error when used to avoid generating client when //+genclient=false + if len(value) > 0 && len(value[0]) > 0 { + return ret, fmt.Errorf("+genclient=%s is invalid, use //+genclient if you want to generate client or omit it when you want to disable generation", value) + } + _, ret.NonNamespaced = values["genclient:nonNamespaced"] + // Check the old format and error when used + if value := values["nonNamespaced"]; len(value) > 0 && len(value[0]) > 0 { + return ret, fmt.Errorf("+nonNamespaced=%s is invalid, use //+genclient:nonNamespaced instead", value[0]) + } + _, ret.NoVerbs = values["genclient:noVerbs"] + _, ret.NoStatus = values["genclient:noStatus"] + onlyVerbs := []string{} + if _, isReadonly := values["genclient:readonly"]; isReadonly { + onlyVerbs = ReadonlyVerbs + } + // Check the old format and error when used + if value := values["readonly"]; len(value) > 0 && len(value[0]) > 0 { + return ret, fmt.Errorf("+readonly=%s is invalid, use //+genclient:readonly instead", value[0]) + } + if v, exists := values["genclient:skipVerbs"]; exists { + ret.SkipVerbs = strings.Split(v[0], ",") + } + if v, exists := values["genclient:onlyVerbs"]; exists || len(onlyVerbs) > 0 { + if len(v) > 0 { + onlyVerbs = append(onlyVerbs, strings.Split(v[0], ",")...) + } + skipVerbs := []string{} + for _, m := range SupportedVerbs { + skip := true + for _, o := range onlyVerbs { + if o == m { + skip = false + break + } + } + // Check for conflicts + for _, v := range skipVerbs { + if v == m { + return ret, fmt.Errorf("verb %q used both in genclient:skipVerbs and genclient:onlyVerbs", v) + } + } + if skip { + skipVerbs = append(skipVerbs, m) + } + } + ret.SkipVerbs = skipVerbs + } + return ret, validateClientGenTags(values) +} + +// validateTags validates that only supported genclient tags were provided. +func validateClientGenTags(values map[string][]string) error { + for _, k := range supportedTags { + delete(values, k) + } + for key := range values { + if strings.HasPrefix(key, "genclient") { + return errors.New("unknown tag detected: " + key) + } + } + return nil +} diff --git a/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/util/tags_test.go b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/util/tags_test.go new file mode 100644 index 00000000000..531b584835d --- /dev/null +++ b/staging/src/k8s.io/kube-gen/cmd/client-gen/generators/util/tags_test.go @@ -0,0 +1,84 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package util + +import ( + "reflect" + "testing" +) + +func TestParseTags(t *testing.T) { + testCases := map[string]struct { + lines []string + expectTags Tags + expectError bool + }{ + "genclient": { + lines: []string{`+genclient`}, + expectTags: Tags{GenerateClient: true}, + }, + "genclient=true": { + lines: []string{`+genclient=true`}, + expectError: true, + }, + "nonNamespaced=true": { + lines: []string{`+genclient=true`, `+nonNamespaced=true`}, + expectError: true, + }, + "readonly=true": { + lines: []string{`+genclient=true`, `+readonly=true`}, + expectError: true, + }, + "genclient:nonNamespaced": { + lines: []string{`+genclient`, `+genclient:nonNamespaced`}, + expectTags: Tags{GenerateClient: true, NonNamespaced: true}, + }, + "genclient:noVerbs": { + lines: []string{`+genclient`, `+genclient:noVerbs`}, + expectTags: Tags{GenerateClient: true, NoVerbs: true}, + }, + "genclient:noStatus": { + lines: []string{`+genclient`, `+genclient:noStatus`}, + expectTags: Tags{GenerateClient: true, NoStatus: true}, + }, + "genclient:onlyVerbs": { + lines: []string{`+genclient`, `+genclient:onlyVerbs=create,delete`}, + expectTags: Tags{GenerateClient: true, SkipVerbs: []string{"update", "updateStatus", "deleteCollection", "get", "list", "watch", "patch"}}, + }, + "genclient:readonly": { + lines: []string{`+genclient`, `+genclient:readonly`}, + expectTags: Tags{GenerateClient: true, SkipVerbs: []string{"create", "update", "updateStatus", "delete", "deleteCollection", "patch"}}, + }, + "genclient:conflict": { + lines: []string{`+genclient`, `+genclient:onlyVerbs=create`, `+genclient:skipVerbs=create`}, + expectError: true, + }, + "genclient:invalid": { + lines: []string{`+genclient`, `+genclient:invalid`}, + expectError: true, + }, + } + for key, c := range testCases { + result, err := ParseClientGenTags(c.lines) + if err != nil && !c.expectError { + t.Fatalf("unexpected error: %v", err) + } + if !c.expectError && !reflect.DeepEqual(result, c.expectTags) { + t.Errorf("[%s] expected %#v to be %#v", key, result, c.expectTags) + } + } +} diff --git a/staging/src/k8s.io/kube-gen/cmd/client-gen/test_apis/testgroup/types.go b/staging/src/k8s.io/kube-gen/cmd/client-gen/test_apis/testgroup/types.go index 82e63e2592b..6a6874f9cea 100644 --- a/staging/src/k8s.io/kube-gen/cmd/client-gen/test_apis/testgroup/types.go +++ b/staging/src/k8s.io/kube-gen/cmd/client-gen/test_apis/testgroup/types.go @@ -18,7 +18,7 @@ package testgroup import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -// +genclient=true +// +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type TestType struct { diff --git a/staging/src/k8s.io/kube-gen/cmd/client-gen/test_apis/testgroup/v1/types.go b/staging/src/k8s.io/kube-gen/cmd/client-gen/test_apis/testgroup/v1/types.go index 9254874a73e..30852235175 100644 --- a/staging/src/k8s.io/kube-gen/cmd/client-gen/test_apis/testgroup/v1/types.go +++ b/staging/src/k8s.io/kube-gen/cmd/client-gen/test_apis/testgroup/v1/types.go @@ -18,7 +18,7 @@ package v1 import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -// +genclient=true +// +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object type TestType struct { diff --git a/staging/src/k8s.io/kube-gen/cmd/client-gen/testoutput/clientset_generated/test_internalclientset/typed/testgroup/internalversion/fake/fake_testtype.go b/staging/src/k8s.io/kube-gen/cmd/client-gen/testoutput/clientset_generated/test_internalclientset/typed/testgroup/internalversion/fake/fake_testtype.go index 4d57a18b9be..889a4168469 100644 --- a/staging/src/k8s.io/kube-gen/cmd/client-gen/testoutput/clientset_generated/test_internalclientset/typed/testgroup/internalversion/fake/fake_testtype.go +++ b/staging/src/k8s.io/kube-gen/cmd/client-gen/testoutput/clientset_generated/test_internalclientset/typed/testgroup/internalversion/fake/fake_testtype.go @@ -36,6 +36,44 @@ var testtypesResource = schema.GroupVersionResource{Group: "testgroup.k8s.io", V var testtypesKind = schema.GroupVersionKind{Group: "testgroup.k8s.io", Version: "", Kind: "TestType"} +func (c *FakeTestTypes) Get(name string, options v1.GetOptions) (result *testgroup.TestType, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(testtypesResource, c.ns, name), &testgroup.TestType{}) + + if obj == nil { + return nil, err + } + return obj.(*testgroup.TestType), err +} + +func (c *FakeTestTypes) List(opts v1.ListOptions) (result *testgroup.TestTypeList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(testtypesResource, testtypesKind, c.ns, opts), &testgroup.TestTypeList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &testgroup.TestTypeList{} + for _, item := range obj.(*testgroup.TestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *FakeTestTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(testtypesResource, c.ns, opts)) + +} + func (c *FakeTestTypes) Create(testType *testgroup.TestType) (result *testgroup.TestType, err error) { obj, err := c.Fake. Invokes(testing.NewCreateAction(testtypesResource, c.ns, testType), &testgroup.TestType{}) @@ -80,44 +118,6 @@ func (c *FakeTestTypes) DeleteCollection(options *v1.DeleteOptions, listOptions return err } -func (c *FakeTestTypes) Get(name string, options v1.GetOptions) (result *testgroup.TestType, err error) { - obj, err := c.Fake. - Invokes(testing.NewGetAction(testtypesResource, c.ns, name), &testgroup.TestType{}) - - if obj == nil { - return nil, err - } - return obj.(*testgroup.TestType), err -} - -func (c *FakeTestTypes) List(opts v1.ListOptions) (result *testgroup.TestTypeList, err error) { - obj, err := c.Fake. - Invokes(testing.NewListAction(testtypesResource, testtypesKind, c.ns, opts), &testgroup.TestTypeList{}) - - if obj == nil { - return nil, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &testgroup.TestTypeList{} - for _, item := range obj.(*testgroup.TestTypeList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested testTypes. -func (c *FakeTestTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchAction(testtypesResource, c.ns, opts)) - -} - // Patch applies the patch and returns the patched testType. func (c *FakeTestTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *testgroup.TestType, err error) { obj, err := c.Fake. diff --git a/staging/src/k8s.io/kube-gen/cmd/client-gen/testoutput/clientset_generated/test_internalclientset/typed/testgroup/internalversion/testtype.go b/staging/src/k8s.io/kube-gen/cmd/client-gen/testoutput/clientset_generated/test_internalclientset/typed/testgroup/internalversion/testtype.go index daad70275c9..54610e80bc9 100644 --- a/staging/src/k8s.io/kube-gen/cmd/client-gen/testoutput/clientset_generated/test_internalclientset/typed/testgroup/internalversion/testtype.go +++ b/staging/src/k8s.io/kube-gen/cmd/client-gen/testoutput/clientset_generated/test_internalclientset/typed/testgroup/internalversion/testtype.go @@ -59,6 +59,41 @@ func newTestTypes(c *TestgroupClient, namespace string) *testTypes { } } +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *testTypes) Get(name string, options v1.GetOptions) (result *testgroup.TestType, err error) { + result = &testgroup.TestType{} + err = c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *testTypes) List(opts v1.ListOptions) (result *testgroup.TestTypeList, err error) { + result = &testgroup.TestTypeList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *testTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("testtypes"). + VersionedParams(&opts, scheme.ParameterCodec). + Watch() +} + // Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. func (c *testTypes) Create(testType *testgroup.TestType) (result *testgroup.TestType, err error) { result = &testgroup.TestType{} @@ -85,7 +120,7 @@ func (c *testTypes) Update(testType *testgroup.TestType) (result *testgroup.Test } // UpdateStatus was generated because the type contains a Status member. -// Add a +genclientstatus=false comment above the type to avoid generating UpdateStatus(). +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). func (c *testTypes) UpdateStatus(testType *testgroup.TestType) (result *testgroup.TestType, err error) { result = &testgroup.TestType{} @@ -122,41 +157,6 @@ func (c *testTypes) DeleteCollection(options *v1.DeleteOptions, listOptions v1.L Error() } -// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. -func (c *testTypes) Get(name string, options v1.GetOptions) (result *testgroup.TestType, err error) { - result = &testgroup.TestType{} - err = c.client.Get(). - Namespace(c.ns). - Resource("testtypes"). - Name(name). - VersionedParams(&options, scheme.ParameterCodec). - Do(). - Into(result) - return -} - -// List takes label and field selectors, and returns the list of TestTypes that match those selectors. -func (c *testTypes) List(opts v1.ListOptions) (result *testgroup.TestTypeList, err error) { - result = &testgroup.TestTypeList{} - err = c.client.Get(). - Namespace(c.ns). - Resource("testtypes"). - VersionedParams(&opts, scheme.ParameterCodec). - Do(). - Into(result) - return -} - -// Watch returns a watch.Interface that watches the requested testTypes. -func (c *testTypes) Watch(opts v1.ListOptions) (watch.Interface, error) { - opts.Watch = true - return c.client.Get(). - Namespace(c.ns). - Resource("testtypes"). - VersionedParams(&opts, scheme.ParameterCodec). - Watch() -} - // Patch applies the patch and returns the patched testType. func (c *testTypes) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *testgroup.TestType, err error) { result = &testgroup.TestType{} diff --git a/staging/src/k8s.io/kube-gen/cmd/informer-gen/generators/BUILD b/staging/src/k8s.io/kube-gen/cmd/informer-gen/generators/BUILD index 5d2e3861c4c..50f884a7444 100644 --- a/staging/src/k8s.io/kube-gen/cmd/informer-gen/generators/BUILD +++ b/staging/src/k8s.io/kube-gen/cmd/informer-gen/generators/BUILD @@ -29,6 +29,7 @@ go_library( "//vendor/k8s.io/gengo/generator:go_default_library", "//vendor/k8s.io/gengo/namer:go_default_library", "//vendor/k8s.io/gengo/types:go_default_library", + "//vendor/k8s.io/kube-gen/cmd/client-gen/generators/util:go_default_library", "//vendor/k8s.io/kube-gen/cmd/client-gen/types:go_default_library", ], ) diff --git a/staging/src/k8s.io/kube-gen/cmd/informer-gen/generators/informer.go b/staging/src/k8s.io/kube-gen/cmd/informer-gen/generators/informer.go index 838f68e2700..b06917b1e34 100644 --- a/staging/src/k8s.io/kube-gen/cmd/informer-gen/generators/informer.go +++ b/staging/src/k8s.io/kube-gen/cmd/informer-gen/generators/informer.go @@ -24,6 +24,8 @@ import ( "k8s.io/gengo/generator" "k8s.io/gengo/namer" "k8s.io/gengo/types" + + "k8s.io/kube-gen/cmd/client-gen/generators/util" clientgentypes "k8s.io/kube-gen/cmd/client-gen/types" "github.com/golang/glog" @@ -69,6 +71,11 @@ func (g *informerGenerator) GenerateType(c *generator.Context, t *types.Type, w clientSetInterface := c.Universe.Type(types.Name{Package: g.clientSetPackage, Name: "Interface"}) informerFor := "InformerFor" + tags, err := util.ParseClientGenTags(t.SecondClosestCommentLines) + if err != nil { + return err + } + m := map[string]interface{}{ "apiScheme": c.Universe.Type(apiScheme), "cacheIndexers": c.Universe.Type(cacheIndexers), @@ -84,7 +91,7 @@ func (g *informerGenerator) GenerateType(c *generator.Context, t *types.Type, w "listOptions": c.Universe.Type(listOptions), "lister": c.Universe.Type(types.Name{Package: listerPackage, Name: t.Name.Name + "Lister"}), "namespaceAll": c.Universe.Type(metav1NamespaceAll), - "namespaced": !extractBoolTagOrDie("nonNamespaced", t.SecondClosestCommentLines), + "namespaced": !tags.NonNamespaced, "newLister": c.Universe.Function(types.Name{Package: listerPackage, Name: "New" + t.Name.Name + "Lister"}), "runtimeObject": c.Universe.Type(runtimeObject), "timeDuration": c.Universe.Type(timeDuration), diff --git a/staging/src/k8s.io/kube-gen/cmd/informer-gen/generators/packages.go b/staging/src/k8s.io/kube-gen/cmd/informer-gen/generators/packages.go index 19ddab6bf25..f74206449ec 100644 --- a/staging/src/k8s.io/kube-gen/cmd/informer-gen/generators/packages.go +++ b/staging/src/k8s.io/kube-gen/cmd/informer-gen/generators/packages.go @@ -25,6 +25,8 @@ import ( "k8s.io/gengo/generator" "k8s.io/gengo/namer" "k8s.io/gengo/types" + + "k8s.io/kube-gen/cmd/client-gen/generators/util" clientgentypes "k8s.io/kube-gen/cmd/client-gen/types" "github.com/golang/glog" @@ -69,8 +71,7 @@ func generatedBy() string { func objectMetaForPackage(p *types.Package) (*types.Type, bool, error) { generatingForPackage := false for _, t := range p.Types { - // filter out types which dont have genclient=true. - if extractBoolTagOrDie("genclient", t.SecondClosestCommentLines) == false { + if !util.MustParseClientGenTags(t.SecondClosestCommentLines).GenerateClient { continue } generatingForPackage = true @@ -170,12 +171,8 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat var typesToGenerate []*types.Type for _, t := range p.Types { - // filter out types which dont have genclient=true. - if extractBoolTagOrDie("genclient", t.SecondClosestCommentLines) == false { - continue - } - // filter out types which have noMethods - if extractBoolTagOrDie("noMethods", t.SecondClosestCommentLines) == true { + tags := util.MustParseClientGenTags(t.SecondClosestCommentLines) + if !tags.GenerateClient || tags.NoVerbs { continue } @@ -307,8 +304,7 @@ func groupPackage(basePackage string, groupVersions clientgentypes.GroupVersions return generators }, FilterFunc: func(c *generator.Context, t *types.Type) bool { - // piggy-back on types that are tagged for client-gen - return extractBoolTagOrDie("genclient", t.SecondClosestCommentLines) == true + return util.MustParseClientGenTags(t.SecondClosestCommentLines).GenerateClient }, } } @@ -348,8 +344,7 @@ func versionPackage(basePackage string, gv clientgentypes.GroupVersion, boilerpl return generators }, FilterFunc: func(c *generator.Context, t *types.Type) bool { - // piggy-back on types that are tagged for client-gen - return extractBoolTagOrDie("genclient", t.SecondClosestCommentLines) == true + return util.MustParseClientGenTags(t.SecondClosestCommentLines).GenerateClient }, } } diff --git a/staging/src/k8s.io/kube-gen/cmd/lister-gen/generators/BUILD b/staging/src/k8s.io/kube-gen/cmd/lister-gen/generators/BUILD index 3544fb3f77b..dca89866e8e 100644 --- a/staging/src/k8s.io/kube-gen/cmd/lister-gen/generators/BUILD +++ b/staging/src/k8s.io/kube-gen/cmd/lister-gen/generators/BUILD @@ -21,6 +21,7 @@ go_library( "//vendor/k8s.io/gengo/generator:go_default_library", "//vendor/k8s.io/gengo/namer:go_default_library", "//vendor/k8s.io/gengo/types:go_default_library", + "//vendor/k8s.io/kube-gen/cmd/client-gen/generators/util:go_default_library", "//vendor/k8s.io/kube-gen/cmd/client-gen/types:go_default_library", ], ) diff --git a/staging/src/k8s.io/kube-gen/cmd/lister-gen/generators/expansion.go b/staging/src/k8s.io/kube-gen/cmd/lister-gen/generators/expansion.go index 67ac8322110..c091982d196 100644 --- a/staging/src/k8s.io/kube-gen/cmd/lister-gen/generators/expansion.go +++ b/staging/src/k8s.io/kube-gen/cmd/lister-gen/generators/expansion.go @@ -24,6 +24,8 @@ import ( "k8s.io/gengo/generator" "k8s.io/gengo/types" + + "k8s.io/kube-gen/cmd/client-gen/generators/util" ) // expansionGenerator produces a file for a expansion interfaces. @@ -41,10 +43,10 @@ func (g *expansionGenerator) Filter(c *generator.Context, t *types.Type) bool { func (g *expansionGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { sw := generator.NewSnippetWriter(w, c, "$", "$") for _, t := range g.types { + tags := util.MustParseClientGenTags(t.SecondClosestCommentLines) if _, err := os.Stat(filepath.Join(g.packagePath, strings.ToLower(t.Name.Name+"_expansion.go"))); os.IsNotExist(err) { sw.Do(expansionInterfaceTemplate, t) - namespaced := !extractBoolTagOrDie("nonNamespaced", t.SecondClosestCommentLines) - if namespaced { + if !tags.NonNamespaced { sw.Do(namespacedExpansionInterfaceTemplate, t) } } diff --git a/staging/src/k8s.io/kube-gen/cmd/lister-gen/generators/lister.go b/staging/src/k8s.io/kube-gen/cmd/lister-gen/generators/lister.go index 45bd9dbc329..44000b93e7a 100644 --- a/staging/src/k8s.io/kube-gen/cmd/lister-gen/generators/lister.go +++ b/staging/src/k8s.io/kube-gen/cmd/lister-gen/generators/lister.go @@ -26,6 +26,8 @@ import ( "k8s.io/gengo/generator" "k8s.io/gengo/namer" "k8s.io/gengo/types" + + "k8s.io/kube-gen/cmd/client-gen/generators/util" clientgentypes "k8s.io/kube-gen/cmd/client-gen/types" "github.com/golang/glog" @@ -115,8 +117,7 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat var typesToGenerate []*types.Type for _, t := range p.Types { - // filter out types which dont have genclient=true. - if extractBoolTagOrDie("genclient", t.SecondClosestCommentLines) == false { + if !util.MustParseClientGenTags(t.SecondClosestCommentLines).GenerateClient { continue } typesToGenerate = append(typesToGenerate, t) @@ -154,8 +155,7 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat return generators }, FilterFunc: func(c *generator.Context, t *types.Type) bool { - // piggy-back on types that are tagged for client-gen - return extractBoolTagOrDie("genclient", t.SecondClosestCommentLines) == true + return util.MustParseClientGenTags(t.SecondClosestCommentLines).GenerateClient }, }) } @@ -168,7 +168,7 @@ func objectMetaForPackage(p *types.Package) (*types.Type, bool, error) { generatingForPackage := false for _, t := range p.Types { // filter out types which dont have genclient=true. - if extractBoolTagOrDie("genclient", t.SecondClosestCommentLines) == false { + if !util.MustParseClientGenTags(t.SecondClosestCommentLines).GenerateClient { continue } generatingForPackage = true @@ -232,27 +232,32 @@ func (g *listerGenerator) GenerateType(c *generator.Context, t *types.Type, w io "objectMeta": g.objectMeta, } - namespaced := !extractBoolTagOrDie("nonNamespaced", t.SecondClosestCommentLines) - if namespaced { - sw.Do(typeListerInterface, m) - } else { + tags, err := util.ParseClientGenTags(t.SecondClosestCommentLines) + if err != nil { + return err + } + + if tags.NonNamespaced { sw.Do(typeListerInterface_NonNamespaced, m) + } else { + sw.Do(typeListerInterface, m) } sw.Do(typeListerStruct, m) sw.Do(typeListerConstructor, m) sw.Do(typeLister_List, m) - if namespaced { - sw.Do(typeLister_NamespaceLister, m) - sw.Do(namespaceListerInterface, m) - sw.Do(namespaceListerStruct, m) - sw.Do(namespaceLister_List, m) - sw.Do(namespaceLister_Get, m) - } else { + if tags.NonNamespaced { sw.Do(typeLister_NonNamespacedGet, m) + return sw.Error() } + sw.Do(typeLister_NamespaceLister, m) + sw.Do(namespaceListerInterface, m) + sw.Do(namespaceListerStruct, m) + sw.Do(namespaceLister_List, m) + sw.Do(namespaceLister_Get, m) + return sw.Error() }