mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 11:21:47 +00:00
add prerelease-lifecycle generator for beta API types
This commit is contained in:
parent
88c5f64763
commit
4b0080d71f
@ -18,6 +18,7 @@ filegroup(
|
||||
"//staging/src/k8s.io/code-generator/cmd/informer-gen:all-srcs",
|
||||
"//staging/src/k8s.io/code-generator/cmd/lister-gen:all-srcs",
|
||||
"//staging/src/k8s.io/code-generator/cmd/openapi-gen:all-srcs",
|
||||
"//staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen:all-srcs",
|
||||
"//staging/src/k8s.io/code-generator/cmd/register-gen:all-srcs",
|
||||
"//staging/src/k8s.io/code-generator/cmd/set-gen:all-srcs",
|
||||
"//staging/src/k8s.io/code-generator/hack:all-srcs",
|
||||
|
@ -0,0 +1,41 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["main.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/k8s.io/code-generator/cmd/prerelease-lifecycle-gen",
|
||||
importpath = "k8s.io/code-generator/cmd/prerelease-lifecycle-gen",
|
||||
visibility = ["//visibility:private"],
|
||||
deps = [
|
||||
"//staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/args:go_default_library",
|
||||
"//staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators:go_default_library",
|
||||
"//staging/src/k8s.io/code-generator/pkg/util:go_default_library",
|
||||
"//vendor/github.com/spf13/pflag:go_default_library",
|
||||
"//vendor/k8s.io/gengo/args:go_default_library",
|
||||
"//vendor/k8s.io/klog:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_binary(
|
||||
name = "status-gen",
|
||||
embed = [":go_default_library"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [
|
||||
":package-srcs",
|
||||
"//staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/args:all-srcs",
|
||||
"//staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators:all-srcs",
|
||||
],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
@ -0,0 +1,28 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["args.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/args",
|
||||
importpath = "k8s.io/code-generator/cmd/prerelease-lifecycle-gen/args",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators:go_default_library",
|
||||
"//vendor/github.com/spf13/pflag:go_default_library",
|
||||
"//vendor/k8s.io/gengo/args:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
Copyright 2020 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 args
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
statusgenerators "k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators"
|
||||
"k8s.io/gengo/args"
|
||||
)
|
||||
|
||||
// CustomArgs is used by the gengo framework to pass args specific to this generator.
|
||||
type CustomArgs statusgenerators.CustomArgs
|
||||
|
||||
// NewDefaults returns default arguments for the generator.
|
||||
func NewDefaults() (*args.GeneratorArgs, *CustomArgs) {
|
||||
genericArgs := args.Default().WithoutDefaultFlagParsing()
|
||||
customArgs := &CustomArgs{}
|
||||
genericArgs.CustomArgs = (*statusgenerators.CustomArgs)(customArgs) // convert to upstream type to make type-casts work there
|
||||
genericArgs.OutputFileBaseName = "zz_prerelease_lifecycle_generated"
|
||||
return genericArgs, customArgs
|
||||
}
|
||||
|
||||
// AddFlags add the generator flags to the flag set.
|
||||
func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet) {
|
||||
}
|
||||
|
||||
// Validate checks the given arguments.
|
||||
func Validate(genericArgs *args.GeneratorArgs) error {
|
||||
_ = genericArgs.CustomArgs.(*statusgenerators.CustomArgs)
|
||||
|
||||
if len(genericArgs.OutputFileBaseName) == 0 {
|
||||
return fmt.Errorf("output file base name cannot be empty")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
Copyright 2020 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.
|
||||
*/
|
||||
|
||||
// prerelease-lifecycle-gen is a tool for auto-generating api-status.csv files.
|
||||
//
|
||||
// Given a list of input directories, it will create a zz_api_status.go file for all beta APIs which indicates the kinds,
|
||||
// the release it was introduced, the release it will be deprecated, and the release it will be removed.
|
||||
//
|
||||
// Generation is governed by comment tags in the source. Any package may
|
||||
// request Status generation by including a comment in the file-comments of
|
||||
// one file, of the form:
|
||||
// // +k8s:prerelease-lifecycle-gen=package
|
||||
//
|
||||
// // +k8s:prerelease-lifecycle-gen:introduced=1.19
|
||||
// // +k8s:prerelease-lifecycle-gen:to-be-deprecated=1.22
|
||||
// // +k8s:prerelease-lifecycle-gen:to-be-removed=1.25
|
||||
//
|
||||
// Note that registration is a whole-package option, and is not available for
|
||||
// individual types.
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
generatorargs "k8s.io/code-generator/cmd/prerelease-lifecycle-gen/args"
|
||||
statusgenerators "k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators"
|
||||
"k8s.io/code-generator/pkg/util"
|
||||
"k8s.io/gengo/args"
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
func main() {
|
||||
klog.InitFlags(nil)
|
||||
genericArgs, customArgs := generatorargs.NewDefaults()
|
||||
|
||||
// Override defaults.
|
||||
// TODO: move this out of prerelease-lifecycle-gen
|
||||
genericArgs.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(), util.BoilerplatePath())
|
||||
|
||||
genericArgs.AddFlags(pflag.CommandLine)
|
||||
customArgs.AddFlags(pflag.CommandLine)
|
||||
flag.Set("logtostderr", "true")
|
||||
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
|
||||
pflag.Parse()
|
||||
|
||||
if err := generatorargs.Validate(genericArgs); err != nil {
|
||||
klog.Fatalf("Error: %v", err)
|
||||
}
|
||||
|
||||
// Run it.
|
||||
if err := genericArgs.Execute(
|
||||
statusgenerators.NameSystems(),
|
||||
statusgenerators.DefaultNameSystem(),
|
||||
statusgenerators.Packages,
|
||||
); err != nil {
|
||||
klog.Fatalf("Error: %v", err)
|
||||
}
|
||||
klog.V(2).Info("Completed successfully.")
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["status.go"],
|
||||
importmap = "k8s.io/kubernetes/vendor/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators",
|
||||
importpath = "k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/k8s.io/gengo/args:go_default_library",
|
||||
"//vendor/k8s.io/gengo/examples/set-gen/sets: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/klog:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "package-srcs",
|
||||
srcs = glob(["**"]),
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:private"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "all-srcs",
|
||||
srcs = [":package-srcs"],
|
||||
tags = ["automanaged"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
@ -0,0 +1,438 @@
|
||||
/*
|
||||
Copyright 2020 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 prereleaselifecyclegenerators
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"k8s.io/gengo/args"
|
||||
"k8s.io/gengo/examples/set-gen/sets"
|
||||
"k8s.io/gengo/generator"
|
||||
"k8s.io/gengo/namer"
|
||||
"k8s.io/gengo/types"
|
||||
|
||||
"k8s.io/klog"
|
||||
)
|
||||
|
||||
// CustomArgs is used tby the go2idl framework to pass args specific to this generator.
|
||||
type CustomArgs struct {
|
||||
}
|
||||
|
||||
// This is the comment tag that carries parameters for API status generation. Because the cadence is fixed, we can predict
|
||||
// with near certainty when this lifecycle happens as the API is introduced.
|
||||
const (
|
||||
tagEnabledName = "k8s:prerelease-lifecycle-gen"
|
||||
introducedTagName = tagEnabledName + ":introduced"
|
||||
deprecatedTagName = tagEnabledName + ":deprecated"
|
||||
removedTagName = tagEnabledName + ":removed"
|
||||
)
|
||||
|
||||
// enabledTagValue holds parameters from a tagName tag.
|
||||
type tagValue struct {
|
||||
value string
|
||||
}
|
||||
|
||||
func extractEnabledTypeTag(t *types.Type) *tagValue {
|
||||
comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...)
|
||||
return extractTag(tagEnabledName, comments)
|
||||
}
|
||||
|
||||
func tagExists(tagName string, t *types.Type) bool {
|
||||
comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...)
|
||||
rawTag := extractTag(tagName, comments)
|
||||
return rawTag != nil
|
||||
}
|
||||
|
||||
func extractKubeVersionTag(tagName string, t *types.Type) (*tagValue, int64, int64, error) {
|
||||
comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...)
|
||||
rawTag := extractTag(tagName, comments)
|
||||
if rawTag == nil || len(rawTag.value) == 0 {
|
||||
return nil, -1, -1, fmt.Errorf("%v missing %v=Version tag", t, tagName)
|
||||
}
|
||||
|
||||
splitValue := strings.Split(rawTag.value, ".")
|
||||
if len(splitValue) != 2 || len(splitValue[0]) == 0 || len(splitValue[0]) == 0 {
|
||||
return nil, -1, -1, fmt.Errorf("%v format must match %v=xx.yy tag", t, tagName)
|
||||
}
|
||||
major, err := strconv.ParseInt(splitValue[0], 10, 64)
|
||||
if err != nil {
|
||||
return nil, -1, -1, fmt.Errorf("%v format must match %v=xx.yy : %w", t, tagName, err)
|
||||
}
|
||||
minor, err := strconv.ParseInt(splitValue[1], 10, 64)
|
||||
if err != nil {
|
||||
return nil, -1, -1, fmt.Errorf("%v format must match %v=xx.yy : %w", t, tagName, err)
|
||||
}
|
||||
|
||||
return rawTag, major, minor, nil
|
||||
}
|
||||
|
||||
func extractIntroducedTag(t *types.Type) (*tagValue, int64, int64, error) {
|
||||
return extractKubeVersionTag(introducedTagName, t)
|
||||
}
|
||||
|
||||
func extractDeprecatedTag(t *types.Type) (*tagValue, int64, int64, error) {
|
||||
return extractKubeVersionTag(deprecatedTagName, t)
|
||||
}
|
||||
|
||||
func extractRemovedTag(t *types.Type) (*tagValue, int64, int64, error) {
|
||||
return extractKubeVersionTag(removedTagName, t)
|
||||
}
|
||||
|
||||
func extractTag(tagName string, comments []string) *tagValue {
|
||||
tagVals := types.ExtractCommentTags("+", comments)[tagName]
|
||||
if tagVals == nil {
|
||||
// No match for the tag.
|
||||
return nil
|
||||
}
|
||||
// If there are multiple values, abort.
|
||||
if len(tagVals) > 1 {
|
||||
klog.Fatalf("Found %d %s tags: %q", len(tagVals), tagName, tagVals)
|
||||
}
|
||||
|
||||
// If we got here we are returning something.
|
||||
tag := &tagValue{}
|
||||
|
||||
// Get the primary value.
|
||||
parts := strings.Split(tagVals[0], ",")
|
||||
if len(parts) >= 1 {
|
||||
tag.value = parts[0]
|
||||
}
|
||||
|
||||
// Parse extra arguments.
|
||||
parts = parts[1:]
|
||||
for i := range parts {
|
||||
kv := strings.SplitN(parts[i], "=", 2)
|
||||
k := kv[0]
|
||||
//v := ""
|
||||
//if len(kv) == 2 {
|
||||
// v = kv[1]
|
||||
//}
|
||||
switch k {
|
||||
//case "register":
|
||||
// if v != "false" {
|
||||
// tag.register = true
|
||||
// }
|
||||
default:
|
||||
klog.Fatalf("Unsupported %s param: %q", tagName, parts[i])
|
||||
}
|
||||
}
|
||||
return tag
|
||||
}
|
||||
|
||||
// NameSystems returns the name system used by the generators in this package.
|
||||
func NameSystems() namer.NameSystems {
|
||||
return namer.NameSystems{
|
||||
"public": namer.NewPublicNamer(1),
|
||||
"raw": namer.NewRawNamer("", nil),
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultNameSystem returns the default name system for ordering the types to be
|
||||
// processed by the generators in this package.
|
||||
func DefaultNameSystem() string {
|
||||
return "public"
|
||||
}
|
||||
|
||||
// Packages makes the package definition.
|
||||
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
|
||||
boilerplate, err := arguments.LoadGoBoilerplate()
|
||||
if err != nil {
|
||||
klog.Fatalf("Failed loading boilerplate: %v", err)
|
||||
}
|
||||
|
||||
inputs := sets.NewString(context.Inputs...)
|
||||
packages := generator.Packages{}
|
||||
header := append([]byte(fmt.Sprintf("// +build !%s\n\n", arguments.GeneratedBuildTag)), boilerplate...)
|
||||
|
||||
for i := range inputs {
|
||||
klog.V(5).Infof("Considering pkg %q", i)
|
||||
pkg := context.Universe[i]
|
||||
if pkg == nil {
|
||||
// If the input had no Go files, for example.
|
||||
continue
|
||||
}
|
||||
|
||||
ptag := extractTag(tagEnabledName, pkg.Comments)
|
||||
pkgNeedsGeneration := false
|
||||
if ptag != nil {
|
||||
pkgNeedsGeneration, err = strconv.ParseBool(ptag.value)
|
||||
if err != nil {
|
||||
klog.Fatalf("Package %v: unsupported %s value: %q :%w", i, tagEnabledName, ptag.value, err)
|
||||
}
|
||||
}
|
||||
if !pkgNeedsGeneration {
|
||||
klog.V(5).Infof(" skipping package")
|
||||
continue
|
||||
}
|
||||
klog.Infof("Generating package %q", pkg.Path)
|
||||
|
||||
// If the pkg-scoped tag says to generate, we can skip scanning types.
|
||||
if !pkgNeedsGeneration {
|
||||
// If the pkg-scoped tag did not exist, scan all types for one that
|
||||
// explicitly wants generation.
|
||||
for _, t := range pkg.Types {
|
||||
klog.V(5).Infof(" considering type %q", t.Name.String())
|
||||
ttag := extractEnabledTypeTag(t)
|
||||
if ttag != nil && ttag.value == "true" {
|
||||
klog.V(5).Infof(" tag=true")
|
||||
if !isAPIType(t) {
|
||||
klog.Fatalf("Type %v requests deepcopy generation but is not copyable", t)
|
||||
}
|
||||
pkgNeedsGeneration = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if pkgNeedsGeneration {
|
||||
path := pkg.Path
|
||||
// if the source path is within a /vendor/ directory (for example,
|
||||
// k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/apis/meta/v1), allow
|
||||
// generation to output to the proper relative path (under vendor).
|
||||
// Otherwise, the generator will create the file in the wrong location
|
||||
// in the output directory.
|
||||
// TODO: build a more fundamental concept in gengo for dealing with modifications
|
||||
// to vendored packages.
|
||||
if strings.HasPrefix(pkg.SourcePath, arguments.OutputBase) {
|
||||
expandedPath := strings.TrimPrefix(pkg.SourcePath, arguments.OutputBase)
|
||||
if strings.Contains(expandedPath, "/vendor/") {
|
||||
path = expandedPath
|
||||
}
|
||||
}
|
||||
packages = append(packages,
|
||||
&generator.DefaultPackage{
|
||||
PackageName: strings.Split(filepath.Base(pkg.Path), ".")[0],
|
||||
PackagePath: path,
|
||||
HeaderText: header,
|
||||
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
|
||||
return []generator.Generator{
|
||||
NewPrereleaseLifecycleGen(arguments.OutputFileBaseName, pkg.Path),
|
||||
}
|
||||
},
|
||||
FilterFunc: func(c *generator.Context, t *types.Type) bool {
|
||||
return t.Name.Package == pkg.Path
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
return packages
|
||||
}
|
||||
|
||||
// genDeepCopy produces a file with autogenerated deep-copy functions.
|
||||
type genPreleaseLifecycle struct {
|
||||
generator.DefaultGen
|
||||
targetPackage string
|
||||
imports namer.ImportTracker
|
||||
typesForInit []*types.Type
|
||||
}
|
||||
|
||||
// NewPrereleaseLifecycleGen creates a generator for the prerelease-lifecycle-generator
|
||||
func NewPrereleaseLifecycleGen(sanitizedName, targetPackage string) generator.Generator {
|
||||
return &genPreleaseLifecycle{
|
||||
DefaultGen: generator.DefaultGen{
|
||||
OptionalName: sanitizedName,
|
||||
},
|
||||
targetPackage: targetPackage,
|
||||
imports: generator.NewImportTracker(),
|
||||
typesForInit: make([]*types.Type, 0),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *genPreleaseLifecycle) Namers(c *generator.Context) namer.NameSystems {
|
||||
return namer.NameSystems{
|
||||
"public": namer.NewPublicNamer(1),
|
||||
"intrapackage": namer.NewPublicNamer(0),
|
||||
"raw": namer.NewRawNamer("", nil),
|
||||
}
|
||||
}
|
||||
|
||||
func (g *genPreleaseLifecycle) Filter(c *generator.Context, t *types.Type) bool {
|
||||
// Filter out types not being processed or not copyable within the package.
|
||||
if !isAPIType(t) {
|
||||
klog.V(2).Infof("Type %v is not a valid target for status", t)
|
||||
return false
|
||||
}
|
||||
g.typesForInit = append(g.typesForInit, t)
|
||||
return true
|
||||
}
|
||||
|
||||
// versionMethod returns the signature of an <methodName>() method, nil or an error
|
||||
// if the type is wrong. Introduced() allows more efficient deep copy
|
||||
// implementations to be defined by the type's author. The correct signature
|
||||
// func (t *T) <methodName>() string
|
||||
func versionMethod(methodName string, t *types.Type) (*types.Signature, error) {
|
||||
f, found := t.Methods[methodName]
|
||||
if !found {
|
||||
return nil, nil
|
||||
}
|
||||
if len(f.Signature.Parameters) != 0 {
|
||||
return nil, fmt.Errorf("type %v: invalid %v signature, expected no parameters", t, methodName)
|
||||
}
|
||||
if len(f.Signature.Results) != 2 {
|
||||
return nil, fmt.Errorf("type %v: invalid %v signature, expected exactly two result types", t, methodName)
|
||||
}
|
||||
|
||||
ptrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Kind == types.Pointer && f.Signature.Receiver.Elem.Name == t.Name
|
||||
nonPtrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Name == t.Name
|
||||
|
||||
if !ptrRcvr && !nonPtrRcvr {
|
||||
// this should never happen
|
||||
return nil, fmt.Errorf("type %v: invalid %v signature, expected a receiver of type %s or *%s", t, methodName, t.Name.Name, t.Name.Name)
|
||||
}
|
||||
|
||||
return f.Signature, nil
|
||||
}
|
||||
|
||||
// versionedMethodOrDie returns the signature of a <methodName>() method, nil or calls klog.Fatalf
|
||||
// if the type is wrong.
|
||||
func versionedMethodOrDie(methodName string, t *types.Type) *types.Signature {
|
||||
ret, err := versionMethod(methodName, t)
|
||||
if err != nil {
|
||||
klog.Fatal(err)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// isAPIType indicates whether or not a type could be used to serve an API. That means, "does it have TypeMeta".
|
||||
// This doesn't mean the type is served, but we will handle all TypeMeta types.
|
||||
func isAPIType(t *types.Type) bool {
|
||||
// Filter out private types.
|
||||
if namer.IsPrivateGoName(t.Name.Name) {
|
||||
return false
|
||||
}
|
||||
|
||||
if t.Kind != types.Struct {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, currMember := range t.Members {
|
||||
if currMember.Embedded && currMember.Name == "TypeMeta" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if t.Kind == types.Alias {
|
||||
return isAPIType(t.Underlying)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (g *genPreleaseLifecycle) isOtherPackage(pkg string) bool {
|
||||
if pkg == g.targetPackage {
|
||||
return false
|
||||
}
|
||||
if strings.HasSuffix(pkg, "\""+g.targetPackage+"\"") {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *genPreleaseLifecycle) Imports(c *generator.Context) (imports []string) {
|
||||
importLines := []string{}
|
||||
for _, singleImport := range g.imports.ImportLines() {
|
||||
if g.isOtherPackage(singleImport) {
|
||||
importLines = append(importLines, singleImport)
|
||||
}
|
||||
}
|
||||
return importLines
|
||||
}
|
||||
|
||||
func argsFromType(t *types.Type) (generator.Args, error) {
|
||||
a := generator.Args{
|
||||
"type": t,
|
||||
}
|
||||
_, introducedMajor, introducedMinor, err := extractIntroducedTag(t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
a = a.
|
||||
With("introducedMajor", introducedMajor).
|
||||
With("introducedMinor", introducedMinor)
|
||||
|
||||
// compute based on our policy
|
||||
deprecatedMajor := introducedMajor
|
||||
deprecatedMinor := introducedMinor + 3
|
||||
// if someone intentionally override the deprecation release
|
||||
if tagExists(deprecatedTagName, t) {
|
||||
_, deprecatedMajor, deprecatedMinor, err = extractDeprecatedTag(t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
a = a.
|
||||
With("deprecatedMajor", deprecatedMajor).
|
||||
With("deprecatedMinor", deprecatedMinor)
|
||||
|
||||
// compute based on our policy
|
||||
removedMajor := deprecatedMajor
|
||||
removedMinor := deprecatedMinor + 3
|
||||
// if someone intentionally override the removed release
|
||||
if tagExists(removedTagName, t) {
|
||||
_, removedMajor, removedMinor, err = extractRemovedTag(t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
a = a.
|
||||
With("removedMajor", removedMajor).
|
||||
With("removedMinor", removedMinor)
|
||||
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func (g *genPreleaseLifecycle) Init(c *generator.Context, w io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *genPreleaseLifecycle) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
|
||||
klog.Infof("Generating prerelease-lifecycle for type %v", t)
|
||||
|
||||
sw := generator.NewSnippetWriter(w, c, "$", "$")
|
||||
args, err := argsFromType(t)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if versionedMethodOrDie("Introduced", t) == nil {
|
||||
sw.Do("// Introduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison.\n", args)
|
||||
sw.Do("// It is controlled by \""+introducedTagName+"\" tags in types.go.\n", args)
|
||||
sw.Do("func (in *$.type|intrapackage$) Introduced() (int64, int64) {\n", args)
|
||||
sw.Do(" return $.introducedMajor$, $.introducedMinor$\n", args)
|
||||
sw.Do("}\n\n", nil)
|
||||
}
|
||||
if versionedMethodOrDie("Deprecated", t) == nil {
|
||||
sw.Do("// Deprecated is an autogenerated function, returning the release in which the API struct was or will be deprecated as int versions of major and minor for comparison.\n", args)
|
||||
sw.Do("// It is controlled by \""+deprecatedTagName+"\" tags in types.go or \""+introducedTagName+"\" plus three minor.\n", args)
|
||||
sw.Do("func (in *$.type|intrapackage$) Deprecated() (int64, int64) {\n", args)
|
||||
sw.Do(" return $.deprecatedMajor$, $.deprecatedMinor$\n", args)
|
||||
sw.Do("}\n\n", nil)
|
||||
}
|
||||
if versionedMethodOrDie("Removed", t) == nil {
|
||||
sw.Do("// Removed is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison.\n", args)
|
||||
sw.Do("// It is controlled by \""+removedTagName+"\" tags in types.go or \""+deprecatedTagName+"\" plus three minor.\n", args)
|
||||
sw.Do("func (in *$.type|intrapackage$) Removed() (int64, int64) {\n", args)
|
||||
sw.Do(" return $.removedMajor$, $.removedMinor$\n", args)
|
||||
sw.Do("}\n\n", nil)
|
||||
}
|
||||
|
||||
return sw.Error()
|
||||
}
|
Loading…
Reference in New Issue
Block a user