1
0
mirror of https://github.com/kubernetes-sigs/descheduler.git synced 2026-01-28 14:41:10 +01:00

[release 1.30] upgrade kubernetes version and docs

Signed-off-by: Amir Alavi <amir.alavi@zendesk.com>
This commit is contained in:
Amir Alavi
2024-05-14 10:08:08 -04:00
parent fda4c96937
commit fca4a0970f
496 changed files with 56662 additions and 16231 deletions

View File

@@ -18,17 +18,18 @@ package args
import (
"fmt"
"path"
"github.com/spf13/pflag"
"k8s.io/gengo/args"
"k8s.io/gengo/types"
codegenutil "k8s.io/code-generator/pkg/util"
"k8s.io/gengo/v2/types"
)
// CustomArgs is a wrapper for arguments to applyconfiguration-gen.
type CustomArgs struct {
// Args is a wrapper for arguments to applyconfiguration-gen.
type Args struct {
OutputDir string // must be a directory path
OutputPkg string // must be a Go import-path
GoHeaderFile string
// ExternalApplyConfigurations provides the locations of externally generated
// apply configuration types for types referenced by the go structs provided as input.
// Locations are provided as a comma separated list of <package>.<typeName>:<applyconfiguration-package>
@@ -44,10 +45,9 @@ type CustomArgs struct {
OpenAPISchemaFilePath string
}
// NewDefaults returns default arguments for the generator.
func NewDefaults() (*args.GeneratorArgs, *CustomArgs) {
genericArgs := args.Default().WithoutDefaultFlagParsing()
customArgs := &CustomArgs{
// New returns default arguments for the generator.
func New() *Args {
return &Args{
ExternalApplyConfigurations: map[types.Name]string{
// Always include the applyconfigurations we've generated in client-go. They are sufficient for the vast majority of use cases.
{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "Condition"}: "k8s.io/client-go/applyconfigurations/meta/v1",
@@ -60,27 +60,29 @@ func NewDefaults() (*args.GeneratorArgs, *CustomArgs) {
{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "TypeMeta"}: "k8s.io/client-go/applyconfigurations/meta/v1",
},
}
genericArgs.CustomArgs = customArgs
if pkg := codegenutil.CurrentPackage(); len(pkg) != 0 {
genericArgs.OutputPackagePath = path.Join(pkg, "pkg/client/applyconfigurations")
}
return genericArgs, customArgs
}
func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet, inputBase string) {
fs.Var(NewExternalApplyConfigurationValue(&ca.ExternalApplyConfigurations, nil), "external-applyconfigurations",
func (args *Args) AddFlags(fs *pflag.FlagSet, inputBase string) {
fs.StringVar(&args.OutputDir, "output-dir", "",
"the base directory under which to generate results")
fs.StringVar(&args.OutputPkg, "output-pkg", args.OutputPkg,
"the Go import-path of the generated results")
fs.StringVar(&args.GoHeaderFile, "go-header-file", "",
"the path to a file containing boilerplate header text; the string \"YEAR\" will be replaced with the current 4-digit year")
fs.Var(NewExternalApplyConfigurationValue(&args.ExternalApplyConfigurations, nil), "external-applyconfigurations",
"list of comma separated external apply configurations locations in <type-package>.<type-name>:<applyconfiguration-package> form."+
"For example: k8s.io/api/apps/v1.Deployment:k8s.io/client-go/applyconfigurations/apps/v1")
fs.StringVar(&ca.OpenAPISchemaFilePath, "openapi-schema", "",
fs.StringVar(&args.OpenAPISchemaFilePath, "openapi-schema", "",
"path to the openapi schema containing all the types that apply configurations will be generated for")
}
// Validate checks the given arguments.
func Validate(genericArgs *args.GeneratorArgs) error {
if len(genericArgs.OutputPackagePath) == 0 {
return fmt.Errorf("output package cannot be empty")
func (args *Args) Validate() error {
if len(args.OutputDir) == 0 {
return fmt.Errorf("--output-dir must be specified")
}
if len(args.OutputPkg) == 0 {
return fmt.Errorf("--output-pkg must be specified")
}
return nil
}

View File

@@ -23,7 +23,7 @@ import (
"fmt"
"strings"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/types"
)
type externalApplyConfigurationValue struct {

View File

@@ -18,11 +18,12 @@ package generators
import (
"io"
"path"
"strings"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
"k8s.io/klog/v2"
"k8s.io/code-generator/cmd/client-gen/generators/util"
@@ -31,14 +32,14 @@ import (
// applyConfigurationGenerator produces apply configurations for a given GroupVersion and type.
type applyConfigurationGenerator struct {
generator.DefaultGen
outputPackage string
localPackage types.Name
groupVersion clientgentypes.GroupVersion
applyConfig applyConfig
imports namer.ImportTracker
refGraph refGraph
openAPIType *string // if absent, extraction function cannot be generated
generator.GoGenerator
// outPkgBase is the base package, under which the "internal" and GV-specific subdirs live
outPkgBase string // must be a Go import-path
groupVersion clientgentypes.GroupVersion
applyConfig applyConfig
imports namer.ImportTracker
refGraph refGraph
openAPIType *string // if absent, extraction function cannot be generated
}
var _ generator.Generator = &applyConfigurationGenerator{}
@@ -48,8 +49,9 @@ func (g *applyConfigurationGenerator) Filter(_ *generator.Context, t *types.Type
}
func (g *applyConfigurationGenerator) Namers(*generator.Context) namer.NameSystems {
localPkg := path.Join(g.outPkgBase, g.groupVersion.Group.PackageName(), g.groupVersion.Version.PackageName())
return namer.NameSystems{
"raw": namer.NewRawNamer(g.localPackage.Package, g.imports),
"raw": namer.NewRawNamer(localPkg, g.imports),
"singularKind": namer.NewPublicNamer(0),
}
}
@@ -90,7 +92,7 @@ func (g *applyConfigurationGenerator) GenerateType(c *generator.Context, t *type
Tags: genclientTags(t),
APIVersion: g.groupVersion.ToAPIVersion(),
ExtractInto: extractInto,
ParserFunc: types.Ref(g.outputPackage+"/internal", "Parser"),
ParserFunc: types.Ref(path.Join(g.outPkgBase, "internal"), "Parser"),
OpenAPIType: g.openAPIType,
}

View File

@@ -23,14 +23,14 @@ import (
"k8s.io/kube-openapi/pkg/schemaconv"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
)
// utilGenerator generates the ForKind() utility function.
type internalGenerator struct {
generator.DefaultGen
generator.GoGenerator
outputPackage string
imports namer.ImportTracker
typeModels *typeModels

View File

@@ -20,7 +20,7 @@ import (
"reflect"
"strings"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/types"
)
// TODO: This implements the same functionality as https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apimachinery/pkg/runtime/converter.go#L236

View File

@@ -23,7 +23,7 @@ import (
"strings"
openapiv2 "github.com/google/gnostic-models/openapiv2"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/types"
utilproto "k8s.io/kube-openapi/pkg/util/proto"
"k8s.io/kube-openapi/pkg/validation/spec"
)

View File

@@ -17,7 +17,7 @@ limitations under the License.
package generators
import (
"k8s.io/gengo/types"
"k8s.io/gengo/v2/types"
"k8s.io/code-generator/cmd/client-gen/generators/util"
)
@@ -171,9 +171,5 @@ func requiresApplyConfiguration(t *types.Type) bool {
hasJSONTaggedMembers = true
}
}
if !hasJSONTaggedMembers {
return false
}
return true
return hasJSONTaggedMembers
}

View File

@@ -23,13 +23,13 @@ import (
"sort"
"strings"
"k8s.io/gengo/args"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/gengo/v2"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
"k8s.io/klog/v2"
applygenargs "k8s.io/code-generator/cmd/applyconfiguration-gen/args"
"k8s.io/code-generator/cmd/applyconfiguration-gen/args"
"k8s.io/code-generator/cmd/client-gen/generators/util"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
)
@@ -54,32 +54,29 @@ func DefaultNameSystem() string {
return "public"
}
// Packages makes the client package definition.
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
boilerplate, err := arguments.LoadGoBoilerplate()
// GetTargets makes the client target definition.
func GetTargets(context *generator.Context, args *args.Args) []generator.Target {
boilerplate, err := gengo.GoBoilerplate(args.GoHeaderFile, "", gengo.StdGeneratedBy)
if err != nil {
klog.Fatalf("Failed loading boilerplate: %v", err)
}
pkgTypes := packageTypesForInputDirs(context, arguments.InputDirs, arguments.OutputPackagePath)
customArgs := arguments.CustomArgs.(*applygenargs.CustomArgs)
initialTypes := customArgs.ExternalApplyConfigurations
pkgTypes := packageTypesForInputs(context, args.OutputPkg)
initialTypes := args.ExternalApplyConfigurations
refs := refGraphForReachableTypes(context.Universe, pkgTypes, initialTypes)
typeModels, err := newTypeModels(customArgs.OpenAPISchemaFilePath, pkgTypes)
typeModels, err := newTypeModels(args.OpenAPISchemaFilePath, pkgTypes)
if err != nil {
klog.Fatalf("Failed build type models from typeModels %s: %v", customArgs.OpenAPISchemaFilePath, err)
klog.Fatalf("Failed build type models from typeModels %s: %v", args.OpenAPISchemaFilePath, err)
}
groupVersions := make(map[string]clientgentypes.GroupVersions)
groupGoNames := make(map[string]string)
applyConfigsForGroupVersion := make(map[clientgentypes.GroupVersion][]applyConfig)
var packageList generator.Packages
var targetList []generator.Target
for pkg, p := range pkgTypes {
gv := groupVersion(p)
pkgType := types.Name{Name: gv.Group.PackageName(), Package: pkg}
var toGenerate []applyConfig
for _, t := range p.Types {
// If we don't have an ObjectMeta field, we lack the information required to make the Apply or ApplyStatus call
@@ -101,8 +98,17 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
}
sort.Sort(applyConfigSort(toGenerate))
// Apparently we allow the groupName to be overridden in a way that it
// no longer maps to a Go package by name. So we have to figure out
// the offset of this particular output package (pkg) from the base
// output package (args.OutputPkg).
pkgSubdir := strings.TrimPrefix(pkg, args.OutputPkg+"/")
// generate the apply configurations
packageList = append(packageList, generatorForApplyConfigurationsPackage(arguments.OutputPackagePath, boilerplate, pkgType, gv, toGenerate, refs, typeModels))
targetList = append(targetList,
targetForApplyConfigurationsPackage(
args.OutputDir, args.OutputPkg, pkgSubdir,
boilerplate, gv, toGenerate, refs, typeModels))
// group all the generated apply configurations by gv so ForKind() can be generated
groupPackageName := gv.Group.NonEmpty()
@@ -124,11 +130,15 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
}
// generate ForKind() utility function
packageList = append(packageList, generatorForUtils(arguments.OutputPackagePath, boilerplate, groupVersions, applyConfigsForGroupVersion, groupGoNames))
targetList = append(targetList,
targetForUtils(args.OutputDir, args.OutputPkg,
boilerplate, groupVersions, applyConfigsForGroupVersion, groupGoNames))
// generate internal embedded schema, required for generated Extract functions
packageList = append(packageList, generatorForInternal(filepath.Join(arguments.OutputPackagePath, "internal"), boilerplate, typeModels))
targetList = append(targetList,
targetForInternal(args.OutputDir, args.OutputPkg,
boilerplate, typeModels))
return packageList
return targetList
}
func friendlyName(name string) string {
@@ -146,18 +156,19 @@ func friendlyName(name string) string {
func typeName(t *types.Type) string {
typePackage := t.Name.Package
if strings.Contains(typePackage, "/vendor/") {
typePackage = typePackage[strings.Index(typePackage, "/vendor/")+len("/vendor/"):]
}
return fmt.Sprintf("%s.%s", typePackage, t.Name.Name)
}
func generatorForApplyConfigurationsPackage(outputPackagePath string, boilerplate []byte, packageName types.Name, gv clientgentypes.GroupVersion, typesToGenerate []applyConfig, refs refGraph, models *typeModels) *generator.DefaultPackage {
return &generator.DefaultPackage{
PackageName: gv.Version.PackageName(),
PackagePath: packageName.Package,
HeaderText: boilerplate,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
func targetForApplyConfigurationsPackage(outputDirBase, outputPkgBase, pkgSubdir string, boilerplate []byte, gv clientgentypes.GroupVersion, typesToGenerate []applyConfig, refs refGraph, models *typeModels) generator.Target {
outputDir := filepath.Join(outputDirBase, pkgSubdir)
outputPkg := path.Join(outputPkgBase, pkgSubdir)
return &generator.SimpleTarget{
PkgName: gv.Version.PackageName(),
PkgPath: outputPkg,
PkgDir: outputDir,
HeaderComment: boilerplate,
GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) {
for _, toGenerate := range typesToGenerate {
var openAPIType *string
gvk := gvk{
@@ -170,16 +181,15 @@ func generatorForApplyConfigurationsPackage(outputPackagePath string, boilerplat
}
generators = append(generators, &applyConfigurationGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: strings.ToLower(toGenerate.Type.Name.Name),
GoGenerator: generator.GoGenerator{
OutputFilename: strings.ToLower(toGenerate.Type.Name.Name) + ".go",
},
outputPackage: outputPackagePath,
localPackage: packageName,
groupVersion: gv,
applyConfig: toGenerate,
imports: generator.NewImportTracker(),
refGraph: refs,
openAPIType: openAPIType,
outPkgBase: outputPkgBase,
groupVersion: gv,
applyConfig: toGenerate,
imports: generator.NewImportTracker(),
refGraph: refs,
openAPIType: openAPIType,
})
}
return generators
@@ -187,17 +197,18 @@ func generatorForApplyConfigurationsPackage(outputPackagePath string, boilerplat
}
}
func generatorForUtils(outPackagePath string, boilerplate []byte, groupVersions map[string]clientgentypes.GroupVersions, applyConfigsForGroupVersion map[clientgentypes.GroupVersion][]applyConfig, groupGoNames map[string]string) *generator.DefaultPackage {
return &generator.DefaultPackage{
PackageName: filepath.Base(outPackagePath),
PackagePath: outPackagePath,
HeaderText: boilerplate,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
func targetForUtils(outputDirBase, outputPkgBase string, boilerplate []byte, groupVersions map[string]clientgentypes.GroupVersions, applyConfigsForGroupVersion map[clientgentypes.GroupVersion][]applyConfig, groupGoNames map[string]string) generator.Target {
return &generator.SimpleTarget{
PkgName: path.Base(outputPkgBase),
PkgPath: outputPkgBase,
PkgDir: outputDirBase,
HeaderComment: boilerplate,
GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = append(generators, &utilGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: "utils",
GoGenerator: generator.GoGenerator{
OutputFilename: "utils.go",
},
outputPackage: outPackagePath,
outputPackage: outputPkgBase,
imports: generator.NewImportTracker(),
groupVersions: groupVersions,
typesForGroupVersion: applyConfigsForGroupVersion,
@@ -208,17 +219,20 @@ func generatorForUtils(outPackagePath string, boilerplate []byte, groupVersions
}
}
func generatorForInternal(outPackagePath string, boilerplate []byte, models *typeModels) *generator.DefaultPackage {
return &generator.DefaultPackage{
PackageName: filepath.Base(outPackagePath),
PackagePath: outPackagePath,
HeaderText: boilerplate,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
func targetForInternal(outputDirBase, outputPkgBase string, boilerplate []byte, models *typeModels) generator.Target {
outputDir := filepath.Join(outputDirBase, "internal")
outputPkg := path.Join(outputPkgBase, "internal")
return &generator.SimpleTarget{
PkgName: path.Base(outputPkg),
PkgPath: outputPkg,
PkgDir: outputDir,
HeaderComment: boilerplate,
GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = append(generators, &internalGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: "internal",
GoGenerator: generator.GoGenerator{
OutputFilename: "internal.go",
},
outputPackage: outPackagePath,
outputPackage: outputPkgBase,
imports: generator.NewImportTracker(),
typeModels: models,
})
@@ -229,15 +243,15 @@ func generatorForInternal(outPackagePath string, boilerplate []byte, models *typ
func goName(gv clientgentypes.GroupVersion, p *types.Package) string {
goName := namer.IC(strings.Split(gv.Group.NonEmpty(), ".")[0])
if override := types.ExtractCommentTags("+", p.Comments)["groupGoName"]; override != nil {
if override := gengo.ExtractCommentTags("+", p.Comments)["groupGoName"]; override != nil {
goName = namer.IC(override[0])
}
return goName
}
func packageTypesForInputDirs(context *generator.Context, inputDirs []string, outputPath string) map[string]*types.Package {
func packageTypesForInputs(context *generator.Context, outPkgBase string) map[string]*types.Package {
pkgTypes := map[string]*types.Package{}
for _, inputDir := range inputDirs {
for _, inputDir := range context.Inputs {
p := context.Universe.Package(inputDir)
internal := isInternalPackage(p)
if internal {
@@ -249,7 +263,7 @@ func packageTypesForInputDirs(context *generator.Context, inputDirs []string, ou
// For example, if openshift/api/cloudnetwork/v1 contains an apigroup cloud.network.openshift.io, the client-gen
// builds a package called cloudnetwork/v1 to contain it. This change makes the applyconfiguration-gen use the same.
_, gvPackageString := util.ParsePathGroupVersion(p.Path)
pkg := filepath.Join(outputPath, strings.ToLower(gvPackageString))
pkg := path.Join(outPkgBase, strings.ToLower(gvPackageString))
pkgTypes[pkg] = p
}
return pkgTypes
@@ -263,7 +277,7 @@ func groupVersion(p *types.Package) (gv clientgentypes.GroupVersion) {
// If there's a comment of the form "// +groupName=somegroup" or
// "// +groupName=somegroup.foo.bar.io", use the first field (somegroup) as the name of the
// group when generating.
if override := types.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil {
if override := gengo.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil {
gv.Group = clientgentypes.Group(override[0])
}
return gv

View File

@@ -16,7 +16,7 @@ limitations under the License.
package generators
import "k8s.io/gengo/types"
import "k8s.io/gengo/v2/types"
var (
applyConfiguration = types.Ref("k8s.io/apimachinery/pkg/runtime", "ApplyConfiguration")

View File

@@ -23,14 +23,14 @@ import (
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
)
// utilGenerator generates the ForKind() utility function.
type utilGenerator struct {
generator.DefaultGen
generator.GoGenerator
outputPackage string
imports namer.ImportTracker
groupVersions map[string]clientgentypes.GroupVersions

View File

@@ -14,39 +14,45 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// typebuilder-gen is a tool for auto-generating apply builder functions.
// applyconfiguration-gen is a tool for auto-generating apply builder functions.
package main
import (
"flag"
"github.com/spf13/pflag"
"k8s.io/klog/v2"
generatorargs "k8s.io/code-generator/cmd/applyconfiguration-gen/args"
"k8s.io/code-generator/cmd/applyconfiguration-gen/args"
"k8s.io/code-generator/cmd/applyconfiguration-gen/generators"
"k8s.io/gengo/v2"
"k8s.io/gengo/v2/generator"
"k8s.io/klog/v2"
)
func main() {
klog.InitFlags(nil)
genericArgs, customArgs := generatorargs.NewDefaults()
genericArgs.AddFlags(pflag.CommandLine)
customArgs.AddFlags(pflag.CommandLine, "k8s.io/kubernetes/pkg/apis") // TODO: move this input path out of applyconfiguration-gen
args := args.New()
args.AddFlags(pflag.CommandLine, "k8s.io/kubernetes/pkg/apis") // TODO: move this input path out of applyconfiguration-gen
if err := flag.Set("logtostderr", "true"); err != nil {
klog.Fatalf("Error: %v", err)
}
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
pflag.Parse()
if err := generatorargs.Validate(genericArgs); err != nil {
if err := args.Validate(); err != nil {
klog.Fatalf("Error: %v", err)
}
myTargets := func(context *generator.Context) []generator.Target {
return generators.GetTargets(context, args)
}
// Run it.
if err := genericArgs.Execute(
if err := gengo.Execute(
generators.NameSystems(),
generators.DefaultNameSystem(),
generators.Packages,
myTargets,
gengo.StdBuildTag,
pflag.Args(),
); err != nil {
klog.Fatalf("Error: %v", err)
}

View File

@@ -18,19 +18,22 @@ package args
import (
"fmt"
"path"
"github.com/spf13/pflag"
"k8s.io/gengo/args"
"k8s.io/code-generator/cmd/client-gen/types"
codegenutil "k8s.io/code-generator/pkg/util"
)
var DefaultInputDirs = []string{}
type Args struct {
// The directory for the generated results.
OutputDir string
// The Go import-path of the generated results.
OutputPkg string
// The boilerplate header for Go files.
GoHeaderFile string
// CustomArgs is a wrapper for arguments to client-gen.
type CustomArgs struct {
// A sorted list of group versions to generate. For each of them the package path is found
// in GroupVersionToInputPath.
Groups []types.GroupVersions
@@ -53,69 +56,75 @@ type CustomArgs struct {
// For example 'Endpoints:Endpoints', otherwise the pluralizer will generate 'Endpointes'.
PluralExceptions []string
// ApplyConfigurationPackage is the package of apply builders generated by typebuilder-gen.
// ApplyConfigurationPackage is the package of apply builders generated by
// applyconfiguration-gen.
// If non-empty, Apply functions are generated for each type and reference the apply builders.
// If empty (""), Apply functions are not generated.
ApplyConfigurationPackage string
}
func NewDefaults() (*args.GeneratorArgs, *CustomArgs) {
genericArgs := args.Default().WithoutDefaultFlagParsing()
customArgs := &CustomArgs{
func New() *Args {
return &Args{
ClientsetName: "internalclientset",
ClientsetAPIPath: "/apis",
ClientsetOnly: false,
FakeClient: true,
PluralExceptions: []string{"Endpoints:Endpoints"},
ApplyConfigurationPackage: "",
}
genericArgs.CustomArgs = customArgs
genericArgs.InputDirs = DefaultInputDirs
if pkg := codegenutil.CurrentPackage(); len(pkg) != 0 {
genericArgs.OutputPackagePath = path.Join(pkg, "pkg/client/clientset")
}
return genericArgs, customArgs
}
func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet, inputBase string) {
gvsBuilder := NewGroupVersionsBuilder(&ca.Groups)
fs.Var(NewGVPackagesValue(gvsBuilder, nil), "input", "group/versions that client-gen will generate clients for. At most one version per group is allowed. Specified in the format \"group1/version1,group2/version2...\".")
fs.Var(NewGVTypesValue(&ca.IncludedTypesOverrides, []string{}), "included-types-overrides", "list of group/version/type for which client should be generated. By default, client is generated for all types which have genclient in types.go. This overrides that. For each groupVersion in this list, only the types mentioned here will be included. The default check of genclient will be used for other group versions.")
fs.Var(NewInputBasePathValue(gvsBuilder, inputBase), "input-base", "base path to look for the api group.")
fs.StringVarP(&ca.ClientsetName, "clientset-name", "n", ca.ClientsetName, "the name of the generated clientset package.")
fs.StringVarP(&ca.ClientsetAPIPath, "clientset-api-path", "", ca.ClientsetAPIPath, "the value of default API HTTP path, starting with / and without trailing /.")
fs.BoolVar(&ca.ClientsetOnly, "clientset-only", ca.ClientsetOnly, "when set, client-gen only generates the clientset shell, without generating the individual typed clients")
fs.BoolVar(&ca.FakeClient, "fake-clientset", ca.FakeClient, "when set, client-gen will generate the fake clientset that can be used in tests")
fs.StringSliceVar(&ca.PluralExceptions, "plural-exceptions", ca.PluralExceptions, "list of comma separated plural exception definitions in Type:PluralizedType form")
fs.StringVar(&ca.ApplyConfigurationPackage, "apply-configuration-package", ca.ApplyConfigurationPackage, "optional package of apply configurations, generated by applyconfiguration-gen, that are required to generate Apply functions for each type in the clientset. By default Apply functions are not generated.")
func (args *Args) AddFlags(fs *pflag.FlagSet, inputBase string) {
gvsBuilder := NewGroupVersionsBuilder(&args.Groups)
fs.StringVar(&args.OutputDir, "output-dir", "",
"the base directory under which to generate results")
fs.StringVar(&args.OutputPkg, "output-pkg", args.OutputPkg,
"the Go import-path of the generated results")
fs.StringVar(&args.GoHeaderFile, "go-header-file", "",
"the path to a file containing boilerplate header text; the string \"YEAR\" will be replaced with the current 4-digit year")
fs.Var(NewGVPackagesValue(gvsBuilder, nil), "input",
"group/versions that client-gen will generate clients for. At most one version per group is allowed. Specified in the format \"group1/version1,group2/version2...\".")
fs.Var(NewGVTypesValue(&args.IncludedTypesOverrides, []string{}), "included-types-overrides",
"list of group/version/type for which client should be generated. By default, client is generated for all types which have genclient in types.go. This overrides that. For each groupVersion in this list, only the types mentioned here will be included. The default check of genclient will be used for other group versions.")
fs.Var(NewInputBasePathValue(gvsBuilder, inputBase), "input-base",
"base path to look for the api group.")
fs.StringVarP(&args.ClientsetName, "clientset-name", "n", args.ClientsetName,
"the name of the generated clientset package.")
fs.StringVarP(&args.ClientsetAPIPath, "clientset-api-path", "", args.ClientsetAPIPath,
"the value of default API HTTP path, starting with / and without trailing /.")
fs.BoolVar(&args.ClientsetOnly, "clientset-only", args.ClientsetOnly,
"when set, client-gen only generates the clientset shell, without generating the individual typed clients")
fs.BoolVar(&args.FakeClient, "fake-clientset", args.FakeClient,
"when set, client-gen will generate the fake clientset that can be used in tests")
fs.StringSliceVar(&args.PluralExceptions, "plural-exceptions", args.PluralExceptions,
"list of comma separated plural exception definitions in Type:PluralizedType form")
fs.StringVar(&args.ApplyConfigurationPackage, "apply-configuration-package", args.ApplyConfigurationPackage,
"optional package of apply configurations, generated by applyconfiguration-gen, that are required to generate Apply functions for each type in the clientset. By default Apply functions are not generated.")
// support old flags
fs.SetNormalizeFunc(mapFlagName("clientset-path", "output-package", fs.GetNormalizeFunc()))
fs.SetNormalizeFunc(mapFlagName("clientset-path", "output-pkg", fs.GetNormalizeFunc()))
}
func Validate(genericArgs *args.GeneratorArgs) error {
customArgs := genericArgs.CustomArgs.(*CustomArgs)
if len(genericArgs.OutputPackagePath) == 0 {
return fmt.Errorf("output package cannot be empty")
func (args *Args) Validate() error {
if len(args.OutputDir) == 0 {
return fmt.Errorf("--output-dir must be specified")
}
if len(customArgs.ClientsetName) == 0 {
return fmt.Errorf("clientset name cannot be empty")
if len(args.OutputPkg) == 0 {
return fmt.Errorf("--output-pkg must be specified")
}
if len(customArgs.ClientsetAPIPath) == 0 {
return fmt.Errorf("clientset API path cannot be empty")
if len(args.ClientsetName) == 0 {
return fmt.Errorf("--clientset-name must be specified")
}
if len(args.ClientsetAPIPath) == 0 {
return fmt.Errorf("--clientset-api-path cannot be empty")
}
return nil
}
// GroupVersionPackages returns a map from GroupVersion to the package with the types.go.
func (ca *CustomArgs) GroupVersionPackages() map[types.GroupVersion]string {
func (args *Args) GroupVersionPackages() map[types.GroupVersion]string {
res := map[types.GroupVersion]string{}
for _, pkg := range ca.Groups {
for _, pkg := range args.Groups {
for _, v := range pkg.Versions {
res[types.GroupVersion{Group: pkg.Group, Version: v.Version}] = v.Package
}

View File

@@ -129,7 +129,9 @@ func (p *groupVersionsBuilder) update() error {
versionPkg := types.PackageVersion{Package: path.Join(p.importBasePath, pth, gv.Group.NonEmpty(), gv.Version.String()), Version: gv.Version}
if group, ok := seenGroups[gv.Group]; ok {
seenGroups[gv.Group].Versions = append(group.Versions, versionPkg)
vers := group.Versions
vers = append(vers, versionPkg)
seenGroups[gv.Group].Versions = vers
} else {
seenGroups[gv.Group] = &types.GroupVersions{
PackageName: gv.Group.NonEmpty(),

View File

@@ -18,21 +18,21 @@ limitations under the License.
package generators
import (
"fmt"
"path"
"path/filepath"
"strings"
clientgenargs "k8s.io/code-generator/cmd/client-gen/args"
"k8s.io/code-generator/cmd/client-gen/args"
"k8s.io/code-generator/cmd/client-gen/generators/fake"
"k8s.io/code-generator/cmd/client-gen/generators/scheme"
"k8s.io/code-generator/cmd/client-gen/generators/util"
"k8s.io/code-generator/cmd/client-gen/path"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
codegennamer "k8s.io/code-generator/pkg/namer"
genutil "k8s.io/code-generator/pkg/util"
"k8s.io/gengo/args"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/gengo/v2"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
"k8s.io/klog/v2"
)
@@ -128,31 +128,35 @@ func DefaultNameSystem() string {
return "public"
}
func packageForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, clientsetPackage string, groupPackageName string, groupGoName string, apiPath string, srcTreePath string, inputPackage string, applyBuilderPackage string, boilerplate []byte) generator.Package {
groupVersionClientPackage := filepath.Join(clientsetPackage, "typed", strings.ToLower(groupPackageName), strings.ToLower(gv.Version.NonEmpty()))
return &generator.DefaultPackage{
PackageName: strings.ToLower(gv.Version.NonEmpty()),
PackagePath: groupVersionClientPackage,
HeaderText: boilerplate,
PackageDocumentation: []byte("// This package has the automatically generated typed clients.\n"),
// GeneratorFunc returns a list of generators. Each generator makes a
func targetForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, clientsetDir, clientsetPkg string, groupPkgName string, groupGoName string, apiPath string, inputPkg string, applyBuilderPkg string, boilerplate []byte) generator.Target {
subdir := []string{"typed", strings.ToLower(groupPkgName), strings.ToLower(gv.Version.NonEmpty())}
gvDir := filepath.Join(clientsetDir, filepath.Join(subdir...))
gvPkg := path.Join(clientsetPkg, path.Join(subdir...))
return &generator.SimpleTarget{
PkgName: strings.ToLower(gv.Version.NonEmpty()),
PkgPath: gvPkg,
PkgDir: gvDir,
HeaderComment: boilerplate,
PkgDocComment: []byte("// This package has the automatically generated typed clients.\n"),
// GeneratorsFunc returns a list of generators. Each generator makes a
// single file.
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = []generator.Generator{
// Always generate a "doc.go" file.
generator.DefaultGen{OptionalName: "doc"},
generator.GoGenerator{OutputFilename: "doc.go"},
}
// Since we want a file per type that we generate a client for, we
// have to provide a function for this.
for _, t := range typeList {
generators = append(generators, &genClientForType{
DefaultGen: generator.DefaultGen{
OptionalName: strings.ToLower(c.Namers["private"].Name(t)),
GoGenerator: generator.GoGenerator{
OutputFilename: strings.ToLower(c.Namers["private"].Name(t)) + ".go",
},
outputPackage: groupVersionClientPackage,
inputPackage: inputPackage,
clientsetPackage: clientsetPackage,
applyConfigurationPackage: applyBuilderPackage,
outputPackage: gvPkg,
inputPackage: inputPkg,
clientsetPackage: clientsetPkg,
applyConfigurationPackage: applyBuilderPkg,
group: gv.Group.NonEmpty(),
version: gv.Version.String(),
groupGoName: groupGoName,
@@ -162,12 +166,12 @@ func packageForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, cli
}
generators = append(generators, &genGroup{
DefaultGen: generator.DefaultGen{
OptionalName: groupPackageName + "_client",
GoGenerator: generator.GoGenerator{
OutputFilename: groupPkgName + "_client.go",
},
outputPackage: groupVersionClientPackage,
inputPackage: inputPackage,
clientsetPackage: clientsetPackage,
outputPackage: gvPkg,
inputPackage: inputPkg,
clientsetPackage: clientsetPkg,
group: gv.Group.NonEmpty(),
version: gv.Version.String(),
groupGoName: groupGoName,
@@ -176,11 +180,11 @@ func packageForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, cli
imports: generator.NewImportTracker(),
})
expansionFileName := "generated_expansion"
expansionFileName := "generated_expansion.go"
generators = append(generators, &genExpansion{
groupPackagePath: filepath.Join(srcTreePath, groupVersionClientPackage),
DefaultGen: generator.DefaultGen{
OptionalName: expansionFileName,
groupPackagePath: gvDir,
GoGenerator: generator.GoGenerator{
OutputFilename: expansionFileName,
},
types: typeList,
})
@@ -193,23 +197,23 @@ func packageForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, cli
}
}
func packageForClientset(customArgs *clientgenargs.CustomArgs, clientsetPackage string, groupGoNames map[clientgentypes.GroupVersion]string, boilerplate []byte) generator.Package {
return &generator.DefaultPackage{
PackageName: customArgs.ClientsetName,
PackagePath: clientsetPackage,
HeaderText: boilerplate,
// GeneratorFunc returns a list of generators. Each generator generates a
func targetForClientset(args *args.Args, clientsetDir, clientsetPkg string, groupGoNames map[clientgentypes.GroupVersion]string, boilerplate []byte) generator.Target {
return &generator.SimpleTarget{
PkgName: args.ClientsetName,
PkgPath: clientsetPkg,
PkgDir: clientsetDir,
HeaderComment: boilerplate,
// GeneratorsFunc returns a list of generators. Each generator generates a
// single file.
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = []generator.Generator{
&genClientset{
DefaultGen: generator.DefaultGen{
OptionalName: "clientset",
GoGenerator: generator.GoGenerator{
OutputFilename: "clientset.go",
},
groups: customArgs.Groups,
groups: args.Groups,
groupGoNames: groupGoNames,
clientsetPackage: clientsetPackage,
outputPackage: customArgs.ClientsetName,
clientsetPackage: clientsetPkg,
imports: generator.NewImportTracker(),
},
}
@@ -218,13 +222,14 @@ func packageForClientset(customArgs *clientgenargs.CustomArgs, clientsetPackage
}
}
func packageForScheme(customArgs *clientgenargs.CustomArgs, clientsetPackage string, srcTreePath string, groupGoNames map[clientgentypes.GroupVersion]string, boilerplate []byte) generator.Package {
schemePackage := filepath.Join(clientsetPackage, "scheme")
func targetForScheme(args *args.Args, clientsetDir, clientsetPkg string, groupGoNames map[clientgentypes.GroupVersion]string, boilerplate []byte) generator.Target {
schemeDir := filepath.Join(clientsetDir, "scheme")
schemePkg := path.Join(clientsetPkg, "scheme")
// create runtime.Registry for internal client because it has to know about group versions
internalClient := false
NextGroup:
for _, group := range customArgs.Groups {
for _, group := range args.Groups {
for _, v := range group.Versions {
if v.String() == "" {
internalClient = true
@@ -233,26 +238,27 @@ NextGroup:
}
}
return &generator.DefaultPackage{
PackageName: "scheme",
PackagePath: schemePackage,
HeaderText: boilerplate,
PackageDocumentation: []byte("// This package contains the scheme of the automatically generated clientset.\n"),
// GeneratorFunc returns a list of generators. Each generator generates a
return &generator.SimpleTarget{
PkgName: "scheme",
PkgPath: schemePkg,
PkgDir: schemeDir,
HeaderComment: boilerplate,
PkgDocComment: []byte("// This package contains the scheme of the automatically generated clientset.\n"),
// GeneratorsFunc returns a list of generators. Each generator generates a
// single file.
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = []generator.Generator{
// Always generate a "doc.go" file.
generator.DefaultGen{OptionalName: "doc"},
generator.GoGenerator{OutputFilename: "doc.go"},
&scheme.GenScheme{
DefaultGen: generator.DefaultGen{
OptionalName: "register",
GoGenerator: generator.GoGenerator{
OutputFilename: "register.go",
},
InputPackages: customArgs.GroupVersionPackages(),
OutputPackage: schemePackage,
OutputPath: filepath.Join(srcTreePath, schemePackage),
Groups: customArgs.Groups,
InputPackages: args.GroupVersionPackages(),
OutputPkg: schemePkg,
OutputPath: schemeDir,
Groups: args.Groups,
GroupGoNames: groupGoNames,
ImportTracker: generator.NewImportTracker(),
CreateRegistry: internalClient,
@@ -268,12 +274,12 @@ NextGroup:
// first field (somegroup) as the name of the group in Go code, e.g. as the func name in a clientset.
//
// If the first field of the groupName is not unique within the clientset, use "// +groupName=unique
func applyGroupOverrides(universe types.Universe, customArgs *clientgenargs.CustomArgs) {
func applyGroupOverrides(universe types.Universe, args *args.Args) {
// Create a map from "old GV" to "new GV" so we know what changes we need to make.
changes := make(map[clientgentypes.GroupVersion]clientgentypes.GroupVersion)
for gv, inputDir := range customArgs.GroupVersionPackages() {
p := universe.Package(genutil.Vendorless(inputDir))
if override := types.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil {
for gv, inputDir := range args.GroupVersionPackages() {
p := universe.Package(inputDir)
if override := gengo.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil {
newGV := clientgentypes.GroupVersion{
Group: clientgentypes.Group(override[0]),
Version: gv.Version,
@@ -282,9 +288,9 @@ func applyGroupOverrides(universe types.Universe, customArgs *clientgenargs.Cust
}
}
// Modify customArgs.Groups based on the groupName overrides.
newGroups := make([]clientgentypes.GroupVersions, 0, len(customArgs.Groups))
for _, gvs := range customArgs.Groups {
// Modify args.Groups based on the groupName overrides.
newGroups := make([]clientgentypes.GroupVersions, 0, len(args.Groups))
for _, gvs := range args.Groups {
gv := clientgentypes.GroupVersion{
Group: gvs.Group,
Version: gvs.Versions[0].Version, // we only need a version, and the first will do
@@ -302,37 +308,64 @@ func applyGroupOverrides(universe types.Universe, customArgs *clientgenargs.Cust
newGroups = append(newGroups, gvs)
}
}
customArgs.Groups = newGroups
args.Groups = newGroups
}
// Packages makes the client package definition.
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
boilerplate, err := arguments.LoadGoBoilerplate()
// Because we try to assemble inputs from an input-base and a set of
// group-version arguments, sometimes that comes in as a filesystem path. This
// function rewrites them all as their canonical Go import-paths.
//
// TODO: Change this tool to just take inputs as Go "patterns" like every other
// gengo tool, then extract GVs from those.
func sanitizePackagePaths(context *generator.Context, args *args.Args) error {
for i := range args.Groups {
pkg := &args.Groups[i]
for j := range pkg.Versions {
ver := &pkg.Versions[j]
input := ver.Package
p := context.Universe[input]
if p == nil || p.Name == "" {
pkgs, err := context.FindPackages(input)
if err != nil {
return fmt.Errorf("can't find input package %q: %w", input, err)
}
p = context.Universe[pkgs[0]]
if p == nil {
return fmt.Errorf("can't find input package %q in universe", input)
}
ver.Package = p.Path
}
}
}
return nil
}
// GetTargets makes the client target definition.
func GetTargets(context *generator.Context, args *args.Args) []generator.Target {
boilerplate, err := gengo.GoBoilerplate(args.GoHeaderFile, "", gengo.StdGeneratedBy)
if err != nil {
klog.Fatalf("Failed loading boilerplate: %v", err)
}
customArgs, ok := arguments.CustomArgs.(*clientgenargs.CustomArgs)
if !ok {
klog.Fatalf("cannot convert arguments.CustomArgs to clientgenargs.CustomArgs")
}
includedTypesOverrides := customArgs.IncludedTypesOverrides
includedTypesOverrides := args.IncludedTypesOverrides
applyGroupOverrides(context.Universe, customArgs)
if err := sanitizePackagePaths(context, args); err != nil {
klog.Fatalf("cannot sanitize inputs: %v", err)
}
applyGroupOverrides(context.Universe, args)
gvToTypes := map[clientgentypes.GroupVersion][]*types.Type{}
groupGoNames := make(map[clientgentypes.GroupVersion]string)
for gv, inputDir := range customArgs.GroupVersionPackages() {
p := context.Universe.Package(path.Vendorless(inputDir))
for gv, inputDir := range args.GroupVersionPackages() {
p := context.Universe.Package(inputDir)
// If there's a comment of the form "// +groupGoName=SomeUniqueShortName", use that as
// the Go group identifier in CamelCase. It defaults
groupGoNames[gv] = namer.IC(strings.Split(gv.Group.NonEmpty(), ".")[0])
if override := types.ExtractCommentTags("+", p.Comments)["groupGoName"]; override != nil {
if override := gengo.ExtractCommentTags("+", p.Comments)["groupGoName"]; override != nil {
groupGoNames[gv] = namer.IC(override[0])
}
// Package are indexed with the vendor prefix stripped
for n, t := range p.Types {
// filter out types which are not included in user specified overrides.
typesOverride, ok := includedTypesOverrides[gv]
@@ -361,33 +394,43 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
}
}
var packageList []generator.Package
clientsetPackage := filepath.Join(arguments.OutputPackagePath, customArgs.ClientsetName)
clientsetDir := filepath.Join(args.OutputDir, args.ClientsetName)
clientsetPkg := path.Join(args.OutputPkg, args.ClientsetName)
packageList = append(packageList, packageForClientset(customArgs, clientsetPackage, groupGoNames, boilerplate))
packageList = append(packageList, packageForScheme(customArgs, clientsetPackage, arguments.OutputBase, groupGoNames, boilerplate))
if customArgs.FakeClient {
packageList = append(packageList, fake.PackageForClientset(customArgs, clientsetPackage, groupGoNames, boilerplate))
var targetList []generator.Target
targetList = append(targetList,
targetForClientset(args, clientsetDir, clientsetPkg, groupGoNames, boilerplate))
targetList = append(targetList,
targetForScheme(args, clientsetDir, clientsetPkg, groupGoNames, boilerplate))
if args.FakeClient {
targetList = append(targetList,
fake.TargetForClientset(args, clientsetDir, clientsetPkg, groupGoNames, boilerplate))
}
// If --clientset-only=true, we don't regenerate the individual typed clients.
if customArgs.ClientsetOnly {
return generator.Packages(packageList)
if args.ClientsetOnly {
return []generator.Target(targetList)
}
orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)}
gvPackages := customArgs.GroupVersionPackages()
for _, group := range customArgs.Groups {
gvPackages := args.GroupVersionPackages()
for _, group := range args.Groups {
for _, version := range group.Versions {
gv := clientgentypes.GroupVersion{Group: group.Group, Version: version.Version}
types := gvToTypes[gv]
inputPath := gvPackages[gv]
packageList = append(packageList, packageForGroup(gv, orderer.OrderTypes(types), clientsetPackage, group.PackageName, groupGoNames[gv], customArgs.ClientsetAPIPath, arguments.OutputBase, inputPath, customArgs.ApplyConfigurationPackage, boilerplate))
if customArgs.FakeClient {
packageList = append(packageList, fake.PackageForGroup(gv, orderer.OrderTypes(types), clientsetPackage, group.PackageName, groupGoNames[gv], inputPath, customArgs.ApplyConfigurationPackage, boilerplate))
targetList = append(targetList,
targetForGroup(
gv, orderer.OrderTypes(types), clientsetDir, clientsetPkg,
group.PackageName, groupGoNames[gv], args.ClientsetAPIPath,
inputPath, args.ApplyConfigurationPackage, boilerplate))
if args.FakeClient {
targetList = append(targetList,
fake.TargetForGroup(gv, orderer.OrderTypes(types), clientsetDir, clientsetPkg, group.PackageName, groupGoNames[gv], inputPath, args.ApplyConfigurationPackage, boilerplate))
}
}
}
return generator.Packages(packageList)
return targetList
}

View File

@@ -17,45 +17,48 @@ limitations under the License.
package fake
import (
"path"
"path/filepath"
"strings"
"k8s.io/gengo/generator"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/types"
clientgenargs "k8s.io/code-generator/cmd/client-gen/args"
"k8s.io/code-generator/cmd/client-gen/args"
scheme "k8s.io/code-generator/cmd/client-gen/generators/scheme"
"k8s.io/code-generator/cmd/client-gen/generators/util"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
)
func PackageForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, clientsetPackage string, groupPackageName string, groupGoName string, inputPackage string, applyBuilderPackage string, boilerplate []byte) generator.Package {
outputPackage := filepath.Join(clientsetPackage, "typed", strings.ToLower(groupPackageName), strings.ToLower(gv.Version.NonEmpty()), "fake")
func TargetForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, clientsetDir, clientsetPkg string, groupPkgName string, groupGoName string, inputPkg string, applyBuilderPackage string, boilerplate []byte) generator.Target {
// TODO: should make this a function, called by here and in client-generator.go
realClientPackage := filepath.Join(clientsetPackage, "typed", strings.ToLower(groupPackageName), strings.ToLower(gv.Version.NonEmpty()))
return &generator.DefaultPackage{
PackageName: "fake",
PackagePath: outputPackage,
HeaderText: boilerplate,
PackageDocumentation: []byte(
`// Package fake has the automatically generated clients.
`),
// GeneratorFunc returns a list of generators. Each generator makes a
subdir := []string{"typed", strings.ToLower(groupPkgName), strings.ToLower(gv.Version.NonEmpty())}
outputDir := filepath.Join(clientsetDir, filepath.Join(subdir...), "fake")
outputPkg := path.Join(clientsetPkg, path.Join(subdir...), "fake")
realClientPkg := path.Join(clientsetPkg, path.Join(subdir...))
return &generator.SimpleTarget{
PkgName: "fake",
PkgPath: outputPkg,
PkgDir: outputDir,
HeaderComment: boilerplate,
PkgDocComment: []byte("// Package fake has the automatically generated clients.\n"),
// GeneratorsFunc returns a list of generators. Each generator makes a
// single file.
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = []generator.Generator{
// Always generate a "doc.go" file.
generator.DefaultGen{OptionalName: "doc"},
generator.GoGenerator{OutputFilename: "doc.go"},
}
// Since we want a file per type that we generate a client for, we
// have to provide a function for this.
for _, t := range typeList {
generators = append(generators, &genFakeForType{
DefaultGen: generator.DefaultGen{
OptionalName: "fake_" + strings.ToLower(c.Namers["private"].Name(t)),
GoGenerator: generator.GoGenerator{
OutputFilename: "fake_" + strings.ToLower(c.Namers["private"].Name(t)) + ".go",
},
outputPackage: outputPackage,
inputPackage: inputPackage,
outputPackage: outputPkg,
inputPackage: inputPkg,
group: gv.Group.NonEmpty(),
version: gv.Version.String(),
groupGoName: groupGoName,
@@ -66,11 +69,11 @@ func PackageForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, cli
}
generators = append(generators, &genFakeForGroup{
DefaultGen: generator.DefaultGen{
OptionalName: "fake_" + groupPackageName + "_client",
GoGenerator: generator.GoGenerator{
OutputFilename: "fake_" + groupPkgName + "_client.go",
},
outputPackage: outputPackage,
realClientPackage: realClientPackage,
outputPackage: outputPkg,
realClientPackage: realClientPkg,
group: gv.Group.NonEmpty(),
version: gv.Version.String(),
groupGoName: groupGoName,
@@ -85,41 +88,39 @@ func PackageForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, cli
}
}
func PackageForClientset(customArgs *clientgenargs.CustomArgs, clientsetPackage string, groupGoNames map[clientgentypes.GroupVersion]string, boilerplate []byte) generator.Package {
return &generator.DefaultPackage{
func TargetForClientset(args *args.Args, clientsetDir, clientsetPkg string, groupGoNames map[clientgentypes.GroupVersion]string, boilerplate []byte) generator.Target {
return &generator.SimpleTarget{
// TODO: we'll generate fake clientset for different release in the future.
// Package name and path are hard coded for now.
PackageName: "fake",
PackagePath: filepath.Join(clientsetPackage, "fake"),
HeaderText: boilerplate,
PackageDocumentation: []byte(
`// This package has the automatically generated fake clientset.
`),
// GeneratorFunc returns a list of generators. Each generator generates a
PkgName: "fake",
PkgPath: path.Join(clientsetPkg, "fake"),
PkgDir: filepath.Join(clientsetDir, "fake"),
HeaderComment: boilerplate,
PkgDocComment: []byte("// This package has the automatically generated fake clientset.\n"),
// GeneratorsFunc returns a list of generators. Each generator generates a
// single file.
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = []generator.Generator{
// Always generate a "doc.go" file.
generator.DefaultGen{OptionalName: "doc"},
generator.GoGenerator{OutputFilename: "doc.go"},
&genClientset{
DefaultGen: generator.DefaultGen{
OptionalName: "clientset_generated",
GoGenerator: generator.GoGenerator{
OutputFilename: "clientset_generated.go",
},
groups: customArgs.Groups,
groups: args.Groups,
groupGoNames: groupGoNames,
fakeClientsetPackage: clientsetPackage,
outputPackage: "fake",
fakeClientsetPackage: clientsetPkg,
imports: generator.NewImportTracker(),
realClientsetPackage: clientsetPackage,
realClientsetPackage: clientsetPkg,
},
&scheme.GenScheme{
DefaultGen: generator.DefaultGen{
OptionalName: "register",
GoGenerator: generator.GoGenerator{
OutputFilename: "register.go",
},
InputPackages: customArgs.GroupVersionPackages(),
OutputPackage: clientsetPackage,
Groups: customArgs.Groups,
InputPackages: args.GroupVersionPackages(),
OutputPkg: clientsetPkg,
Groups: args.Groups,
GroupGoNames: groupGoNames,
ImportTracker: generator.NewImportTracker(),
PrivateScheme: true,

View File

@@ -19,33 +19,32 @@ package fake
import (
"fmt"
"io"
"path/filepath"
"path"
"strings"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
)
// genClientset generates a package for a clientset.
type genClientset struct {
generator.DefaultGen
generator.GoGenerator
groups []clientgentypes.GroupVersions
groupGoNames map[clientgentypes.GroupVersion]string
fakeClientsetPackage string
outputPackage string
fakeClientsetPackage string // must be a Go import-path
imports namer.ImportTracker
clientsetGenerated bool
// the import path of the generated real clientset.
realClientsetPackage string
realClientsetPackage string // must be a Go import-path
}
var _ generator.Generator = &genClientset{}
func (g *genClientset) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
"raw": namer.NewRawNamer(g.fakeClientsetPackage, g.imports),
}
}
@@ -60,8 +59,8 @@ func (g *genClientset) Imports(c *generator.Context) (imports []string) {
imports = append(imports, g.imports.ImportLines()...)
for _, group := range g.groups {
for _, version := range group.Versions {
groupClientPackage := filepath.Join(g.fakeClientsetPackage, "typed", strings.ToLower(group.PackageName), strings.ToLower(version.NonEmpty()))
fakeGroupClientPackage := filepath.Join(groupClientPackage, "fake")
groupClientPackage := path.Join(g.fakeClientsetPackage, "typed", strings.ToLower(group.PackageName), strings.ToLower(version.NonEmpty()))
fakeGroupClientPackage := path.Join(groupClientPackage, "fake")
groupAlias := strings.ToLower(g.groupGoNames[clientgentypes.GroupVersion{Group: group.Group, Version: version.Version}])
imports = append(imports, fmt.Sprintf("%s%s \"%s\"", groupAlias, strings.ToLower(version.NonEmpty()), groupClientPackage))

View File

@@ -19,21 +19,21 @@ package fake
import (
"fmt"
"io"
"path/filepath"
"path"
"strings"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
"k8s.io/code-generator/cmd/client-gen/generators/util"
)
// genFakeForGroup produces a file for a group client, e.g. ExtensionsClient for the extension group.
type genFakeForGroup struct {
generator.DefaultGen
outputPackage string
realClientPackage string
generator.GoGenerator
outputPackage string // must be a Go import-path
realClientPackage string // must be a Go import-path
group string
version string
groupGoName string
@@ -64,7 +64,7 @@ func (g *genFakeForGroup) Namers(c *generator.Context) namer.NameSystems {
func (g *genFakeForGroup) Imports(c *generator.Context) (imports []string) {
imports = g.imports.ImportLines()
if len(g.types) != 0 {
imports = append(imports, fmt.Sprintf("%s \"%s\"", strings.ToLower(filepath.Base(g.realClientPackage)), g.realClientPackage))
imports = append(imports, fmt.Sprintf("%s \"%s\"", strings.ToLower(path.Base(g.realClientPackage)), g.realClientPackage))
}
return imports
}
@@ -90,7 +90,7 @@ func (g *genFakeForGroup) GenerateType(c *generator.Context, t *types.Type, w io
"type": t,
"GroupGoName": g.groupGoName,
"Version": namer.IC(g.version),
"realClientPackage": strings.ToLower(filepath.Base(g.realClientPackage)),
"realClientPackage": strings.ToLower(path.Base(g.realClientPackage)),
}
if tags.NonNamespaced {
sw.Do(getterImplNonNamespaced, wrapper)

View File

@@ -18,21 +18,20 @@ package fake
import (
"io"
gopath "path"
"path/filepath"
"path"
"strings"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
"k8s.io/code-generator/cmd/client-gen/generators/util"
)
// genFakeForType produces a file for each top-level type.
type genFakeForType struct {
generator.DefaultGen
outputPackage string
generator.GoGenerator
outputPackage string // Must be a Go import-path
group string
version string
groupGoName string
@@ -87,7 +86,7 @@ func hasObjectMeta(t *types.Type) bool {
// GenerateType makes the body of a file implementing the individual typed client for type t.
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)
pkg := path.Base(t.Name.Package)
tags, err := util.ParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
if err != nil {
return err
@@ -153,7 +152,7 @@ func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io.
if generateApply {
// Generated apply builder type references required for generated Apply function
_, gvString := util.ParsePathGroupVersion(g.inputPackage)
m["inputApplyConfig"] = types.Ref(gopath.Join(g.applyConfigurationPackage, gvString), t.Name.Name+"ApplyConfiguration")
m["inputApplyConfig"] = types.Ref(path.Join(g.applyConfigurationPackage, gvString), t.Name.Name+"ApplyConfiguration")
}
if tags.NonNamespaced {
@@ -237,7 +236,7 @@ func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io.
m["resultType"] = &resultType
m["subresourcePath"] = e.SubResourcePath
if e.HasVerb("apply") {
m["inputApplyConfig"] = types.Ref(gopath.Join(g.applyConfigurationPackage, inputGVString), inputType.Name.Name+"ApplyConfiguration")
m["inputApplyConfig"] = types.Ref(path.Join(g.applyConfigurationPackage, inputGVString), inputType.Name.Name+"ApplyConfiguration")
}
if e.HasVerb("get") {
@@ -300,7 +299,9 @@ func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io.
// TODO: Make the verbs in templates parametrized so the strings.Replace() is
// not needed.
func adjustTemplate(name, verbType, template string) string {
return strings.Replace(template, " "+strings.Title(verbType), " "+name, -1)
//nolint:staticcheck
// TODO: convert this to use golang.org/x/text/cases
return strings.ReplaceAll(template, " "+strings.Title(verbType), " "+name)
}
// template for the struct that implements the type's interface

View File

@@ -19,22 +19,21 @@ package generators
import (
"fmt"
"io"
"path/filepath"
"path"
"strings"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
)
// genClientset generates a package for a clientset.
type genClientset struct {
generator.DefaultGen
generator.GoGenerator
groups []clientgentypes.GroupVersions
groupGoNames map[clientgentypes.GroupVersion]string
clientsetPackage string
outputPackage string
clientsetPackage string // must be a Go import-path
imports namer.ImportTracker
clientsetGenerated bool
}
@@ -43,7 +42,7 @@ var _ generator.Generator = &genClientset{}
func (g *genClientset) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
"raw": namer.NewRawNamer(g.outputPackage, g.imports),
"raw": namer.NewRawNamer(g.clientsetPackage, g.imports),
}
}
@@ -58,7 +57,7 @@ func (g *genClientset) Imports(c *generator.Context) (imports []string) {
imports = append(imports, g.imports.ImportLines()...)
for _, group := range g.groups {
for _, version := range group.Versions {
typedClientPath := filepath.Join(g.clientsetPackage, "typed", strings.ToLower(group.PackageName), strings.ToLower(version.NonEmpty()))
typedClientPath := path.Join(g.clientsetPackage, "typed", strings.ToLower(group.PackageName), strings.ToLower(version.NonEmpty()))
groupAlias := strings.ToLower(g.groupGoNames[clientgentypes.GroupVersion{Group: group.Group, Version: version.Version}])
imports = append(imports, fmt.Sprintf("%s%s \"%s\"", groupAlias, strings.ToLower(version.NonEmpty()), typedClientPath))
}

View File

@@ -22,13 +22,13 @@ import (
"path/filepath"
"strings"
"k8s.io/gengo/generator"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/types"
)
// genExpansion produces a file for a group client, e.g. ExtensionsClient for the extension group.
type genExpansion struct {
generator.DefaultGen
generator.GoGenerator
groupPackagePath string
// types in a group
types []*types.Type

View File

@@ -18,19 +18,19 @@ package generators
import (
"io"
"path/filepath"
"path"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/gengo/v2"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
"k8s.io/code-generator/cmd/client-gen/generators/util"
"k8s.io/code-generator/cmd/client-gen/path"
)
// genGroup produces a file for a group client, e.g. ExtensionsClient for the extension group.
type genGroup struct {
generator.DefaultGen
generator.GoGenerator
outputPackage string
group string
version string
@@ -40,7 +40,7 @@ type genGroup struct {
types []*types.Type
imports namer.ImportTracker
inputPackage string
clientsetPackage string
clientsetPackage string // must be a Go import-path
// If the genGroup has been called. This generator should only execute once.
called bool
}
@@ -64,7 +64,7 @@ func (g *genGroup) Namers(c *generator.Context) namer.NameSystems {
func (g *genGroup) Imports(c *generator.Context) (imports []string) {
imports = append(imports, g.imports.ImportLines()...)
imports = append(imports, filepath.Join(g.clientsetPackage, "scheme"))
imports = append(imports, path.Join(g.clientsetPackage, "scheme"))
return
}
@@ -83,8 +83,8 @@ func (g *genGroup) GenerateType(c *generator.Context, t *types.Type, w io.Writer
groupName = ""
}
// allow user to define a group name that's different from the one parsed from the directory.
p := c.Universe.Package(path.Vendorless(g.inputPackage))
if override := types.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil {
p := c.Universe.Package(g.inputPackage)
if override := gengo.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil {
groupName = override[0]
}
@@ -104,7 +104,7 @@ func (g *genGroup) GenerateType(c *generator.Context, t *types.Type, w io.Writer
"RESTHTTPClientFor": c.Universe.Function(types.Name{Package: "k8s.io/client-go/rest", Name: "HTTPClientFor"}),
"restRESTClientFor": c.Universe.Function(types.Name{Package: "k8s.io/client-go/rest", Name: "RESTClientFor"}),
"restRESTClientForConfigAndClient": c.Universe.Function(types.Name{Package: "k8s.io/client-go/rest", Name: "RESTClientForConfigAndClient"}),
"SchemeGroupVersion": c.Universe.Variable(types.Name{Package: path.Vendorless(g.inputPackage), Name: "SchemeGroupVersion"}),
"SchemeGroupVersion": c.Universe.Variable(types.Name{Package: g.inputPackage, Name: "SchemeGroupVersion"}),
}
sw.Do(groupInterfaceTemplate, m)
sw.Do(groupClientTemplate, m)

View File

@@ -19,23 +19,22 @@ package generators
import (
"io"
"path"
"path/filepath"
"strings"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
"k8s.io/code-generator/cmd/client-gen/generators/util"
)
// genClientForType produces a file for each top-level type.
type genClientForType struct {
generator.DefaultGen
outputPackage string
generator.GoGenerator
outputPackage string // must be a Go import-path
inputPackage string
clientsetPackage string
applyConfigurationPackage string
clientsetPackage string // must be a Go import-path
applyConfigurationPackage string // must be a Go import-path
group string
version string
groupGoName string
@@ -81,7 +80,7 @@ func (g *genClientForType) GenerateType(c *generator.Context, t *types.Type, w i
defaultVerbTemplates := buildDefaultVerbTemplates(generateApply)
subresourceDefaultVerbTemplates := buildSubresourceDefaultVerbTemplates(generateApply)
sw := generator.NewSnippetWriter(w, c, "$", "$")
pkg := filepath.Base(t.Name.Package)
pkg := path.Base(t.Name.Package)
tags, err := util.ParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
if err != nil {
return err
@@ -120,8 +119,12 @@ func (g *genClientForType) GenerateType(c *generator.Context, t *types.Type, w i
}
var updatedVerbtemplate string
if _, exists := subresourceDefaultVerbTemplates[e.VerbType]; e.IsSubresource() && exists {
//nolint:staticcheck
// TODO: convert this to use golang.org/x/text/cases
updatedVerbtemplate = e.VerbName + "(" + strings.TrimPrefix(subresourceDefaultVerbTemplates[e.VerbType], strings.Title(e.VerbType)+"(")
} else {
//nolint:staticcheck
// TODO: convert this to use golang.org/x/text/cases
updatedVerbtemplate = e.VerbName + "(" + strings.TrimPrefix(defaultVerbTemplates[e.VerbType], strings.Title(e.VerbType)+"(")
}
extendedMethod := extendedInterfaceMethod{
@@ -167,7 +170,7 @@ func (g *genClientForType) GenerateType(c *generator.Context, t *types.Type, w i
"ApplyPatchType": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/types", Name: "ApplyPatchType"}),
"watchInterface": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/watch", Name: "Interface"}),
"RESTClientInterface": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Interface"}),
"schemeParameterCodec": c.Universe.Variable(types.Name{Package: filepath.Join(g.clientsetPackage, "scheme"), Name: "ParameterCodec"}),
"schemeParameterCodec": c.Universe.Variable(types.Name{Package: path.Join(g.clientsetPackage, "scheme"), Name: "ParameterCodec"}),
"jsonMarshal": c.Universe.Type(types.Name{Package: "encoding/json", Name: "Marshal"}),
}
@@ -345,7 +348,9 @@ func (g *genClientForType) GenerateType(c *generator.Context, t *types.Type, w i
// TODO: Make the verbs in templates parametrized so the strings.Replace() is
// not needed.
func adjustTemplate(name, verbType, template string) string {
return strings.Replace(template, " "+strings.Title(verbType), " "+name, -1)
//nolint:staticcheck
// TODO: convert this to use golang.org/x/text/cases
return strings.ReplaceAll(template, " "+strings.Title(verbType), " "+name)
}
func generateInterface(defaultVerbTemplates map[string]string, tags util.Tags) string {

View File

@@ -20,24 +20,24 @@ import (
"fmt"
"io"
"os"
"path"
"path/filepath"
"strings"
"k8s.io/code-generator/cmd/client-gen/path"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
)
// GenScheme produces a package for a clientset with the scheme, codecs and parameter codecs.
type GenScheme struct {
generator.DefaultGen
OutputPackage string
generator.GoGenerator
OutputPkg string // Must be a Go import-path
OutputPath string // optional
Groups []clientgentypes.GroupVersions
GroupGoNames map[clientgentypes.GroupVersion]string
InputPackages map[clientgentypes.GroupVersion]string
OutputPath string
ImportTracker namer.ImportTracker
PrivateScheme bool
CreateRegistry bool
@@ -46,7 +46,7 @@ type GenScheme struct {
func (g *GenScheme) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
"raw": namer.NewRawNamer(g.OutputPackage, g.ImportTracker),
"raw": namer.NewRawNamer(g.OutputPkg, g.ImportTracker),
}
}
@@ -66,14 +66,14 @@ func (g *GenScheme) Imports(c *generator.Context) (imports []string) {
if g.CreateRegistry {
// import the install package for internal clientsets instead of the type package with register.go
if version.Version != "" {
packagePath = filepath.Dir(packagePath)
packagePath = path.Dir(packagePath)
}
packagePath = filepath.Join(packagePath, "install")
packagePath = path.Join(packagePath, "install")
imports = append(imports, fmt.Sprintf("%s \"%s\"", groupAlias, path.Vendorless(packagePath)))
imports = append(imports, fmt.Sprintf("%s \"%s\"", groupAlias, packagePath))
break
} else {
imports = append(imports, fmt.Sprintf("%s%s \"%s\"", groupAlias, strings.ToLower(version.Version.NonEmpty()), path.Vendorless(packagePath)))
imports = append(imports, fmt.Sprintf("%s%s \"%s\"", groupAlias, strings.ToLower(version.Version.NonEmpty()), packagePath))
}
}
}

View File

@@ -21,7 +21,7 @@ import (
"fmt"
"strings"
"k8s.io/gengo/types"
"k8s.io/gengo/v2"
)
var supportedTags = []string{
@@ -192,7 +192,7 @@ func MustParseClientGenTags(lines []string) Tags {
// tags are provided.
func ParseClientGenTags(lines []string) (Tags, error) {
ret := Tags{}
values := types.ExtractCommentTags("+", lines)
values := gengo.ExtractCommentTags("+", lines)
var value []string
value, ret.GenerateClient = values["genclient"]
// Check the old format and error when used to avoid generating client when //+genclient=false

View File

@@ -23,40 +23,44 @@ import (
"github.com/spf13/pflag"
"k8s.io/klog/v2"
generatorargs "k8s.io/code-generator/cmd/client-gen/args"
"k8s.io/code-generator/cmd/client-gen/args"
"k8s.io/code-generator/cmd/client-gen/generators"
"k8s.io/code-generator/pkg/util"
"k8s.io/gengo/v2"
"k8s.io/gengo/v2/generator"
)
func main() {
klog.InitFlags(nil)
genericArgs, customArgs := generatorargs.NewDefaults()
args := args.New()
// Override defaults.
// TODO: move this out of client-gen
genericArgs.OutputPackagePath = "k8s.io/kubernetes/pkg/client/clientset_generated/"
genericArgs.AddFlags(pflag.CommandLine)
customArgs.AddFlags(pflag.CommandLine, "k8s.io/kubernetes/pkg/apis") // TODO: move this input path out of client-gen
args.AddFlags(pflag.CommandLine, "k8s.io/kubernetes/pkg/apis") // TODO: move this input path out of client-gen
flag.Set("logtostderr", "true")
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
pflag.Parse()
// add group version package as input dirs for gengo
for _, pkg := range customArgs.Groups {
inputPkgs := []string{}
for _, pkg := range args.Groups {
for _, v := range pkg.Versions {
genericArgs.InputDirs = append(genericArgs.InputDirs, v.Package)
inputPkgs = append(inputPkgs, v.Package)
}
}
if err := generatorargs.Validate(genericArgs); err != nil {
if err := args.Validate(); err != nil {
klog.Fatalf("Error: %v", err)
}
if err := genericArgs.Execute(
generators.NameSystems(util.PluralExceptionListToMapOrDie(customArgs.PluralExceptions)),
myTargets := func(context *generator.Context) []generator.Target {
return generators.GetTargets(context, args)
}
if err := gengo.Execute(
generators.NameSystems(util.PluralExceptionListToMapOrDie(args.PluralExceptions)),
generators.DefaultNameSystem(),
generators.Packages,
myTargets,
gengo.StdBuildTag,
inputPkgs,
); err != nil {
klog.Fatalf("Error: %v", err)
}

View File

@@ -1,31 +0,0 @@
/*
Copyright 2017 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 path
import "strings"
// Vendorless removes the longest match of "*/vendor/" from the front of p.
// It is useful if a package locates in vendor/, e.g.,
// k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/apis/meta/v1, because gengo
// indexes the package with its import path, e.g.,
// k8s.io/apimachinery/pkg/apis/meta/v1,
func Vendorless(p string) string {
if pos := strings.LastIndex(p, "/vendor/"); pos != -1 {
return p[pos+len("/vendor/"):]
}
return p
}

View File

@@ -22,7 +22,7 @@ import (
"sort"
"strings"
"k8s.io/gengo/namer"
"k8s.io/gengo/v2/namer"
)
// ToGroupVersion turns "group/version" string into a GroupVersion struct. It reports error
@@ -116,6 +116,6 @@ func ToGroupInstallPackages(groups []GroupVersions, groupGoNames map[GroupVersio
}
// NormalizeGroupVersion calls normalizes the GroupVersion.
//func NormalizeGroupVersion(gv GroupVersion) GroupVersion {
// return GroupVersion{Group: gv.Group.NonEmpty(), Version: gv.Version, NonEmptyVersion: normalization.Version(gv.Version)}
//}
// func NormalizeGroupVersion(gv GroupVersion) GroupVersion {
// return GroupVersion{Group: gv.Group.NonEmpty(), Version: gv.Version, NonEmptyVersion: normalization.Version(gv.Version)}
// }

View File

@@ -20,7 +20,6 @@ import (
"fmt"
"github.com/spf13/pflag"
"k8s.io/gengo/args"
)
// DefaultBasePeerDirs are the peer-dirs nearly everybody will use, i.e. those coming from
@@ -31,8 +30,10 @@ var DefaultBasePeerDirs = []string{
"k8s.io/apimachinery/pkg/runtime",
}
// CustomArgs is used by the gengo framework to pass args specific to this generator.
type CustomArgs struct {
type Args struct {
// The filename of the generated results.
OutputFile string
// Base peer dirs which nearly everybody will use, i.e. outside of Kubernetes core. Peer dirs
// are declared to make the generator pick up manually written conversion funcs from external
// packages.
@@ -52,39 +53,40 @@ type CustomArgs struct {
// (within the allowed uses of unsafe) and is equivalent to a proposed Golang change to
// allow structs that are identical to be assigned to each other.
SkipUnsafe bool
// GoHeaderFile is the path to a boilerplate header file for generated
// code.
GoHeaderFile string
}
// NewDefaults returns default arguments for the generator.
func NewDefaults() (*args.GeneratorArgs, *CustomArgs) {
genericArgs := args.Default().WithoutDefaultFlagParsing()
customArgs := &CustomArgs{
// New returns default arguments for the generator.
func New() *Args {
return &Args{
BasePeerDirs: DefaultBasePeerDirs,
SkipUnsafe: false,
}
genericArgs.CustomArgs = customArgs
genericArgs.OutputFileBaseName = "conversion_generated"
return genericArgs, customArgs
}
// AddFlags add the generator flags to the flag set.
func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet) {
fs.StringSliceVar(&ca.BasePeerDirs, "base-peer-dirs", ca.BasePeerDirs,
func (args *Args) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&args.OutputFile, "output-file", "generated.conversion.go",
"the name of the file to be generated")
fs.StringSliceVar(&args.BasePeerDirs, "base-peer-dirs", args.BasePeerDirs,
"Comma-separated list of apimachinery import paths which are considered, after tag-specified peers, for conversions. Only change these if you have very good reasons.")
fs.StringSliceVar(&ca.ExtraPeerDirs, "extra-peer-dirs", ca.ExtraPeerDirs,
fs.StringSliceVar(&args.ExtraPeerDirs, "extra-peer-dirs", args.ExtraPeerDirs,
"Application specific comma-separated list of import paths which are considered, after tag-specified peers and base-peer-dirs, for conversions.")
fs.StringSliceVar(&ca.ExtraDirs, "extra-dirs", ca.ExtraDirs,
fs.StringSliceVar(&args.ExtraDirs, "extra-dirs", args.ExtraDirs,
"Application specific comma-separated list of import paths which are loaded and considered for callable conversions, but are not considered peers for conversion.")
fs.BoolVar(&ca.SkipUnsafe, "skip-unsafe", ca.SkipUnsafe,
fs.BoolVar(&args.SkipUnsafe, "skip-unsafe", args.SkipUnsafe,
"If true, will not generate code using unsafe pointer conversions; resulting code may be slower.")
fs.StringVar(&args.GoHeaderFile, "go-header-file", "",
"the path to a file containing boilerplate header text; the string \"YEAR\" will be replaced with the current 4-digit year")
}
// Validate checks the given arguments.
func Validate(genericArgs *args.GeneratorArgs) error {
_ = genericArgs.CustomArgs.(*CustomArgs)
if len(genericArgs.OutputFileBaseName) == 0 {
return fmt.Errorf("output file base name cannot be empty")
func (args *Args) Validate() error {
if len(args.OutputFile) == 0 {
return fmt.Errorf("--output-file must be specified")
}
return nil
}

View File

@@ -20,20 +20,17 @@ import (
"bytes"
"fmt"
"io"
"path/filepath"
"path"
"reflect"
"sort"
"strings"
"k8s.io/gengo/args"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/code-generator/cmd/conversion-gen/args"
"k8s.io/gengo/v2"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
"k8s.io/klog/v2"
conversionargs "k8s.io/code-generator/cmd/conversion-gen/args"
genutil "k8s.io/code-generator/pkg/util"
)
// These are the comment tags that carry parameters for conversion generation.
@@ -52,24 +49,24 @@ const (
)
func extractTag(comments []string) []string {
return types.ExtractCommentTags("+", comments)[tagName]
return gengo.ExtractCommentTags("+", comments)[tagName]
}
func extractExplicitFromTag(comments []string) []string {
return types.ExtractCommentTags("+", comments)[explicitFromTagName]
return gengo.ExtractCommentTags("+", comments)[explicitFromTagName]
}
func extractExternalTypesTag(comments []string) []string {
return types.ExtractCommentTags("+", comments)[externalTypesTagName]
return gengo.ExtractCommentTags("+", comments)[externalTypesTagName]
}
func isCopyOnly(comments []string) bool {
values := types.ExtractCommentTags("+", comments)["k8s:conversion-fn"]
values := gengo.ExtractCommentTags("+", comments)["k8s:conversion-fn"]
return len(values) == 1 && values[0] == "copy-only"
}
func isDrop(comments []string) bool {
values := types.ExtractCommentTags("+", comments)["k8s:conversion-fn"]
values := gengo.ExtractCommentTags("+", comments)["k8s:conversion-fn"]
return len(values) == 1 && values[0] == "drop"
}
@@ -136,7 +133,7 @@ func getManualConversionFunctions(context *generator.Context, pkg *types.Package
klog.Warning("Skipping nil package passed to getManualConversionFunctions")
return
}
klog.V(5).Infof("Scanning for conversion functions in %v", pkg.Name)
klog.V(3).Infof("Scanning for conversion functions in %v", pkg.Path)
scopeName := types.Ref(conversionPackagePath, "Scope").Name
errorName := types.Ref("", "error").Name
@@ -152,27 +149,27 @@ func getManualConversionFunctions(context *generator.Context, pkg *types.Package
klog.Errorf("Function without signature: %#v", f)
continue
}
klog.V(8).Infof("Considering function %s", f.Name)
klog.V(6).Infof("Considering function %s", f.Name)
signature := f.Underlying.Signature
// Check whether the function is conversion function.
// Note that all of them have signature:
// func Convert_inType_To_outType(inType, outType, conversion.Scope) error
if signature.Receiver != nil {
klog.V(8).Infof("%s has a receiver", f.Name)
klog.V(6).Infof("%s has a receiver", f.Name)
continue
}
if len(signature.Parameters) != 3 || signature.Parameters[2].Name != scopeName {
klog.V(8).Infof("%s has wrong parameters", f.Name)
klog.V(6).Infof("%s has wrong parameters", f.Name)
continue
}
if len(signature.Results) != 1 || signature.Results[0].Name != errorName {
klog.V(8).Infof("%s has wrong results", f.Name)
klog.V(6).Infof("%s has wrong results", f.Name)
continue
}
inType := signature.Parameters[0]
outType := signature.Parameters[1]
if inType.Kind != types.Pointer || outType.Kind != types.Pointer {
klog.V(8).Infof("%s has wrong parameter types", f.Name)
klog.V(6).Infof("%s has wrong parameter types", f.Name)
continue
}
// Now check if the name satisfies the convention.
@@ -180,7 +177,7 @@ func getManualConversionFunctions(context *generator.Context, pkg *types.Package
args := argsFromType(inType.Elem, outType.Elem)
sw.Do("Convert_$.inType|public$_To_$.outType|public$", args)
if f.Name.Name == buffer.String() {
klog.V(4).Infof("Found conversion function %s", f.Name)
klog.V(2).Infof("Found conversion function %s", f.Name)
key := conversionPair{inType.Elem, outType.Elem}
// We might scan the same package twice, and that's OK.
if v, ok := manualMap[key]; ok && v != nil && v.Name.Package != pkg.Path {
@@ -192,20 +189,19 @@ func getManualConversionFunctions(context *generator.Context, pkg *types.Package
if strings.HasPrefix(f.Name.Name, "Convert_") {
klog.Errorf("Rename function %s %s -> %s to match expected conversion signature", f.Name.Package, f.Name.Name, buffer.String())
}
klog.V(8).Infof("%s has wrong name", f.Name)
klog.V(3).Infof("%s has wrong name", f.Name)
}
buffer.Reset()
}
}
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
boilerplate, err := arguments.LoadGoBoilerplate()
func GetTargets(context *generator.Context, args *args.Args) []generator.Target {
boilerplate, err := gengo.GoBoilerplate(args.GoHeaderFile, gengo.StdBuildTag, gengo.StdGeneratedBy)
if err != nil {
klog.Fatalf("Failed loading boilerplate: %v", err)
}
packages := generator.Packages{}
header := append([]byte(fmt.Sprintf("// +build !%s\n\n", arguments.GeneratedBuildTag)), boilerplate...)
targets := []generator.Target{}
// Accumulate pre-existing conversion functions.
// TODO: This is too ad-hoc. We need a better way.
@@ -219,131 +215,122 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
// have non-trivial conversion
memoryEquivalentTypes := equalMemoryTypes{}
// We are generating conversions only for packages that are explicitly
// passed as InputDir.
processed := map[string]bool{}
// First load other "input" packages. We do this as a single call because
// it is MUCH faster.
filteredInputs := make([]string, 0, len(context.Inputs))
otherPkgs := make([]string, 0, len(context.Inputs))
pkgToPeers := map[string][]string{}
pkgToExternal := map[string]string{}
for _, i := range context.Inputs {
// skip duplicates
if processed[i] {
continue
}
processed[i] = true
klog.V(3).Infof("pre-processing pkg %q", i)
klog.V(5).Infof("considering pkg %q", i)
pkg := context.Universe[i]
// typesPkg is where the versioned types are defined. Sometimes it is
// different from pkg. For example, kubernetes core/v1 types are defined
// in vendor/k8s.io/api/core/v1, while pkg is at pkg/api/v1.
typesPkg := pkg
if pkg == nil {
// If the input had no Go files, for example.
continue
}
// Add conversion and defaulting functions.
getManualConversionFunctions(context, pkg, manualConversions)
// Only generate conversions for packages which explicitly request it
// by specifying one or more "+k8s:conversion-gen=<peer-pkg>"
// in their doc.go file.
peerPkgs := extractTag(pkg.Comments)
if peerPkgs != nil {
klog.V(5).Infof(" tags: %q", peerPkgs)
if len(peerPkgs) == 1 && peerPkgs[0] == "false" {
// If a single +k8s:conversion-gen=false tag is defined, we still want
// the generator to fire for this package for explicit conversions, but
// we are clearing the peerPkgs to not generate any standard conversions.
peerPkgs = nil
}
} else {
klog.V(5).Infof(" no tag")
if peerPkgs == nil {
klog.V(3).Infof(" no tag")
continue
}
skipUnsafe := false
extraDirs := []string{}
if customArgs, ok := arguments.CustomArgs.(*conversionargs.CustomArgs); ok {
if len(peerPkgs) > 0 {
peerPkgs = append(peerPkgs, customArgs.BasePeerDirs...)
peerPkgs = append(peerPkgs, customArgs.ExtraPeerDirs...)
}
extraDirs = customArgs.ExtraDirs
skipUnsafe = customArgs.SkipUnsafe
klog.V(3).Infof(" tags: %q", peerPkgs)
if len(peerPkgs) == 1 && peerPkgs[0] == "false" {
// If a single +k8s:conversion-gen=false tag is defined, we still want
// the generator to fire for this package for explicit conversions, but
// we are clearing the peerPkgs to not generate any standard conversions.
peerPkgs = nil
} else {
// Save peers for each input
pkgToPeers[i] = peerPkgs
}
otherPkgs = append(otherPkgs, peerPkgs...)
// Keep this one for further processing.
filteredInputs = append(filteredInputs, i)
// if the external types are not in the same package where the conversion functions to be generated
// if the external types are not in the same package where the
// conversion functions to be generated
externalTypesValues := extractExternalTypesTag(pkg.Comments)
if externalTypesValues != nil {
if len(externalTypesValues) != 1 {
klog.Fatalf(" expect only one value for %q tag, got: %q", externalTypesTagName, externalTypesValues)
}
externalTypes := externalTypesValues[0]
klog.V(5).Infof(" external types tags: %q", externalTypes)
var err error
typesPkg, err = context.AddDirectory(externalTypes)
if err != nil {
klog.Fatalf("cannot import package %s", externalTypes)
}
// update context.Order to the latest context.Universe
orderer := namer.Orderer{Namer: namer.NewPublicNamer(1)}
context.Order = orderer.OrderUniverse(context.Universe)
klog.V(3).Infof(" external types tags: %q", externalTypes)
otherPkgs = append(otherPkgs, externalTypes)
pkgToExternal[i] = externalTypes
} else {
pkgToExternal[i] = i
}
}
// 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.
for i := range peerPkgs {
peerPkgs[i] = genutil.Vendorless(peerPkgs[i])
}
for i := range extraDirs {
extraDirs[i] = genutil.Vendorless(extraDirs[i])
// Make sure explicit peer-packages are added.
peers := args.BasePeerDirs
peers = append(peers, args.ExtraPeerDirs...)
if expanded, err := context.FindPackages(peers...); err != nil {
klog.Fatalf("cannot find peer packages: %v", err)
} else {
otherPkgs = append(otherPkgs, expanded...)
// for each pkg, add these extras, too
for k := range pkgToPeers {
pkgToPeers[k] = append(pkgToPeers[k], expanded...)
}
}
// Make sure our peer-packages are added and fully parsed.
for _, pp := range append(peerPkgs, extraDirs...) {
context.AddDir(pp)
p := context.Universe[pp]
if nil == p {
klog.Fatalf("failed to find pkg: %s", pp)
}
getManualConversionFunctions(context, p, manualConversions)
if len(otherPkgs) > 0 {
if _, err := context.LoadPackages(otherPkgs...); err != nil {
klog.Fatalf("cannot load packages: %v", err)
}
}
// update context.Order to the latest context.Universe
orderer := namer.Orderer{Namer: namer.NewPublicNamer(1)}
context.Order = orderer.OrderUniverse(context.Universe)
// Look for conversion functions in the peer-packages.
for _, pp := range otherPkgs {
p := context.Universe[pp]
if p == nil {
klog.Fatalf("failed to find pkg: %s", pp)
}
getManualConversionFunctions(context, p, manualConversions)
}
// We are generating conversions only for packages that are explicitly
// passed as InputDir.
for _, i := range filteredInputs {
klog.V(3).Infof("considering pkg %q", i)
pkg := context.Universe[i]
// typesPkg is where the versioned types are defined. Sometimes it is
// different from pkg. For example, kubernetes core/v1 types are defined
// in k8s.io/api/core/v1, while pkg is at pkg/api/v1.
typesPkg := pkg
// Add conversion and defaulting functions.
getManualConversionFunctions(context, pkg, manualConversions)
// Find the right input pkg, which might not be this one.
externalTypes := pkgToExternal[i]
typesPkg = context.Universe[externalTypes]
unsafeEquality := TypesEqual(memoryEquivalentTypes)
if skipUnsafe {
if args.SkipUnsafe {
unsafeEquality = noEquality{}
}
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: filepath.Base(pkg.Path),
PackagePath: path,
HeaderText: header,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
return []generator.Generator{
NewGenConversion(arguments.OutputFileBaseName, typesPkg.Path, pkg.Path, manualConversions, peerPkgs, unsafeEquality),
}
},
targets = append(targets,
&generator.SimpleTarget{
PkgName: path.Base(pkg.Path),
PkgPath: pkg.Path,
PkgDir: pkg.Dir, // output pkg is the same as the input
HeaderComment: boilerplate,
FilterFunc: func(c *generator.Context, t *types.Type) bool {
return t.Name.Package == typesPkg.Path
},
GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) {
return []generator.Generator{
NewGenConversion(args.OutputFile, typesPkg.Path, pkg.Path, manualConversions, pkgToPeers[pkg.Path], unsafeEquality),
}
},
})
}
@@ -351,14 +338,14 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
// from being a candidate for unsafe conversion
for k, v := range manualConversions {
if isCopyOnly(v.CommentLines) {
klog.V(5).Infof("Conversion function %s will not block memory copy because it is copy-only", v.Name)
klog.V(4).Infof("Conversion function %s will not block memory copy because it is copy-only", v.Name)
continue
}
// this type should be excluded from all equivalence, because the converter must be called.
memoryEquivalentTypes.Skip(k.inType, k.outType)
}
return packages
return targets
}
type equalMemoryTypes map[conversionPair]bool
@@ -466,7 +453,7 @@ type TypesEqual interface {
// genConversion produces a file with a autogenerated conversions.
type genConversion struct {
generator.DefaultGen
generator.GoGenerator
// the package that contains the types that conversion func are going to be
// generated for
typesPackage string
@@ -482,10 +469,10 @@ type genConversion struct {
useUnsafe TypesEqual
}
func NewGenConversion(sanitizedName, typesPackage, outputPackage string, manualConversions conversionFuncMap, peerPkgs []string, useUnsafe TypesEqual) generator.Generator {
func NewGenConversion(outputFilename, typesPackage, outputPackage string, manualConversions conversionFuncMap, peerPkgs []string, useUnsafe TypesEqual) generator.Generator {
return &genConversion{
DefaultGen: generator.DefaultGen{
OptionalName: sanitizedName,
GoGenerator: generator.GoGenerator{
OutputFilename: outputFilename,
},
typesPackage: typesPackage,
outputPackage: outputPackage,
@@ -538,7 +525,7 @@ func (g *genConversion) convertibleOnlyWithinPackage(inType, outType *types.Type
if tagvals[0] != "false" {
klog.Fatalf("Type %v: unsupported %s value: %q", t, tagName, tagvals[0])
}
klog.V(5).Infof("type %v requests no conversion generation, skipping", t)
klog.V(2).Infof("type %v requests no conversion generation, skipping", t)
return false
}
// TODO: Consider generating functions for other kinds too.
@@ -553,7 +540,8 @@ func (g *genConversion) convertibleOnlyWithinPackage(inType, outType *types.Type
}
func getExplicitFromTypes(t *types.Type) []types.Name {
comments := append(t.SecondClosestCommentLines, t.CommentLines...)
comments := t.SecondClosestCommentLines
comments = append(comments, t.CommentLines...)
paths := extractExplicitFromTag(comments)
result := []types.Name{}
for _, path := range paths {
@@ -638,7 +626,7 @@ func (g *genConversion) preexists(inType, outType *types.Type) (*types.Type, boo
}
func (g *genConversion) Init(c *generator.Context, w io.Writer) error {
klogV := klog.V(5)
klogV := klog.V(6)
if klogV.Enabled() {
if m, ok := g.useUnsafe.(equalMemoryTypes); ok {
var result []string
@@ -694,10 +682,7 @@ func (g *genConversion) Init(c *generator.Context, w io.Writer) error {
}
// sort by name of the conversion function
sort.Slice(pairs, func(i, j int) bool {
if g.manualConversions[pairs[i]].Name.Name < g.manualConversions[pairs[j]].Name.Name {
return true
}
return false
return g.manualConversions[pairs[i]].Name.Name < g.manualConversions[pairs[j]].Name.Name
})
for _, pair := range pairs {
args := argsFromType(pair.inType, pair.outType).With("Scope", types.Ref(conversionPackagePath, "Scope")).With("fn", g.manualConversions[pair])
@@ -731,7 +716,7 @@ func (g *genConversion) GenerateType(c *generator.Context, t *types.Type, w io.W
}
switch {
case inType.Name.Package == "net/url" && inType.Name.Name == "Values":
g.generateFromUrlValues(inType, t, sw)
g.generateFromURLValues(inType, t, sw)
default:
klog.Errorf("Not supported input type: %#v", inType.Name)
}
@@ -771,7 +756,7 @@ func (g *genConversion) generateConversion(inType, outType *types.Type, sw *gene
// at any nesting level. This makes the autogenerator easy to understand, and
// the compiler shouldn't care.
func (g *genConversion) generateFor(inType, outType *types.Type, sw *generator.SnippetWriter) {
klog.V(5).Infof("generating %v -> %v", inType, outType)
klog.V(4).Infof("generating %v -> %v", inType, outType)
var f func(*types.Type, *types.Type, *generator.SnippetWriter)
switch inType.Kind {
@@ -948,7 +933,7 @@ func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.Snip
sw.Do("}\n", nil)
continue
}
klog.V(5).Infof("Skipped function %s because it is copy-only and we can use direct assignment", function.Name)
klog.V(2).Infof("Skipped function %s because it is copy-only and we can use direct assignment", function.Name)
}
// If we can't auto-convert, punt before we emit any code.
@@ -1087,7 +1072,7 @@ func (g *genConversion) doUnknown(inType, outType *types.Type, sw *generator.Sni
sw.Do("// FIXME: Type $.|raw$ is unsupported.\n", inType)
}
func (g *genConversion) generateFromUrlValues(inType, outType *types.Type, sw *generator.SnippetWriter) {
func (g *genConversion) generateFromURLValues(inType, outType *types.Type, sw *generator.SnippetWriter) {
args := generator.Args{
"inType": inType,
"outType": outType,

View File

@@ -102,36 +102,34 @@ import (
generatorargs "k8s.io/code-generator/cmd/conversion-gen/args"
"k8s.io/code-generator/cmd/conversion-gen/generators"
"k8s.io/gengo/v2"
"k8s.io/gengo/v2/generator"
)
func main() {
klog.InitFlags(nil)
genericArgs, customArgs := generatorargs.NewDefaults()
args := generatorargs.New()
genericArgs.AddFlags(pflag.CommandLine)
customArgs.AddFlags(pflag.CommandLine)
args.AddFlags(pflag.CommandLine)
flag.Set("logtostderr", "true")
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
pflag.Parse()
// k8s.io/apimachinery/pkg/runtime contains a number of manual conversions,
// that we need to generate conversions.
// Packages being dependencies of explicitly requested packages are only
// partially scanned - only types explicitly used are being traversed.
// Not used functions or types are omitted.
// Adding this explicitly to InputDirs ensures that the package is fully
// scanned and all functions are parsed and processed.
genericArgs.InputDirs = append(genericArgs.InputDirs, "k8s.io/apimachinery/pkg/runtime")
if err := generatorargs.Validate(genericArgs); err != nil {
if err := args.Validate(); err != nil {
klog.Fatalf("Error: %v", err)
}
myTargets := func(context *generator.Context) []generator.Target {
return generators.GetTargets(context, args)
}
// Run it.
if err := genericArgs.Execute(
if err := gengo.Execute(
generators.NameSystems(),
generators.DefaultNameSystem(),
generators.Packages,
myTargets,
gengo.StdBuildTag,
pflag.Args(),
); err != nil {
klog.Fatalf("Error: %v", err)
}

View File

@@ -20,35 +20,33 @@ import (
"fmt"
"github.com/spf13/pflag"
"k8s.io/gengo/args"
"k8s.io/gengo/examples/deepcopy-gen/generators"
)
// CustomArgs is used by the gengo framework to pass args specific to this generator.
type CustomArgs generators.CustomArgs
type Args struct {
OutputFile string
BoundingDirs []string // Only deal with types rooted under these dirs.
GoHeaderFile string
}
// NewDefaults returns default arguments for the generator.
func NewDefaults() (*args.GeneratorArgs, *CustomArgs) {
genericArgs := args.Default().WithoutDefaultFlagParsing()
customArgs := &CustomArgs{}
genericArgs.CustomArgs = (*generators.CustomArgs)(customArgs) // convert to upstream type to make type-casts work there
genericArgs.OutputFileBaseName = "deepcopy_generated"
return genericArgs, customArgs
// New returns default arguments for the generator.
func New() *Args {
return &Args{}
}
// AddFlags add the generator flags to the flag set.
func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet) {
fs.StringSliceVar(&ca.BoundingDirs, "bounding-dirs", ca.BoundingDirs,
func (args *Args) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&args.OutputFile, "output-file", "generated.deepcopy.go",
"the name of the file to be generated")
fs.StringSliceVar(&args.BoundingDirs, "bounding-dirs", args.BoundingDirs,
"Comma-separated list of import paths which bound the types for which deep-copies will be generated.")
fs.StringVar(&args.GoHeaderFile, "go-header-file", "",
"the path to a file containing boilerplate header text; the string \"YEAR\" will be replaced with the current 4-digit year")
}
// Validate checks the given arguments.
func Validate(genericArgs *args.GeneratorArgs) error {
_ = genericArgs.CustomArgs.(*generators.CustomArgs)
if len(genericArgs.OutputFileBaseName) == 0 {
return fmt.Errorf("output file base name cannot be empty")
func (args *Args) Validate() error {
if len(args.OutputFile) == 0 {
return fmt.Errorf("--output-file must be specified")
}
return nil
}

View File

@@ -0,0 +1,892 @@
/*
Copyright 2015 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 generators
import (
"fmt"
"io"
"path"
"sort"
"strings"
"k8s.io/code-generator/cmd/deepcopy-gen/args"
"k8s.io/gengo/v2"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
"k8s.io/klog/v2"
)
// This is the comment tag that carries parameters for deep-copy generation.
const (
tagEnabledName = "k8s:deepcopy-gen"
interfacesTagName = tagEnabledName + ":interfaces"
interfacesNonPointerTagName = tagEnabledName + ":nonpointer-interfaces" // attach the DeepCopy<Interface> methods to the
)
// Known values for the comment tag.
const tagValuePackage = "package"
// enabledTagValue holds parameters from a tagName tag.
type enabledTagValue struct {
value string
register bool
}
func extractEnabledTypeTag(t *types.Type) *enabledTagValue {
comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...)
return extractEnabledTag(comments)
}
func extractEnabledTag(comments []string) *enabledTagValue {
tagVals := gengo.ExtractCommentTags("+", comments)[tagEnabledName]
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), tagEnabledName, tagVals)
}
// If we got here we are returning something.
tag := &enabledTagValue{}
// 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", tagEnabledName, parts[i])
}
}
return tag
}
// TODO: This is created only to reduce number of changes in a single PR.
// Remove it and use PublicNamer instead.
func deepCopyNamer() *namer.NameStrategy {
return &namer.NameStrategy{
Join: func(pre string, in []string, post string) string {
return strings.Join(in, "_")
},
PrependPackageNames: 1,
}
}
// NameSystems returns the name system used by the generators in this package.
func NameSystems() namer.NameSystems {
return namer.NameSystems{
"public": deepCopyNamer(),
"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"
}
func GetTargets(context *generator.Context, args *args.Args) []generator.Target {
boilerplate, err := gengo.GoBoilerplate(args.GoHeaderFile, gengo.StdBuildTag, gengo.StdGeneratedBy)
if err != nil {
klog.Fatalf("Failed loading boilerplate: %v", err)
}
boundingDirs := []string{}
if args.BoundingDirs == nil {
args.BoundingDirs = context.Inputs
}
for i := range args.BoundingDirs {
// Strip any trailing slashes - they are not exactly "correct" but
// this is friendlier.
boundingDirs = append(boundingDirs, strings.TrimRight(args.BoundingDirs[i], "/"))
}
targets := []generator.Target{}
for _, i := range context.Inputs {
klog.V(3).Infof("Considering pkg %q", i)
pkg := context.Universe[i]
ptag := extractEnabledTag(pkg.Comments)
ptagValue := ""
ptagRegister := false
if ptag != nil {
ptagValue = ptag.value
if ptagValue != tagValuePackage {
klog.Fatalf("Package %v: unsupported %s value: %q", i, tagEnabledName, ptagValue)
}
ptagRegister = ptag.register
klog.V(3).Infof(" tag.value: %q, tag.register: %t", ptagValue, ptagRegister)
} else {
klog.V(3).Infof(" no tag")
}
// If the pkg-scoped tag says to generate, we can skip scanning types.
pkgNeedsGeneration := (ptagValue == tagValuePackage)
if !pkgNeedsGeneration {
// If the pkg-scoped tag did not exist, scan all types for one that
// explicitly wants generation. Ensure all types that want generation
// can be copied.
var uncopyable []string
for _, t := range pkg.Types {
klog.V(3).Infof(" considering type %q", t.Name.String())
ttag := extractEnabledTypeTag(t)
if ttag != nil && ttag.value == "true" {
klog.V(3).Infof(" tag=true")
if !copyableType(t) {
uncopyable = append(uncopyable, fmt.Sprintf("%v", t))
} else {
pkgNeedsGeneration = true
}
}
}
if len(uncopyable) > 0 {
klog.Fatalf("Types requested deepcopy generation but are not copyable: %s",
strings.Join(uncopyable, ", "))
}
}
if pkgNeedsGeneration {
klog.V(3).Infof("Package %q needs generation", i)
targets = append(targets,
&generator.SimpleTarget{
PkgName: strings.Split(path.Base(pkg.Path), ".")[0],
PkgPath: pkg.Path,
PkgDir: pkg.Dir, // output pkg is the same as the input
HeaderComment: boilerplate,
FilterFunc: func(c *generator.Context, t *types.Type) bool {
return t.Name.Package == pkg.Path
},
GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) {
return []generator.Generator{
NewGenDeepCopy(args.OutputFile, pkg.Path, boundingDirs, (ptagValue == tagValuePackage), ptagRegister),
}
},
})
}
}
return targets
}
// genDeepCopy produces a file with autogenerated deep-copy functions.
type genDeepCopy struct {
generator.GoGenerator
targetPackage string
boundingDirs []string
allTypes bool
registerTypes bool
imports namer.ImportTracker
typesForInit []*types.Type
}
func NewGenDeepCopy(outputFilename, targetPackage string, boundingDirs []string, allTypes, registerTypes bool) generator.Generator {
return &genDeepCopy{
GoGenerator: generator.GoGenerator{
OutputFilename: outputFilename,
},
targetPackage: targetPackage,
boundingDirs: boundingDirs,
allTypes: allTypes,
registerTypes: registerTypes,
imports: generator.NewImportTracker(),
typesForInit: make([]*types.Type, 0),
}
}
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),
}
}
func (g *genDeepCopy) Filter(c *generator.Context, t *types.Type) bool {
// Filter out types not being processed or not copyable within the package.
enabled := g.allTypes
if !enabled {
ttag := extractEnabledTypeTag(t)
if ttag != nil && ttag.value == "true" {
enabled = true
}
}
if !enabled {
return false
}
if !copyableType(t) {
klog.V(3).Infof("Type %v is not copyable", t)
return false
}
klog.V(3).Infof("Type %v is copyable", t)
g.typesForInit = append(g.typesForInit, t)
return true
}
// deepCopyMethod returns the signature of a DeepCopy() method, nil or an error
// if the type does not match. This allows more efficient deep copy
// implementations to be defined by the type's author. The correct signature
// for a type T is:
//
// func (t T) DeepCopy() T
//
// or:
//
// func (t *T) DeepCopy() *T
func deepCopyMethod(t *types.Type) (*types.Signature, error) {
f, found := t.Methods["DeepCopy"]
if !found {
return nil, nil
}
if len(f.Signature.Parameters) != 0 {
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected no parameters", t)
}
if len(f.Signature.Results) != 1 {
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected exactly one result", t)
}
ptrResult := f.Signature.Results[0].Kind == types.Pointer && f.Signature.Results[0].Elem.Name == t.Name
nonPtrResult := f.Signature.Results[0].Name == t.Name
if !ptrResult && !nonPtrResult {
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected to return %s or *%s", t, t.Name.Name, t.Name.Name)
}
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 && !ptrResult {
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected a *%s result for a *%s receiver", t, t.Name.Name, t.Name.Name)
}
if nonPtrRcvr && !nonPtrResult {
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected a %s result for a %s receiver", t, t.Name.Name, t.Name.Name)
}
return f.Signature, nil
}
// deepCopyMethodOrDie returns the signatrue of a DeepCopy method, nil or calls klog.Fatalf
// if the type does not match.
func deepCopyMethodOrDie(t *types.Type) *types.Signature {
ret, err := deepCopyMethod(t)
if err != nil {
klog.Fatal(err)
}
return ret
}
// deepCopyIntoMethod returns the signature of a DeepCopyInto() method, nil or an error
// if the type is wrong. DeepCopyInto allows more efficient deep copy
// implementations to be defined by the type's author. The correct signature
// for a type T is:
//
// func (t T) DeepCopyInto(t *T)
//
// or:
//
// func (t *T) DeepCopyInto(t *T)
func deepCopyIntoMethod(t *types.Type) (*types.Signature, error) {
f, found := t.Methods["DeepCopyInto"]
if !found {
return nil, nil
}
if len(f.Signature.Parameters) != 1 {
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected exactly one parameter", t)
}
if len(f.Signature.Results) != 0 {
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected no result type", t)
}
ptrParam := f.Signature.Parameters[0].Kind == types.Pointer && f.Signature.Parameters[0].Elem.Name == t.Name
if !ptrParam {
return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected parameter of type *%s", t, t.Name.Name)
}
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 DeepCopy signature, expected a receiver of type %s or *%s", t, t.Name.Name, t.Name.Name)
}
return f.Signature, nil
}
// deepCopyIntoMethodOrDie returns the signature of a DeepCopyInto() method, nil or calls klog.Fatalf
// if the type is wrong.
func deepCopyIntoMethodOrDie(t *types.Type) *types.Signature {
ret, err := deepCopyIntoMethod(t)
if err != nil {
klog.Fatal(err)
}
return ret
}
func copyableType(t *types.Type) bool {
// If the type opts out of copy-generation, stop.
ttag := extractEnabledTypeTag(t)
if ttag != nil && ttag.value == "false" {
return false
}
// Filter out private types.
if namer.IsPrivateGoName(t.Name.Name) {
return false
}
if t.Kind == types.Alias {
// if the underlying built-in is not deepcopy-able, deepcopy is opt-in through definition of custom methods.
// Note that aliases of builtins, maps, slices can have deepcopy methods.
if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
return true
} else {
return t.Underlying.Kind != types.Builtin || copyableType(t.Underlying)
}
}
if t.Kind != types.Struct {
return false
}
return true
}
func underlyingType(t *types.Type) *types.Type {
for t.Kind == types.Alias {
t = t.Underlying
}
return t
}
func (g *genDeepCopy) isOtherPackage(pkg string) bool {
if pkg == g.targetPackage {
return false
}
if strings.HasSuffix(pkg, "\""+g.targetPackage+"\"") {
return false
}
return true
}
func (g *genDeepCopy) 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(ts ...*types.Type) generator.Args {
a := generator.Args{
"type": ts[0],
}
for i, t := range ts {
a[fmt.Sprintf("type%d", i+1)] = t
}
return a
}
func (g *genDeepCopy) Init(c *generator.Context, w io.Writer) error {
return nil
}
func (g *genDeepCopy) needsGeneration(t *types.Type) bool {
tag := extractEnabledTypeTag(t)
tv := ""
if tag != nil {
tv = tag.value
if tv != "true" && tv != "false" {
klog.Fatalf("Type %v: unsupported %s value: %q", t, tagEnabledName, tag.value)
}
}
if g.allTypes && tv == "false" {
// The whole package is being generated, but this type has opted out.
klog.V(2).Infof("Not generating for type %v because type opted out", t)
return false
}
if !g.allTypes && tv != "true" {
// The whole package is NOT being generated, and this type has NOT opted in.
klog.V(2).Infof("Not generating for type %v because type did not opt in", t)
return false
}
return true
}
func extractInterfacesTag(t *types.Type) []string {
var result []string
comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...)
values := gengo.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(t *types.Type) (bool, error) {
comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...)
values := gengo.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) deepCopyableInterfacesInner(c *generator.Context, t *types.Type) ([]*types.Type, error) {
if t.Kind != types.Struct {
return nil, nil
}
intfs := extractInterfacesTag(t)
var ts []*types.Type
for _, intf := range intfs {
t := types.ParseFullyQualifiedName(intf)
klog.V(3).Infof("Loading package for interface %v", intf)
_, err := c.LoadPackages(t.Package)
if err != nil {
return nil, err
}
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.deepCopyableInterfacesInner(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(t)
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
}
klog.V(2).Infof("Generating deepcopy functions for type %v", t)
sw := generator.NewSnippetWriter(w, c, "$", "$")
args := argsFromType(t)
if deepCopyIntoMethodOrDie(t) == nil {
sw.Do("// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\n", args)
if isReference(t) {
sw.Do("func (in $.type|raw$) DeepCopyInto(out *$.type|raw$) {\n", args)
sw.Do("{in:=&in\n", nil)
} else {
sw.Do("func (in *$.type|raw$) DeepCopyInto(out *$.type|raw$) {\n", args)
}
if deepCopyMethodOrDie(t) != nil {
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)
}
if isReference(t) {
sw.Do("}\n", nil)
}
sw.Do("}\n\n", nil)
}
if deepCopyMethodOrDie(t) == nil {
sw.Do("// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new $.type|raw$.\n", args)
if isReference(t) {
sw.Do("func (in $.type|raw$) DeepCopy() $.type|raw$ {\n", args)
} else {
sw.Do("func (in *$.type|raw$) DeepCopy() *$.type|raw$ {\n", args)
}
sw.Do("if in == nil { return nil }\n", nil)
sw.Do("out := new($.type|raw$)\n", args)
sw.Do("in.DeepCopyInto(out)\n", nil)
if isReference(t) {
sw.Do("return *out\n", nil)
} else {
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 (in $.type|raw$) DeepCopy%s() $.type2|raw$ {\n", intf.Name.Name), argsFromType(t, intf))
sw.Do("return *in.DeepCopy()", nil)
sw.Do("}\n\n", nil)
} else {
sw.Do(fmt.Sprintf("func (in *$.type|raw$) DeepCopy%s() $.type2|raw$ {\n", intf.Name.Name), argsFromType(t, intf))
sw.Do("if c := in.DeepCopy(); c != nil {\n", nil)
sw.Do("return c\n", nil)
sw.Do("}\n", nil)
sw.Do("return nil\n", nil)
sw.Do("}\n\n", nil)
}
}
return sw.Error()
}
// isReference return true for pointer, maps, slices and aliases of those.
func isReference(t *types.Type) bool {
if t.Kind == types.Pointer || t.Kind == types.Map || t.Kind == types.Slice {
return true
}
return t.Kind == types.Alias && isReference(underlyingType(t))
}
// we use the system of shadowing 'in' and 'out' so that the same code is valid
// at any nesting level. This makes the autogenerator easy to understand, and
// the compiler shouldn't care.
func (g *genDeepCopy) generateFor(t *types.Type, sw *generator.SnippetWriter) {
// derive inner types if t is an alias. We call the do* methods below with the alias type.
// basic rule: generate according to inner type, but construct objects with the alias type.
ut := underlyingType(t)
var f func(*types.Type, *generator.SnippetWriter)
switch ut.Kind {
case types.Builtin:
f = g.doBuiltin
case types.Map:
f = g.doMap
case types.Slice:
f = g.doSlice
case types.Struct:
f = g.doStruct
case types.Pointer:
f = g.doPointer
case types.Interface:
// interfaces are handled in-line in the other cases
klog.Fatalf("Hit an interface type %v. This should never happen.", t)
case types.Alias:
// can never happen because we branch on the underlying type which is never an alias
klog.Fatalf("Hit an alias type %v. This should never happen.", t)
default:
klog.Fatalf("Hit an unsupported type %v.", t)
}
f(t, sw)
}
// doBuiltin generates code for a builtin or an alias to a builtin. The generated code is
// is the same for both cases, i.e. it's the code for the underlying type.
func (g *genDeepCopy) doBuiltin(t *types.Type, sw *generator.SnippetWriter) {
if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
sw.Do("*out = in.DeepCopy()\n", nil)
return
}
sw.Do("*out = *in\n", nil)
}
// doMap generates code for a map or an alias to a map. The generated code is
// is the same for both cases, i.e. it's the code for the underlying type.
func (g *genDeepCopy) doMap(t *types.Type, sw *generator.SnippetWriter) {
ut := underlyingType(t)
uet := underlyingType(ut.Elem)
if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
sw.Do("*out = in.DeepCopy()\n", nil)
return
}
if !ut.Key.IsAssignable() {
klog.Fatalf("Hit an unsupported type %v for: %v", uet, t)
}
sw.Do("*out = make($.|raw$, len(*in))\n", t)
sw.Do("for key, val := range *in {\n", nil)
dc, dci := deepCopyMethodOrDie(ut.Elem), deepCopyIntoMethodOrDie(ut.Elem)
switch {
case dc != nil || dci != nil:
// Note: a DeepCopy exists because it is added if DeepCopyInto is manually defined
leftPointer := ut.Elem.Kind == types.Pointer
rightPointer := !isReference(ut.Elem)
if dc != nil {
rightPointer = dc.Results[0].Kind == types.Pointer
}
if leftPointer == rightPointer {
sw.Do("(*out)[key] = val.DeepCopy()\n", nil)
} else if leftPointer {
sw.Do("x := val.DeepCopy()\n", nil)
sw.Do("(*out)[key] = &x\n", nil)
} else {
sw.Do("(*out)[key] = *val.DeepCopy()\n", nil)
}
case ut.Elem.IsAnonymousStruct(): // not uet here because it needs type cast
sw.Do("(*out)[key] = val\n", nil)
case uet.IsAssignable():
sw.Do("(*out)[key] = val\n", nil)
case uet.Kind == types.Interface:
// Note: do not generate code that won't compile as `DeepCopyinterface{}()` is not a valid function
if uet.Name.Name == "interface{}" {
klog.Fatalf("DeepCopy of %q is unsupported. Instead, use named interfaces with DeepCopy<named-interface> as one of the methods.", uet.Name.Name)
}
sw.Do("if val == nil {(*out)[key]=nil} else {\n", nil)
// Note: if t.Elem has been an alias "J" of an interface "I" in Go, we will see it
// as kind Interface of name "J" here, i.e. generate val.DeepCopyJ(). The golang
// parser does not give us the underlying interface name. So we cannot do any better.
sw.Do(fmt.Sprintf("(*out)[key] = val.DeepCopy%s()\n", uet.Name.Name), nil)
sw.Do("}\n", nil)
case uet.Kind == types.Slice || uet.Kind == types.Map || uet.Kind == types.Pointer:
sw.Do("var outVal $.|raw$\n", uet)
sw.Do("if val == nil { (*out)[key] = nil } else {\n", nil)
sw.Do("in, out := &val, &outVal\n", uet)
g.generateFor(ut.Elem, sw)
sw.Do("}\n", nil)
sw.Do("(*out)[key] = outVal\n", nil)
case uet.Kind == types.Struct:
sw.Do("(*out)[key] = *val.DeepCopy()\n", uet)
default:
klog.Fatalf("Hit an unsupported type %v for %v", uet, t)
}
sw.Do("}\n", nil)
}
// doSlice generates code for a slice or an alias to a slice. The generated code is
// is the same for both cases, i.e. it's the code for the underlying type.
func (g *genDeepCopy) doSlice(t *types.Type, sw *generator.SnippetWriter) {
ut := underlyingType(t)
uet := underlyingType(ut.Elem)
if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
sw.Do("*out = in.DeepCopy()\n", nil)
return
}
sw.Do("*out = make($.|raw$, len(*in))\n", t)
if deepCopyMethodOrDie(ut.Elem) != nil || deepCopyIntoMethodOrDie(ut.Elem) != nil {
sw.Do("for i := range *in {\n", nil)
// Note: a DeepCopyInto exists because it is added if DeepCopy is manually defined
sw.Do("(*in)[i].DeepCopyInto(&(*out)[i])\n", nil)
sw.Do("}\n", nil)
} else if uet.Kind == types.Builtin || uet.IsAssignable() {
sw.Do("copy(*out, *in)\n", nil)
} else {
sw.Do("for i := range *in {\n", nil)
if uet.Kind == types.Slice || uet.Kind == types.Map || uet.Kind == types.Pointer || deepCopyMethodOrDie(ut.Elem) != nil || deepCopyIntoMethodOrDie(ut.Elem) != nil {
sw.Do("if (*in)[i] != nil {\n", nil)
sw.Do("in, out := &(*in)[i], &(*out)[i]\n", nil)
g.generateFor(ut.Elem, sw)
sw.Do("}\n", nil)
} else if uet.Kind == types.Interface {
// Note: do not generate code that won't compile as `DeepCopyinterface{}()` is not a valid function
if uet.Name.Name == "interface{}" {
klog.Fatalf("DeepCopy of %q is unsupported. Instead, use named interfaces with DeepCopy<named-interface> as one of the methods.", uet.Name.Name)
}
sw.Do("if (*in)[i] != nil {\n", nil)
// Note: if t.Elem has been an alias "J" of an interface "I" in Go, we will see it
// as kind Interface of name "J" here, i.e. generate val.DeepCopyJ(). The golang
// parser does not give us the underlying interface name. So we cannot do any better.
sw.Do(fmt.Sprintf("(*out)[i] = (*in)[i].DeepCopy%s()\n", uet.Name.Name), nil)
sw.Do("}\n", nil)
} else if uet.Kind == types.Struct {
sw.Do("(*in)[i].DeepCopyInto(&(*out)[i])\n", nil)
} else {
klog.Fatalf("Hit an unsupported type %v for %v", uet, t)
}
sw.Do("}\n", nil)
}
}
// doStruct generates code for a struct or an alias to a struct. The generated code is
// is the same for both cases, i.e. it's the code for the underlying type.
func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) {
ut := underlyingType(t)
if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil {
sw.Do("*out = in.DeepCopy()\n", nil)
return
}
// Simple copy covers a lot of cases.
sw.Do("*out = *in\n", nil)
// Now fix-up fields as needed.
for _, m := range ut.Members {
ft := m.Type
uft := underlyingType(ft)
args := generator.Args{
"type": ft,
"kind": ft.Kind,
"name": m.Name,
}
dc, dci := deepCopyMethodOrDie(ft), deepCopyIntoMethodOrDie(ft)
switch {
case dc != nil || dci != nil:
// Note: a DeepCopyInto exists because it is added if DeepCopy is manually defined
leftPointer := ft.Kind == types.Pointer
rightPointer := !isReference(ft)
if dc != nil {
rightPointer = dc.Results[0].Kind == types.Pointer
}
if leftPointer == rightPointer {
sw.Do("out.$.name$ = in.$.name$.DeepCopy()\n", args)
} else if leftPointer {
sw.Do("x := in.$.name$.DeepCopy()\n", args)
sw.Do("out.$.name$ = = &x\n", args)
} else {
sw.Do("in.$.name$.DeepCopyInto(&out.$.name$)\n", args)
}
case uft.Kind == types.Builtin:
// the initial *out = *in was enough
case uft.Kind == types.Map, uft.Kind == types.Slice, uft.Kind == types.Pointer:
// Fixup non-nil reference-semantic types.
sw.Do("if in.$.name$ != nil {\n", args)
sw.Do("in, out := &in.$.name$, &out.$.name$\n", args)
g.generateFor(ft, sw)
sw.Do("}\n", nil)
case uft.Kind == types.Array:
sw.Do("out.$.name$ = in.$.name$\n", args)
case uft.Kind == types.Struct:
if ft.IsAssignable() {
sw.Do("out.$.name$ = in.$.name$\n", args)
} else {
sw.Do("in.$.name$.DeepCopyInto(&out.$.name$)\n", args)
}
case uft.Kind == types.Interface:
// Note: do not generate code that won't compile as `DeepCopyinterface{}()` is not a valid function
if uft.Name.Name == "interface{}" {
klog.Fatalf("DeepCopy of %q is unsupported. Instead, use named interfaces with DeepCopy<named-interface> as one of the methods.", uft.Name.Name)
}
sw.Do("if in.$.name$ != nil {\n", args)
// Note: if t.Elem has been an alias "J" of an interface "I" in Go, we will see it
// as kind Interface of name "J" here, i.e. generate val.DeepCopyJ(). The golang
// parser does not give us the underlying interface name. So we cannot do any better.
sw.Do(fmt.Sprintf("out.$.name$ = in.$.name$.DeepCopy%s()\n", uft.Name.Name), args)
sw.Do("}\n", nil)
default:
klog.Fatalf("Hit an unsupported type '%v' for '%v', from %v.%v", uft, ft, t, m.Name)
}
}
}
// doPointer generates code for a pointer or an alias to a pointer. The generated code is
// is the same for both cases, i.e. it's the code for the underlying type.
func (g *genDeepCopy) doPointer(t *types.Type, sw *generator.SnippetWriter) {
ut := underlyingType(t)
uet := underlyingType(ut.Elem)
dc, dci := deepCopyMethodOrDie(ut.Elem), deepCopyIntoMethodOrDie(ut.Elem)
switch {
case dc != nil || dci != nil:
rightPointer := !isReference(ut.Elem)
if dc != nil {
rightPointer = dc.Results[0].Kind == types.Pointer
}
if rightPointer {
sw.Do("*out = (*in).DeepCopy()\n", nil)
} else {
sw.Do("x := (*in).DeepCopy()\n", nil)
sw.Do("*out = &x\n", nil)
}
case uet.IsAssignable():
sw.Do("*out = new($.Elem|raw$)\n", ut)
sw.Do("**out = **in", nil)
case uet.Kind == types.Map, uet.Kind == types.Slice, uet.Kind == types.Pointer:
sw.Do("*out = new($.Elem|raw$)\n", ut)
sw.Do("if **in != nil {\n", nil)
sw.Do("in, out := *in, *out\n", nil)
g.generateFor(uet, sw)
sw.Do("}\n", nil)
case uet.Kind == types.Struct:
sw.Do("*out = new($.Elem|raw$)\n", ut)
sw.Do("(*in).DeepCopyInto(*out)\n", nil)
default:
klog.Fatalf("Hit an unsupported type %v for %v", uet, t)
}
}

View File

@@ -16,14 +16,24 @@ limitations under the License.
// deepcopy-gen is a tool for auto-generating DeepCopy functions.
//
// Given a list of input directories, it will generate functions that
// efficiently perform a full deep-copy of each type. For any type that
// offers a `.DeepCopy()` method, it will simply call that. Otherwise it will
// use standard value assignment whenever possible. If that is not possible it
// will try to call its own generated copy function for the type, if the type is
// within the allowed root packages. Failing that, it will fall back on
// `conversion.Cloner.DeepCopy(val)` to make the copy. The resulting file will
// be stored in the same directory as the processed source package.
// Given a list of input directories, it will generate DeepCopy and
// DeepCopyInto methods that efficiently perform a full deep-copy of each type.
// If these methods already exist (are predefined by the developer), they are
// used instead of generating new ones. Generated code will use standard value
// assignment whenever possible. If that is not possible it will try to call
// its own generated copy function for the type. Failing that, it will fall
// back on `conversion.Cloner.DeepCopy(val)` to make the copy. The resulting
// file will be stored in the same directory as the processed source package.
//
// If interfaces are referenced in types, it is expected that corresponding
// DeepCopyInterfaceName methods exist, e.g. DeepCopyObject for runtime.Object.
// These can be predefined by the developer or generated through tags, see
// below. They must be added to the interfaces themselves manually, e.g.
//
// type Object interface {
// ...
// DeepCopyObject() Object
// }
//
// Generation is governed by comment tags in the source. Any package may
// request DeepCopy generation by including a comment in the file-comments of
@@ -32,48 +42,67 @@ limitations under the License.
// // +k8s:deepcopy-gen=package
//
// DeepCopy functions can be generated for individual types, rather than the
// entire package by specifying a comment on the type definion of the form:
// entire package by specifying a comment on the type definition of the form:
//
// // +k8s:deepcopy-gen=true
//
// When generating for a whole package, individual types may opt out of
// DeepCopy generation by specifying a comment on the of the form:
// DeepCopy generation by specifying a comment on the type definition of the
// form:
//
// // +k8s:deepcopy-gen=false
//
// Note that registration is a whole-package option, and is not available for
// individual types.
// Additional DeepCopyInterfaceName methods can be generated by specifying a
// comment on the type definition of the form:
//
// // +k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object,k8s.io/kubernetes/runtime.List
//
// This leads to the generation of DeepCopyObject and DeepCopyList with the given
// interfaces as return types. We say that the tagged type implements deepcopy for the
// interfaces.
//
// The deepcopy funcs for interfaces using "+k8s:deepcopy-gen:interfaces" use the pointer
// of the type as receiver. For those special cases where the non-pointer object should
// implement the interface, this can be done with:
//
// // +k8s:deepcopy-gen:nonpointer-interfaces=true
package main
import (
"flag"
"github.com/spf13/pflag"
"k8s.io/gengo/examples/deepcopy-gen/generators"
"k8s.io/code-generator/cmd/deepcopy-gen/args"
"k8s.io/code-generator/cmd/deepcopy-gen/generators"
"k8s.io/gengo/v2"
"k8s.io/gengo/v2/generator"
"k8s.io/klog/v2"
generatorargs "k8s.io/code-generator/cmd/deepcopy-gen/args"
)
func main() {
klog.InitFlags(nil)
genericArgs, customArgs := generatorargs.NewDefaults()
args := args.New()
genericArgs.AddFlags(pflag.CommandLine)
customArgs.AddFlags(pflag.CommandLine)
args.AddFlags(pflag.CommandLine)
flag.Set("logtostderr", "true")
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
pflag.Parse()
if err := generatorargs.Validate(genericArgs); err != nil {
if err := args.Validate(); err != nil {
klog.Fatalf("Error: %v", err)
}
myTargets := func(context *generator.Context) []generator.Target {
return generators.GetTargets(context, args)
}
// Run it.
if err := genericArgs.Execute(
if err := gengo.Execute(
generators.NameSystems(),
generators.DefaultNameSystem(),
generators.Packages,
myTargets,
gengo.StdBuildTag,
pflag.Args(),
); err != nil {
klog.Fatalf("Error: %v", err)
}

View File

@@ -20,34 +20,33 @@ import (
"fmt"
"github.com/spf13/pflag"
"k8s.io/gengo/args"
"k8s.io/gengo/examples/defaulter-gen/generators"
)
// CustomArgs is used by the gengo framework to pass args specific to this generator.
type CustomArgs generators.CustomArgs
type Args struct {
OutputFile string
ExtraPeerDirs []string // Always consider these as last-ditch possibilities for conversions.
GoHeaderFile string
}
// NewDefaults returns default arguments for the generator.
func NewDefaults() (*args.GeneratorArgs, *CustomArgs) {
genericArgs := args.Default().WithoutDefaultFlagParsing()
customArgs := &CustomArgs{}
genericArgs.CustomArgs = (*generators.CustomArgs)(customArgs) // convert to upstream type to make type-casts work there
genericArgs.OutputFileBaseName = "zz_generated.defaults"
return genericArgs, customArgs
// New returns default arguments for the generator.
func New() *Args {
return &Args{}
}
// AddFlags add the generator flags to the flag set.
func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet) {
fs.StringSliceVar(&ca.ExtraPeerDirs, "extra-peer-dirs", ca.ExtraPeerDirs,
func (args *Args) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&args.OutputFile, "output-file", "generated.defaults.go",
"the name of the file to be generated")
fs.StringSliceVar(&args.ExtraPeerDirs, "extra-peer-dirs", args.ExtraPeerDirs,
"Comma-separated list of import paths which are considered, after tag-specified peers, for conversions.")
fs.StringVar(&args.GoHeaderFile, "go-header-file", "",
"the path to a file containing boilerplate header text; the string \"YEAR\" will be replaced with the current 4-digit year")
}
// Validate checks the given arguments.
func Validate(genericArgs *args.GeneratorArgs) error {
_ = genericArgs.CustomArgs.(*generators.CustomArgs)
if len(genericArgs.OutputFileBaseName) == 0 {
return fmt.Errorf("output file base name cannot be empty")
func (args *Args) Validate() error {
if len(args.OutputFile) == 0 {
return fmt.Errorf("--output-file must be specified")
}
return nil

File diff suppressed because it is too large Load Diff

View File

@@ -45,31 +45,37 @@ import (
"flag"
"github.com/spf13/pflag"
"k8s.io/gengo/examples/defaulter-gen/generators"
"k8s.io/code-generator/cmd/defaulter-gen/args"
"k8s.io/code-generator/cmd/defaulter-gen/generators"
"k8s.io/gengo/v2"
"k8s.io/gengo/v2/generator"
"k8s.io/klog/v2"
generatorargs "k8s.io/code-generator/cmd/defaulter-gen/args"
)
func main() {
klog.InitFlags(nil)
genericArgs, customArgs := generatorargs.NewDefaults()
args := args.New()
genericArgs.AddFlags(pflag.CommandLine)
customArgs.AddFlags(pflag.CommandLine)
args.AddFlags(pflag.CommandLine)
flag.Set("logtostderr", "true")
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
pflag.Parse()
if err := generatorargs.Validate(genericArgs); err != nil {
if err := args.Validate(); err != nil {
klog.Fatalf("Error: %v", err)
}
myTargets := func(context *generator.Context) []generator.Target {
return generators.GetTargets(context, args)
}
// Run it.
if err := genericArgs.Execute(
if err := gengo.Execute(
generators.NameSystems(),
generators.DefaultNameSystem(),
generators.Packages,
myTargets,
gengo.StdBuildTag,
pflag.Args(),
); err != nil {
klog.Fatalf("Error: %v", err)
}

View File

@@ -22,7 +22,6 @@ import (
"bytes"
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"sort"
@@ -30,19 +29,18 @@ import (
flag "github.com/spf13/pflag"
"k8s.io/gengo/args"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/parser"
"k8s.io/gengo/types"
"k8s.io/gengo/v2"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/parser"
"k8s.io/gengo/v2/types"
)
type Generator struct {
Common args.GeneratorArgs
GoHeaderFile string
APIMachineryPackages string
Packages string
OutputBase string
VendorOutputBase string
OutputDir string
ProtoImport []string
Conditional string
Clean bool
@@ -50,24 +48,12 @@ type Generator struct {
KeepGogoproto bool
SkipGeneratedRewrite bool
DropEmbeddedFields string
TrimPathPrefix string
}
func New() *Generator {
sourceTree := args.DefaultSourceTree()
common := args.GeneratorArgs{
OutputBase: sourceTree,
}
defaultProtoImport := filepath.Join(sourceTree, "k8s.io", "kubernetes", "vendor", "github.com", "gogo", "protobuf", "protobuf")
cwd, err := os.Getwd()
if err != nil {
log.Fatalf("Cannot get current directory.")
}
defaultSourceTree := "."
return &Generator{
Common: common,
OutputBase: sourceTree,
VendorOutputBase: filepath.Join(cwd, "vendor"),
ProtoImport: []string{defaultProtoImport},
OutputDir: defaultSourceTree,
APIMachineryPackages: strings.Join([]string{
`+k8s.io/apimachinery/pkg/util/intstr`,
`+k8s.io/apimachinery/pkg/api/resource`,
@@ -83,30 +69,94 @@ func New() *Generator {
}
func (g *Generator) BindFlags(flag *flag.FlagSet) {
flag.StringVarP(&g.Common.GoHeaderFilePath, "go-header-file", "h", g.Common.GoHeaderFilePath, "File containing boilerplate header text. The string YEAR will be replaced with the current 4-digit year.")
flag.BoolVar(&g.Common.VerifyOnly, "verify-only", g.Common.VerifyOnly, "If true, only verify existing output, do not write anything.")
flag.StringVarP(&g.GoHeaderFile, "go-header-file", "h", "", "File containing boilerplate header text. The string YEAR will be replaced with the current 4-digit year.")
flag.StringVarP(&g.Packages, "packages", "p", g.Packages, "comma-separated list of directories to get input types from. Directories prefixed with '-' are not generated, directories prefixed with '+' only create types with explicit IDL instructions.")
flag.StringVar(&g.APIMachineryPackages, "apimachinery-packages", g.APIMachineryPackages, "comma-separated list of directories to get apimachinery input types from which are needed by any API. Directories prefixed with '-' are not generated, directories prefixed with '+' only create types with explicit IDL instructions.")
flag.StringVarP(&g.OutputBase, "output-base", "o", g.OutputBase, "Output base; defaults to $GOPATH/src/")
flag.StringVar(&g.VendorOutputBase, "vendor-output-base", g.VendorOutputBase, "The vendor/ directory to look for packages in; defaults to $PWD/vendor/.")
flag.StringSliceVar(&g.ProtoImport, "proto-import", g.ProtoImport, "The search path for the core protobuf .protos, required; defaults $GOPATH/src/k8s.io/kubernetes/vendor/github.com/gogo/protobuf/protobuf.")
flag.StringVar(&g.OutputDir, "output-dir", g.OutputDir, "The base directory under which to generate results.")
flag.StringSliceVar(&g.ProtoImport, "proto-import", g.ProtoImport, "A search path for imported protobufs (may be repeated).")
flag.StringVar(&g.Conditional, "conditional", g.Conditional, "An optional Golang build tag condition to add to the generated Go code")
flag.BoolVar(&g.Clean, "clean", g.Clean, "If true, remove all generated files for the specified Packages.")
flag.BoolVar(&g.OnlyIDL, "only-idl", g.OnlyIDL, "If true, only generate the IDL for each package.")
flag.BoolVar(&g.KeepGogoproto, "keep-gogoproto", g.KeepGogoproto, "If true, the generated IDL will contain gogoprotobuf extensions which are normally removed")
flag.BoolVar(&g.SkipGeneratedRewrite, "skip-generated-rewrite", g.SkipGeneratedRewrite, "If true, skip fixing up the generated.pb.go file (debugging only).")
flag.StringVar(&g.DropEmbeddedFields, "drop-embedded-fields", g.DropEmbeddedFields, "Comma-delimited list of embedded Go types to omit from generated protobufs")
flag.StringVar(&g.TrimPathPrefix, "trim-path-prefix", g.TrimPathPrefix, "If set, trim the specified prefix from --output-package when generating files.")
}
// This roughly models gengo/v2.Execute.
func Run(g *Generator) {
if g.Common.VerifyOnly {
g.OnlyIDL = true
g.Clean = false
// Roughly models gengo/v2.newBuilder.
p := parser.NewWithOptions(parser.Options{BuildTags: []string{"proto"}})
var allInputs []string
if len(g.APIMachineryPackages) != 0 {
allInputs = append(allInputs, strings.Split(g.APIMachineryPackages, ",")...)
}
if len(g.Packages) != 0 {
allInputs = append(allInputs, strings.Split(g.Packages, ",")...)
}
if len(allInputs) == 0 {
log.Fatalf("Both apimachinery-packages and packages are empty. At least one package must be specified.")
}
b := parser.New()
b.AddBuildTags("proto")
// Build up a list of packages to load from all the inputs. Track the
// special modifiers for each. NOTE: This does not support pkg/... syntax.
type modifier struct {
allTypes bool
output bool
name string
}
inputModifiers := map[string]modifier{}
packages := make([]string, 0, len(allInputs))
for _, d := range allInputs {
modifier := modifier{allTypes: true, output: true}
switch {
case strings.HasPrefix(d, "+"):
d = d[1:]
modifier.allTypes = false
case strings.HasPrefix(d, "-"):
d = d[1:]
modifier.output = false
}
name := protoSafePackage(d)
parts := strings.SplitN(d, "=", 2)
if len(parts) > 1 {
d = parts[0]
name = parts[1]
}
modifier.name = name
packages = append(packages, d)
inputModifiers[d] = modifier
}
// Load all the packages at once.
if err := p.LoadPackages(packages...); err != nil {
log.Fatalf("Unable to load packages: %v", err)
}
c, err := generator.NewContext(
p,
namer.NameSystems{
"public": namer.NewPublicNamer(3),
},
"public",
)
if err != nil {
log.Fatalf("Failed making a context: %v", err)
}
c.FileTypes["protoidl"] = NewProtoFile()
// Roughly models gengo/v2.Execute calling the
// tool-provided Targets() callback.
boilerplate, err := gengo.GoBoilerplate(g.GoHeaderFile, "", "")
if err != nil {
log.Fatalf("Failed loading boilerplate (consider using the go-header-file flag): %v", err)
}
omitTypes := map[types.Name]struct{}{}
for _, t := range strings.Split(g.DropEmbeddedFields, ",") {
@@ -122,59 +172,32 @@ func Run(g *Generator) {
omitTypes[name] = struct{}{}
}
boilerplate, err := g.Common.LoadGoBoilerplate()
if err != nil {
log.Fatalf("Failed loading boilerplate (consider using the go-header-file flag): %v", err)
}
protobufNames := NewProtobufNamer()
outputPackages := generator.Packages{}
outputPackages := []generator.Target{}
nonOutputPackages := map[string]struct{}{}
var packages []string
if len(g.APIMachineryPackages) != 0 {
packages = append(packages, strings.Split(g.APIMachineryPackages, ",")...)
}
if len(g.Packages) != 0 {
packages = append(packages, strings.Split(g.Packages, ",")...)
}
if len(packages) == 0 {
log.Fatalf("Both apimachinery-packages and packages are empty. At least one package must be specified.")
}
for _, d := range packages {
generateAllTypes, outputPackage := true, true
switch {
case strings.HasPrefix(d, "+"):
d = d[1:]
generateAllTypes = false
case strings.HasPrefix(d, "-"):
d = d[1:]
outputPackage = false
for _, input := range c.Inputs {
mod, found := inputModifiers[input]
if !found {
log.Fatalf("BUG: can't find input modifiers for %q", input)
}
name := protoSafePackage(d)
parts := strings.SplitN(d, "=", 2)
if len(parts) > 1 {
d = parts[0]
name = parts[1]
}
p := newProtobufPackage(d, name, generateAllTypes, omitTypes)
pkg := c.Universe[input]
protopkg := newProtobufPackage(pkg.Path, pkg.Dir, mod.name, mod.allTypes, omitTypes)
header := append([]byte{}, boilerplate...)
header = append(header, p.HeaderText...)
p.HeaderText = header
protobufNames.Add(p)
if outputPackage {
outputPackages = append(outputPackages, p)
header = append(header, protopkg.HeaderComment...)
protopkg.HeaderComment = header
protobufNames.Add(protopkg)
if mod.output {
outputPackages = append(outputPackages, protopkg)
} else {
nonOutputPackages[name] = struct{}{}
nonOutputPackages[mod.name] = struct{}{}
}
}
c.Namers["proto"] = protobufNames
if !g.Common.VerifyOnly {
for _, p := range outputPackages {
if err := p.(*protobufPackage).Clean(g.OutputBase); err != nil {
log.Fatalf("Unable to clean package %s: %v", p.Name(), err)
}
for _, p := range outputPackages {
if err := p.(*protobufPackage).Clean(); err != nil {
log.Fatalf("Unable to clean package %s: %v", p.Name(), err)
}
}
@@ -182,28 +205,6 @@ func Run(g *Generator) {
return
}
for _, p := range protobufNames.List() {
if err := b.AddDir(p.Path()); err != nil {
log.Fatalf("Unable to add directory %q: %v", p.Path(), err)
}
}
c, err := generator.NewContext(
b,
namer.NameSystems{
"public": namer.NewPublicNamer(3),
"proto": protobufNames,
},
"public",
)
if err != nil {
log.Fatalf("Failed making a context: %v", err)
}
c.Verify = g.Common.VerifyOnly
c.FileTypes["protoidl"] = NewProtoFile()
c.TrimPathPrefix = g.TrimPathPrefix
// order package by imports, importees first
deps := deps(c, protobufNames.packages)
order, err := importOrder(deps)
@@ -216,28 +217,20 @@ func Run(g *Generator) {
}
sort.Sort(positionOrder{topologicalPos, protobufNames.packages})
var vendoredOutputPackages, localOutputPackages generator.Packages
var localOutputPackages []generator.Target
for _, p := range protobufNames.packages {
if _, ok := nonOutputPackages[p.Name()]; ok {
// if we're not outputting the package, don't include it in either package list
continue
}
p.Vendored = strings.Contains(c.Universe[p.PackagePath].SourcePath, "/vendor/")
if p.Vendored {
vendoredOutputPackages = append(vendoredOutputPackages, p)
} else {
localOutputPackages = append(localOutputPackages, p)
}
localOutputPackages = append(localOutputPackages, p)
}
if err := protobufNames.AssignTypesToPackages(c); err != nil {
log.Fatalf("Failed to identify Common types: %v", err)
}
if err := c.ExecutePackages(g.VendorOutputBase, vendoredOutputPackages); err != nil {
log.Fatalf("Failed executing vendor generator: %v", err)
}
if err := c.ExecutePackages(g.OutputBase, localOutputPackages); err != nil {
if err := c.ExecuteTargets(localOutputPackages); err != nil {
log.Fatalf("Failed executing local generator: %v", err)
}
@@ -249,13 +242,24 @@ func Run(g *Generator) {
log.Fatalf("Unable to find 'protoc': %v", err)
}
searchArgs := []string{"-I", ".", "-I", g.OutputBase}
searchArgs := []string{"-I", ".", "-I", g.OutputDir}
if len(g.ProtoImport) != 0 {
for _, s := range g.ProtoImport {
searchArgs = append(searchArgs, "-I", s)
}
}
args := append(searchArgs, fmt.Sprintf("--gogo_out=%s", g.OutputBase))
// Despite docs saying that `--gogo_out=paths=source_relative:.` will
// output the .pb.go file to the same directory as the .proto file, it
// doesn't. Given example.com/foo/bar.proto (found in one of the -I paths
// above), the output becomes
// $output_base/example.com/foo/example.com/foo/bar.pb.go - basically
// useless. Users should set the output-dir to a single dir under which
// all the packages in question live (e.g. staging/src in kubernetes).
// Alternately, we could generate into a temp path and then move the
// resulting file back to the input dir, but that seems brittle in other
// ways.
args := searchArgs
args = append(args, fmt.Sprintf("--gogo_out=%s", g.OutputDir))
buf := &bytes.Buffer{}
if len(g.Conditional) > 0 {
@@ -266,28 +270,8 @@ func Run(g *Generator) {
for _, outputPackage := range outputPackages {
p := outputPackage.(*protobufPackage)
path := filepath.Join(g.OutputBase, p.ImportPath())
outputPath := filepath.Join(g.OutputBase, p.OutputPath())
if p.Vendored {
path = filepath.Join(g.VendorOutputBase, p.ImportPath())
outputPath = filepath.Join(g.VendorOutputBase, p.OutputPath())
}
// When working outside of GOPATH, we typically won't want to generate the
// full path for a package. For example, if our current project's root/base
// package is github.com/foo/bar, outDir=., p.Path()=github.com/foo/bar/generated,
// then we really want to be writing files to ./generated, not ./github.com/foo/bar/generated.
// The following will trim a path prefix (github.com/foo/bar) from p.Path() to arrive at
// a relative path that works with projects not in GOPATH.
if g.TrimPathPrefix != "" {
separator := string(filepath.Separator)
if !strings.HasSuffix(g.TrimPathPrefix, separator) {
g.TrimPathPrefix += separator
}
path = strings.TrimPrefix(path, g.TrimPathPrefix)
outputPath = strings.TrimPrefix(outputPath, g.TrimPathPrefix)
}
path := filepath.Join(g.OutputDir, p.ImportPath())
outputPath := filepath.Join(g.OutputDir, p.OutputPath())
// generate the gogoprotobuf protoc
cmd := exec.Command("protoc", append(args, path)...)
@@ -295,7 +279,7 @@ func Run(g *Generator) {
if err != nil {
log.Println(strings.Join(cmd.Args, " "))
log.Println(string(out))
log.Fatalf("Unable to generate protoc on %s: %v", p.PackageName, err)
log.Fatalf("Unable to run protoc on %s: %v", p.Name(), err)
}
if g.SkipGeneratedRewrite {
@@ -316,7 +300,7 @@ func Run(g *Generator) {
}
if err != nil {
log.Println(strings.Join(cmd.Args, " "))
log.Fatalf("Unable to rewrite imports for %s: %v", p.PackageName, err)
log.Fatalf("Unable to rewrite imports for %s: %v", p.Name(), err)
}
// format and simplify the generated file
@@ -327,7 +311,7 @@ func Run(g *Generator) {
}
if err != nil {
log.Println(strings.Join(cmd.Args, " "))
log.Fatalf("Unable to apply gofmt for %s: %v", p.PackageName, err)
log.Fatalf("Unable to apply gofmt for %s: %v", p.Name(), err)
}
}
@@ -341,10 +325,7 @@ func Run(g *Generator) {
p := outputPackage.(*protobufPackage)
p.OmitGogo = true
}
if err := c.ExecutePackages(g.VendorOutputBase, vendoredOutputPackages); err != nil {
log.Fatalf("Failed executing vendor generator: %v", err)
}
if err := c.ExecutePackages(g.OutputBase, localOutputPackages); err != nil {
if err := c.ExecuteTargets(localOutputPackages); err != nil {
log.Fatalf("Failed executing local generator: %v", err)
}
}
@@ -356,10 +337,7 @@ func Run(g *Generator) {
continue
}
pattern := filepath.Join(g.OutputBase, p.PackagePath, "*.go")
if p.Vendored {
pattern = filepath.Join(g.VendorOutputBase, p.PackagePath, "*.go")
}
pattern := filepath.Join(g.OutputDir, p.Path(), "*.go")
files, err := filepath.Glob(pattern)
if err != nil {
log.Fatalf("Can't glob pattern %q: %v", pattern, err)
@@ -379,13 +357,13 @@ func Run(g *Generator) {
func deps(c *generator.Context, pkgs []*protobufPackage) map[string][]string {
ret := map[string][]string{}
for _, p := range pkgs {
pkg, ok := c.Universe[p.PackagePath]
pkg, ok := c.Universe[p.Path()]
if !ok {
log.Fatalf("Unrecognized package: %s", p.PackagePath)
log.Fatalf("Unrecognized package: %s", p.Path())
}
for _, d := range pkg.Imports {
ret[p.PackagePath] = append(ret[p.PackagePath], d.Path)
ret[p.Path()] = append(ret[p.Path()], d.Path)
}
}
return ret
@@ -414,9 +392,9 @@ func importOrder(deps map[string][]string) ([]string, error) {
if len(remainingNodes) > 0 {
return nil, fmt.Errorf("cycle: remaining nodes: %#v, remaining edges: %#v", remainingNodes, graph)
}
//for _, n := range sorted {
// fmt.Println("topological order", n)
//}
// for _, n := range sorted {
// fmt.Println("topological order", n)
// }
return sorted, nil
}
@@ -470,11 +448,9 @@ func (o positionOrder) Len() int {
}
func (o positionOrder) Less(i, j int) bool {
return o.pos[o.elements[i].PackagePath] < o.pos[o.elements[j].PackagePath]
return o.pos[o.elements[i].Path()] < o.pos[o.elements[j].Path()]
}
func (o positionOrder) Swap(i, j int) {
x := o.elements[i]
o.elements[i] = o.elements[j]
o.elements[j] = x
o.elements[i], o.elements[j] = o.elements[j], o.elements[i]
}

View File

@@ -25,16 +25,18 @@ import (
"strconv"
"strings"
"k8s.io/gengo/v2"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
"k8s.io/klog/v2"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
)
// genProtoIDL produces a .proto IDL.
type genProtoIDL struct {
generator.DefaultGen
// This base type is close enough to what we need, if we redefine some
// methods.
generator.GoGenerator
localPackage types.Name
localGoPackage types.Name
imports namer.ImportTracker
@@ -63,8 +65,11 @@ func (g *genProtoIDL) PackageVars(c *generator.Context) []string {
fmt.Sprintf("option go_package = %q;", g.localGoPackage.Package),
}
}
func (g *genProtoIDL) Filename() string { return g.OptionalName + ".proto" }
func (g *genProtoIDL) Filename() string { return g.OutputFilename + ".proto" }
func (g *genProtoIDL) FileType() string { return "protoidl" }
func (g *genProtoIDL) Namers(c *generator.Context) namer.NameSystems {
return namer.NameSystems{
// The local namer returns the correct protobuf name for a proto type
@@ -75,7 +80,7 @@ func (g *genProtoIDL) Namers(c *generator.Context) namer.NameSystems {
// Filter ignores types that are identified as not exportable.
func (g *genProtoIDL) Filter(c *generator.Context, t *types.Type) bool {
tagVals := types.ExtractCommentTags("+", t.CommentLines)["protobuf"]
tagVals := gengo.ExtractCommentTags("+", t.CommentLines)["protobuf"]
if tagVals != nil {
if tagVals[0] == "false" {
// Type specified "false".
@@ -224,9 +229,8 @@ func (p protobufLocator) GoTypeForName(name types.Name) *types.Type {
// ProtoTypeFor locates a Protobuf type for the provided Go type (if possible).
func (p protobufLocator) ProtoTypeFor(t *types.Type) (*types.Type, error) {
switch {
// we've already converted the type, or it's a map
case t.Kind == types.Protobuf || t.Kind == types.Map:
if t.Kind == types.Protobuf || t.Kind == types.Map {
p.tracker.AddType(t)
return t, nil
}
@@ -304,7 +308,7 @@ func (b bodyGen) doStruct(sw *generator.SnippetWriter) error {
var alias *types.Type
var fields []protoField
options := []string{}
allOptions := types.ExtractCommentTags("+", b.t.CommentLines)
allOptions := gengo.ExtractCommentTags("+", b.t.CommentLines)
for k, v := range allOptions {
switch {
case strings.HasPrefix(k, "protobuf.options."):
@@ -554,11 +558,11 @@ func protobufTagToField(tag string, field *protoField, m types.Member, t *types.
// protobuf:"bytes,3,opt,name=Id,customtype=github.com/gogo/protobuf/test.Uuid"
parts := strings.Split(tag, ",")
if len(parts) < 3 {
return fmt.Errorf("member %q of %q malformed 'protobuf' tag, not enough segments\n", m.Name, t.Name)
return fmt.Errorf("member %q of %q malformed 'protobuf' tag, not enough segments", m.Name, t.Name)
}
protoTag, err := strconv.Atoi(parts[1])
if err != nil {
return fmt.Errorf("member %q of %q malformed 'protobuf' tag, field ID is %q which is not an integer: %v\n", m.Name, t.Name, parts[1], err)
return fmt.Errorf("member %q of %q malformed 'protobuf' tag, field ID is %q which is not an integer: %w", m.Name, t.Name, parts[1], err)
}
field.Tag = protoTag
@@ -579,7 +583,7 @@ func protobufTagToField(tag string, field *protoField, m types.Member, t *types.
name = types.Name{
Name: parts[0][last+1:],
Package: prefix,
Path: strings.Replace(prefix, ".", "/", -1),
Path: strings.ReplaceAll(prefix, ".", "/"),
}
} else {
name = types.Name{
@@ -598,7 +602,7 @@ func protobufTagToField(tag string, field *protoField, m types.Member, t *types.
for i, extra := range parts[3:] {
parts := strings.SplitN(extra, "=", 2)
if len(parts) != 2 {
return fmt.Errorf("member %q of %q malformed 'protobuf' tag, tag %d should be key=value, got %q\n", m.Name, t.Name, i+4, extra)
return fmt.Errorf("member %q of %q malformed 'protobuf' tag, tag %d should be key=value, got %q", m.Name, t.Name, i+4, extra)
}
switch parts[0] {
case "name":

View File

@@ -17,8 +17,8 @@ limitations under the License.
package protobuf
import (
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
)
type ImportTracker struct {

View File

@@ -21,9 +21,9 @@ import (
"reflect"
"strings"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
)
type localNamer struct {
@@ -41,7 +41,8 @@ func (n localNamer) Name(t *types.Type) string {
}
type protobufNamer struct {
packages []*protobufPackage
packages []*protobufPackage
// The key here is a Go import-path.
packagesByPath map[string]*protobufPackage
}
@@ -58,17 +59,9 @@ func (n *protobufNamer) Name(t *types.Type) string {
return t.Name.String()
}
func (n *protobufNamer) List() []generator.Package {
packages := make([]generator.Package, 0, len(n.packages))
for i := range n.packages {
packages = append(packages, n.packages[i])
}
return packages
}
func (n *protobufNamer) Add(p *protobufPackage) {
if _, ok := n.packagesByPath[p.PackagePath]; !ok {
n.packagesByPath[p.PackagePath] = p
if _, ok := n.packagesByPath[p.Path()]; !ok {
n.packagesByPath[p.Path()] = p
n.packages = append(n.packages, p)
}
}
@@ -77,7 +70,7 @@ func (n *protobufNamer) GoNameToProtoName(name types.Name) types.Name {
if p, ok := n.packagesByPath[name.Package]; ok {
return types.Name{
Name: name.Name,
Package: p.PackageName,
Package: p.Name(),
Path: p.ImportPath(),
}
}
@@ -85,7 +78,7 @@ func (n *protobufNamer) GoNameToProtoName(name types.Name) types.Name {
if _, ok := p.FilterTypes[name]; ok {
return types.Name{
Name: name.Name,
Package: p.PackageName,
Package: p.Name(),
Path: p.ImportPath(),
}
}
@@ -94,8 +87,8 @@ func (n *protobufNamer) GoNameToProtoName(name types.Name) types.Name {
}
func protoSafePackage(name string) string {
pkg := strings.Replace(name, "/", ".", -1)
return strings.Replace(pkg, "-", "_", -1)
pkg := strings.ReplaceAll(name, "/", ".")
return strings.ReplaceAll(pkg, "-", "_")
}
type typeNameSet map[types.Name]*protobufPackage
@@ -116,7 +109,7 @@ func assignGoTypeToProtoPackage(p *protobufPackage, t *types.Type, local, global
}
return
}
if t.Name.Package == p.PackagePath {
if t.Name.Package == p.Path() {
// Associate types only to their own package
global[t.Name] = p
}
@@ -182,7 +175,7 @@ func (n *protobufNamer) AssignTypesToPackages(c *generator.Context) error {
optional := make(map[types.Name]struct{})
p.Imports = NewImportTracker(p.ProtoTypeName())
for _, t := range c.Order {
if t.Name.Package != p.PackagePath {
if t.Name.Package != p.Path() {
continue
}
if !isTypeApplicableToProtobuf(t) {

View File

@@ -25,41 +25,31 @@ import (
"reflect"
"strings"
"k8s.io/gengo/generator"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/types"
)
func newProtobufPackage(packagePath, packageName string, generateAll bool, omitFieldTypes map[types.Name]struct{}) *protobufPackage {
func newProtobufPackage(packagePath, packageDir, packageName string, generateAll bool, omitFieldTypes map[types.Name]struct{}) *protobufPackage {
pkg := &protobufPackage{
DefaultPackage: generator.DefaultPackage{
SimpleTarget: generator.SimpleTarget{
// The protobuf package name (foo.bar.baz)
PackageName: packageName,
// A path segment relative to the GOPATH root (foo/bar/baz)
PackagePath: packagePath,
HeaderText: []byte(
`
// This file was autogenerated by go-to-protobuf. Do not edit it manually!
`),
PackageDocumentation: []byte(fmt.Sprintf(
`// Package %s is an autogenerated protobuf IDL.
`, packageName)),
PkgName: packageName,
PkgPath: packagePath,
PkgDir: packageDir,
HeaderComment: []byte("// This file was autogenerated by go-to-protobuf. Do not edit it manually!\n\n"),
PkgDocComment: []byte(fmt.Sprintf("// Package %s is an autogenerated protobuf IDL.\n", packageName)),
},
GenerateAll: generateAll,
OmitFieldTypes: omitFieldTypes,
}
pkg.FilterFunc = pkg.filterFunc
pkg.GeneratorFunc = pkg.generatorFunc
pkg.GeneratorsFunc = pkg.generatorsFunc
return pkg
}
// protobufPackage contains the protobuf implementation of Package.
type protobufPackage struct {
generator.DefaultPackage
// If true, this package has been vendored into our source tree and thus can
// only be generated by changing the vendor tree.
Vendored bool
generator.SimpleTarget
// If true, generate protobuf serializations for all public types.
// If false, only generate protobuf serializations for structs that
@@ -89,9 +79,9 @@ type protobufPackage struct {
Imports *ImportTracker
}
func (p *protobufPackage) Clean(outputBase string) error {
func (p *protobufPackage) Clean() error {
for _, s := range []string{p.ImportPath(), p.OutputPath()} {
if err := os.Remove(filepath.Join(outputBase, s)); err != nil && !os.IsNotExist(err) {
if err := os.Remove(filepath.Join(p.Dir(), filepath.Base(s))); err != nil && !os.IsNotExist(err) {
return err
}
}
@@ -179,17 +169,17 @@ func (p *protobufPackage) ExtractGeneratedType(t *ast.TypeSpec) bool {
return true
}
func (p *protobufPackage) generatorFunc(c *generator.Context) []generator.Generator {
func (p *protobufPackage) generatorsFunc(c *generator.Context) []generator.Generator {
generators := []generator.Generator{}
p.Imports.AddNullable()
generators = append(generators, &genProtoIDL{
DefaultGen: generator.DefaultGen{
OptionalName: "generated",
GoGenerator: generator.GoGenerator{
OutputFilename: "generated", // the extension is added later
},
localPackage: types.Name{Package: p.PackageName, Path: p.PackagePath},
localGoPackage: types.Name{Package: p.PackagePath, Name: p.GoPackageName()},
localPackage: types.Name{Package: p.Name(), Path: p.Path()},
localGoPackage: types.Name{Package: p.Path(), Name: p.GoPackageName()},
imports: p.Imports,
generateAll: p.GenerateAll,
omitGogo: p.OmitGogo,
@@ -199,17 +189,17 @@ func (p *protobufPackage) generatorFunc(c *generator.Context) []generator.Genera
}
func (p *protobufPackage) GoPackageName() string {
return filepath.Base(p.PackagePath)
return filepath.Base(p.Path())
}
func (p *protobufPackage) ImportPath() string {
return filepath.Join(p.PackagePath, "generated.proto")
return filepath.Join(p.Path(), "generated.proto")
}
func (p *protobufPackage) OutputPath() string {
return filepath.Join(p.PackagePath, "generated.pb.go")
return filepath.Join(p.Path(), "generated.pb.go")
}
var (
_ = generator.Package(&protobufPackage{})
_ = generator.Target(&protobufPackage{})
)

View File

@@ -111,8 +111,7 @@ func RewriteGeneratedGogoProtobufFile(name string, extractFn ExtractFunc, option
// TODO: move into upstream gogo-protobuf once https://github.com/gogo/protobuf/issues/181
// has agreement
func rewriteOptionalMethods(decl ast.Decl, isOptional OptionalFunc) {
switch t := decl.(type) {
case *ast.FuncDecl:
if t, ok := decl.(*ast.FuncDecl); ok {
ident, ptr, ok := receiver(t)
if !ok {
return
@@ -150,8 +149,7 @@ type optionalAssignmentVisitor struct {
// Visit walks the provided node, transforming field initializations of the form
// m.Field = &OptionalType{} -> m.Field = OptionalType{}
func (v optionalAssignmentVisitor) Visit(n ast.Node) ast.Visitor {
switch t := n.(type) {
case *ast.AssignStmt:
if t, ok := n.(*ast.AssignStmt); ok {
if len(t.Lhs) == 1 && len(t.Rhs) == 1 {
if !isFieldSelector(t.Lhs[0], "m", "") {
return nil
@@ -195,13 +193,11 @@ func (v *optionalItemsVisitor) Visit(n ast.Node) ast.Visitor {
t.Lhs[0] = &ast.StarExpr{X: &ast.Ident{Name: "m"}}
}
}
switch rhs := t.Rhs[0].(type) {
case *ast.CallExpr:
if rhs, ok := t.Rhs[0].(*ast.CallExpr); ok {
if ident, ok := rhs.Fun.(*ast.Ident); ok && ident.Name == "append" {
ast.Walk(v, rhs)
if len(rhs.Args) > 0 {
switch arg := rhs.Args[0].(type) {
case *ast.Ident:
if arg, ok := rhs.Args[0].(*ast.Ident); ok {
if arg.Name == "m" {
rhs.Args[0] = &ast.StarExpr{X: &ast.Ident{Name: "m"}}
}
@@ -212,8 +208,7 @@ func (v *optionalItemsVisitor) Visit(n ast.Node) ast.Visitor {
}
}
case *ast.IfStmt:
switch cond := t.Cond.(type) {
case *ast.BinaryExpr:
if cond, ok := t.Cond.(*ast.BinaryExpr); ok {
if cond.Op == token.EQL {
if isFieldSelector(cond.X, "m", "Items") && isIdent(cond.Y, "nil") {
cond.X = &ast.StarExpr{X: &ast.Ident{Name: "m"}}
@@ -225,8 +220,7 @@ func (v *optionalItemsVisitor) Visit(n ast.Node) ast.Visitor {
// if err := m[len(m.Items)-1].Unmarshal(data[iNdEx:postIndex]); err != nil {
// return err
// }
switch s := t.Init.(type) {
case *ast.AssignStmt:
if s, ok := t.Init.(*ast.AssignStmt); ok {
if call, ok := s.Rhs[0].(*ast.CallExpr); ok {
if sel, ok := call.Fun.(*ast.SelectorExpr); ok {
if x, ok := sel.X.(*ast.IndexExpr); ok {
@@ -302,15 +296,13 @@ func receiver(f *ast.FuncDecl) (ident *ast.Ident, pointer bool, ok bool) {
// dropExistingTypeDeclarations removes any type declaration for which extractFn returns true. The function
// returns true if the entire declaration should be dropped.
func dropExistingTypeDeclarations(decl ast.Decl, extractFn ExtractFunc) bool {
switch t := decl.(type) {
case *ast.GenDecl:
if t, ok := decl.(*ast.GenDecl); ok {
if t.Tok != token.TYPE {
return false
}
specs := []ast.Spec{}
for _, s := range t.Specs {
switch spec := s.(type) {
case *ast.TypeSpec:
if spec, ok := s.(*ast.TypeSpec); ok {
if extractFn(spec) {
continue
}
@@ -329,15 +321,13 @@ func dropExistingTypeDeclarations(decl ast.Decl, extractFn ExtractFunc) bool {
// to prevent generation from being able to define side-effects. The function returns true
// if the entire declaration should be dropped.
func dropEmptyImportDeclarations(decl ast.Decl) bool {
switch t := decl.(type) {
case *ast.GenDecl:
if t, ok := decl.(*ast.GenDecl); ok {
if t.Tok != token.IMPORT {
return false
}
specs := []ast.Spec{}
for _, s := range t.Specs {
switch spec := s.(type) {
case *ast.ImportSpec:
if spec, ok := s.(*ast.ImportSpec); ok {
if spec.Name != nil && spec.Name.Name == "_" {
continue
}

View File

@@ -17,7 +17,7 @@ limitations under the License.
package protobuf
import (
"k8s.io/gengo/types"
"k8s.io/gengo/v2"
"k8s.io/klog/v2"
)
@@ -25,7 +25,7 @@ import (
// 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)
val, err := gengo.ExtractSingleBoolCommentTag("+", key, false, lines)
if err != nil {
klog.Fatal(err)
}

View File

@@ -1 +0,0 @@
import-boss

View File

@@ -1,97 +0,0 @@
## Purpose
- `import-boss` enforces import restrictions against all pull requests submitted to the [k/k](https://github.com/kubernetes/kubernetes) repository. There are a number of `.import-restrictions` files that in the [k/k](https://github.com/kubernetes/kubernetes) repository, all of which are defined in `YAML` (or `JSON`) format.
## How does it work?
- When a directory is verified, `import-boss` looks for a file called `.import-restrictions`. If this file is not found, `import-boss` will go up to the parent directory until it finds this `.import-restrictions` file.
- Adding `.import-restrictions` files does not add them to CI runs. They need to be explicitly added to `hack/verify-import-boss.sh`. Once an `.import-restrictions` file is added, all of the sub-packages of this file's directory are added as well.
### What are Rules?
- If an `.import-restrictions` file is found, then all imports of the package are checked against each `rule` in the file. A `rule` consists of three parts:
- A `SelectorRegexp`, to select the import paths that the rule applies to.
- A list of `AllowedPrefixes`
- A list of `ForbiddenPrefixes`
- An import is allowed if it matches at least one allowed prefix and does not match any forbidden prefixes. An example `.import-restrictions` file looks like this:
```json
{
"Rules": [
{
"SelectorRegexp": "k8s[.]io",
"AllowedPrefixes": [
"k8s.io/gengo/examples",
"k8s.io/kubernetes/third_party"
],
"ForbiddenPrefixes": [
"k8s.io/kubernetes/pkg/third_party/deprecated"
]
},
{
"SelectorRegexp": "^unsafe$",
"AllowedPrefixes": [
],
"ForbiddenPrefixes": [
""
]
}
]
}
```
- Take note of `"SelectorRegexp": "k8s[.]io"` in the first block. This specifies that we are applying these rules to the `"k8s.io"` import path.
- The second block explicitly matches the "unsafe" package, and forbids it ("" is a prefix of everything).
### What are Inverse Rules?
- In contrast to non-inverse rules, which are defined in importing packages, inverse rules are defined in imported packages.
- Inverse rules allow for fine-grained import restrictions for "private packages" where we don't want to spread use inside of [kubernetes/kubernetes](https://github.com/kubernetes/kubernetes).
- If an `.import-restrictions` file is found, then all imports of the package are checked against each `inverse rule` in the file. This check will continue, climbing up the directory tree, until a match is found and accepted.
- Inverse rules also have a boolean `transitive` option. When this option is true, the import rule is also applied to `transitive` imports.
- `transitive` imports are dependencies not directly depended on by the code, but are needed to run the application. Use this option if you want to apply restrictions to those indirect dependencies.
```yaml
rules:
- selectorRegexp: k8s[.]io
allowedPrefixes:
- k8s.io/gengo/examples
- k8s.io/kubernetes/third_party
forbiddenPrefixes:
- k8s.io/kubernetes/pkg/third_party/deprecated
- selectorRegexp: ^unsafe$
forbiddenPrefixes:
- ""
inverseRules:
- selectorRegexp: k8s[.]io
allowedPrefixes:
- k8s.io/same-repo
- k8s.io/kubernetes/pkg/legacy
forbiddenPrefixes:
- k8s.io/kubernetes/pkg/legacy/subpkg
- selectorRegexp: k8s[.]io
transitive: true
forbiddenPrefixes:
- k8s.io/kubernetes/cmd/kubelet
- k8s.io/kubernetes/cmd/kubectl
```
## How do I run import-boss within the k/k repo?
- In order to include _test.go files, make sure to pass in the `include-test-files` flag:
```sh
hack/verify-import-boss.sh --include-test-files=true
```
- To include other directories, pass in a directory or directories using the `input-dirs` flag:
```sh
hack/verify-import-boss.sh --input-dirs="k8s.io/kubernetes/test/e2e/framework/..."
```
## Reference
- [import-boss](https://github.com/kubernetes/gengo/tree/master/examples/import-boss)

View File

@@ -1,45 +0,0 @@
/*
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.
*/
// import-boss enforces import restrictions in a given repository.
package main
import (
"os"
"github.com/spf13/pflag"
"k8s.io/gengo/args"
"k8s.io/gengo/examples/import-boss/generators"
"k8s.io/klog/v2"
)
func main() {
klog.InitFlags(nil)
arguments := args.Default()
pflag.CommandLine.BoolVar(&arguments.IncludeTestFiles, "include-test-files", false, "If true, include *_test.go files.")
if err := arguments.Execute(
generators.NameSystems(),
generators.DefaultNameSystem(),
generators.Packages,
); err != nil {
klog.Errorf("Error: %v", err)
os.Exit(1)
}
klog.V(2).Info("Completed successfully.")
}

View File

@@ -18,18 +18,18 @@ package args
import (
"fmt"
"path"
"github.com/spf13/pflag"
codegenutil "k8s.io/code-generator/pkg/util"
"k8s.io/gengo/args"
)
// CustomArgs is used by the gengo framework to pass args specific to this generator.
type CustomArgs struct {
VersionedClientSetPackage string
InternalClientSetPackage string
ListersPackage string
// Args is used by the gengo framework to pass args specific to this generator.
type Args struct {
OutputDir string // must be a directory path
OutputPkg string // must be a Go import-path
GoHeaderFile string
VersionedClientSetPackage string // must be a Go import-path
InternalClientSetPackage string // must be a Go import-path
ListersPackage string // must be a Go import-path
SingleDirectory bool
// PluralExceptions define a list of pluralizer exceptions in Type:PluralType format.
@@ -37,47 +37,46 @@ type CustomArgs struct {
PluralExceptions []string
}
// NewDefaults returns default arguments for the generator.
func NewDefaults() (*args.GeneratorArgs, *CustomArgs) {
genericArgs := args.Default().WithoutDefaultFlagParsing()
customArgs := &CustomArgs{
SingleDirectory: false,
PluralExceptions: []string{"Endpoints:Endpoints"},
// New returns default arguments for the generator.
func New() *Args {
return &Args{
SingleDirectory: false,
}
genericArgs.CustomArgs = customArgs
if pkg := codegenutil.CurrentPackage(); len(pkg) != 0 {
genericArgs.OutputPackagePath = path.Join(pkg, "pkg/client/informers")
customArgs.VersionedClientSetPackage = path.Join(pkg, "pkg/client/clientset/versioned")
customArgs.InternalClientSetPackage = path.Join(pkg, "pkg/client/clientset/internalversion")
customArgs.ListersPackage = path.Join(pkg, "pkg/client/listers")
}
return genericArgs, customArgs
}
// AddFlags add the generator flags to the flag set.
func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&ca.InternalClientSetPackage, "internal-clientset-package", ca.InternalClientSetPackage, "the full package name for the internal clientset to use")
fs.StringVar(&ca.VersionedClientSetPackage, "versioned-clientset-package", ca.VersionedClientSetPackage, "the full package name for the versioned clientset to use")
fs.StringVar(&ca.ListersPackage, "listers-package", ca.ListersPackage, "the full package name for the listers to use")
fs.BoolVar(&ca.SingleDirectory, "single-directory", ca.SingleDirectory, "if true, omit the intermediate \"internalversion\" and \"externalversions\" subdirectories")
fs.StringSliceVar(&ca.PluralExceptions, "plural-exceptions", ca.PluralExceptions, "list of comma separated plural exception definitions in Type:PluralizedType format")
func (args *Args) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&args.OutputDir, "output-dir", "",
"the base directory under which to generate results")
fs.StringVar(&args.OutputPkg, "output-pkg", args.OutputPkg,
"the Go import-path of the generated results")
fs.StringVar(&args.GoHeaderFile, "go-header-file", "",
"the path to a file containing boilerplate header text; the string \"YEAR\" will be replaced with the current 4-digit year")
fs.StringVar(&args.InternalClientSetPackage, "internal-clientset-package", args.InternalClientSetPackage,
"the Go import-path of the internal clientset to use")
fs.StringVar(&args.VersionedClientSetPackage, "versioned-clientset-package", args.VersionedClientSetPackage,
"the Go import-path of the versioned clientset to use")
fs.StringVar(&args.ListersPackage, "listers-package", args.ListersPackage,
"the Go import-path of the listers to use")
fs.BoolVar(&args.SingleDirectory, "single-directory", args.SingleDirectory,
"if true, omit the intermediate \"internalversion\" and \"externalversions\" subdirectories")
fs.StringSliceVar(&args.PluralExceptions, "plural-exceptions", args.PluralExceptions,
"list of comma separated plural exception definitions in Type:PluralizedType format")
}
// Validate checks the given arguments.
func Validate(genericArgs *args.GeneratorArgs) error {
customArgs := genericArgs.CustomArgs.(*CustomArgs)
if len(genericArgs.OutputPackagePath) == 0 {
return fmt.Errorf("output package cannot be empty")
func (args *Args) Validate() error {
if len(args.OutputDir) == 0 {
return fmt.Errorf("--output-dir must be specified")
}
if len(customArgs.VersionedClientSetPackage) == 0 {
return fmt.Errorf("versioned clientset package cannot be empty")
if len(args.OutputPkg) == 0 {
return fmt.Errorf("--output-pkg must be specified")
}
if len(customArgs.ListersPackage) == 0 {
return fmt.Errorf("listers package cannot be empty")
if len(args.VersionedClientSetPackage) == 0 {
return fmt.Errorf("--versioned-clientset-package must be specified")
}
if len(args.ListersPackage) == 0 {
return fmt.Errorf("--listers-package must be specified")
}
return nil
}

View File

@@ -21,9 +21,9 @@ import (
"path"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
"k8s.io/klog/v2"
)
@@ -31,7 +31,7 @@ import (
// factoryGenerator produces a file of listers for a given GroupVersion and
// type.
type factoryGenerator struct {
generator.DefaultGen
generator.GoGenerator
outputPackage string
imports namer.ImportTracker
groupVersions map[string]clientgentypes.GroupVersions

View File

@@ -19,9 +19,9 @@ package generators
import (
"io"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
"k8s.io/klog/v2"
)
@@ -29,7 +29,7 @@ import (
// factoryInterfaceGenerator produces a file of interfaces used to break a dependency cycle for
// informer registration
type factoryInterfaceGenerator struct {
generator.DefaultGen
generator.GoGenerator
outputPackage string
imports namer.ImportTracker
clientSetPackage string

View File

@@ -23,14 +23,14 @@ import (
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
codegennamer "k8s.io/code-generator/pkg/namer"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
)
// genericGenerator generates the generic informer.
type genericGenerator struct {
generator.DefaultGen
generator.GoGenerator
outputPackage string
imports namer.ImportTracker
groupVersions map[string]clientgentypes.GroupVersions

View File

@@ -18,18 +18,18 @@ package generators
import (
"io"
"path/filepath"
"path"
"strings"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
)
// groupInterfaceGenerator generates the per-group interface file.
type groupInterfaceGenerator struct {
generator.DefaultGen
generator.GoGenerator
outputPackage string
imports namer.ImportTracker
groupVersions clientgentypes.GroupVersions
@@ -70,7 +70,7 @@ func (g *groupInterfaceGenerator) GenerateType(c *generator.Context, t *types.Ty
versions := make([]versionData, 0, len(g.groupVersions.Versions))
for _, version := range g.groupVersions.Versions {
gv := clientgentypes.GroupVersion{Group: g.groupVersions.Group, Version: version.Version}
versionPackage := filepath.Join(g.outputPackage, strings.ToLower(gv.Version.NonEmpty()))
versionPackage := path.Join(g.outputPackage, strings.ToLower(gv.Version.NonEmpty()))
iface := c.Universe.Type(types.Name{Package: versionPackage, Name: "Interface"})
versions = append(versions, versionData{
Name: namer.IC(version.Version.NonEmpty()),

View File

@@ -21,9 +21,9 @@ import (
"io"
"strings"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
"k8s.io/code-generator/cmd/client-gen/generators/util"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
@@ -34,7 +34,7 @@ import (
// informerGenerator produces a file of listers for a given GroupVersion and
// type.
type informerGenerator struct {
generator.DefaultGen
generator.GoGenerator
outputPackage string
groupPkgName string
groupVersion clientgentypes.GroupVersion

View File

@@ -22,16 +22,15 @@ import (
"path/filepath"
"strings"
"k8s.io/gengo/args"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/klog/v2"
"k8s.io/code-generator/cmd/client-gen/generators/util"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
informergenargs "k8s.io/code-generator/cmd/informer-gen/args"
"k8s.io/code-generator/cmd/informer-gen/args"
genutil "k8s.io/code-generator/pkg/util"
"k8s.io/gengo/v2"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
"k8s.io/klog/v2"
)
// NameSystems returns the name system used by the generators in this package.
@@ -85,37 +84,34 @@ func isInternal(m types.Member) bool {
return !strings.Contains(m.Tags, "json")
}
func packageForInternalInterfaces(base string) string {
return filepath.Join(base, "internalinterfaces")
}
const subdirForInternalInterfaces = "internalinterfaces"
// Packages makes the client package definition.
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
boilerplate, err := arguments.LoadGoBoilerplate()
// GetTargets makes the client target definition.
func GetTargets(context *generator.Context, args *args.Args) []generator.Target {
boilerplate, err := gengo.GoBoilerplate(args.GoHeaderFile, "", gengo.StdGeneratedBy)
if err != nil {
klog.Fatalf("Failed loading boilerplate: %v", err)
}
customArgs, ok := arguments.CustomArgs.(*informergenargs.CustomArgs)
if !ok {
klog.Fatalf("Wrong CustomArgs type: %T", arguments.CustomArgs)
internalVersionOutputDir := args.OutputDir
internalVersionOutputPkg := args.OutputPkg
externalVersionOutputDir := args.OutputDir
externalVersionOutputPkg := args.OutputPkg
if !args.SingleDirectory {
internalVersionOutputDir = filepath.Join(internalVersionOutputDir, "internalversion")
internalVersionOutputPkg = path.Join(internalVersionOutputPkg, "internalversion")
externalVersionOutputDir = filepath.Join(externalVersionOutputDir, "externalversions")
externalVersionOutputPkg = path.Join(externalVersionOutputPkg, "externalversions")
}
internalVersionPackagePath := filepath.Join(arguments.OutputPackagePath)
externalVersionPackagePath := filepath.Join(arguments.OutputPackagePath)
if !customArgs.SingleDirectory {
internalVersionPackagePath = filepath.Join(arguments.OutputPackagePath, "internalversion")
externalVersionPackagePath = filepath.Join(arguments.OutputPackagePath, "externalversions")
}
var packageList generator.Packages
var targetList []generator.Target
typesForGroupVersion := make(map[clientgentypes.GroupVersion][]*types.Type)
externalGroupVersions := make(map[string]clientgentypes.GroupVersions)
internalGroupVersions := make(map[string]clientgentypes.GroupVersions)
groupGoNames := make(map[string]string)
for _, inputDir := range arguments.InputDirs {
p := context.Universe.Package(genutil.Vendorless(inputDir))
for _, inputPkg := range context.Inputs {
p := context.Universe.Package(inputPkg)
objectMeta, internal, err := objectMetaForPackage(p)
if err != nil {
@@ -148,14 +144,14 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
// If there's a comment of the form "// +groupName=somegroup" or
// "// +groupName=somegroup.foo.bar.io", use the first field (somegroup) as the name of the
// group when generating.
if override := types.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil {
if override := gengo.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil {
gv.Group = clientgentypes.Group(override[0])
}
// If there's a comment of the form "// +groupGoName=SomeUniqueShortName", use that as
// the Go group identifier in CamelCase. It defaults
groupGoNames[groupPackageName] = namer.IC(strings.Split(gv.Group.NonEmpty(), ".")[0])
if override := types.ExtractCommentTags("+", p.Comments)["groupGoName"]; override != nil {
if override := gengo.ExtractCommentTags("+", p.Comments)["groupGoName"]; override != nil {
groupGoNames[groupPackageName] = namer.IC(override[0])
}
@@ -191,57 +187,80 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
typesToGenerate = orderer.OrderTypes(typesToGenerate)
if internal {
packageList = append(packageList, versionPackage(internalVersionPackagePath, groupPackageName, gv, groupGoNames[groupPackageName], boilerplate, typesToGenerate, customArgs.InternalClientSetPackage, customArgs.ListersPackage))
targetList = append(targetList,
versionTarget(
internalVersionOutputDir, internalVersionOutputPkg,
groupPackageName, gv, groupGoNames[groupPackageName],
boilerplate, typesToGenerate,
args.InternalClientSetPackage, args.ListersPackage))
} else {
packageList = append(packageList, versionPackage(externalVersionPackagePath, groupPackageName, gv, groupGoNames[groupPackageName], boilerplate, typesToGenerate, customArgs.VersionedClientSetPackage, customArgs.ListersPackage))
targetList = append(targetList,
versionTarget(
externalVersionOutputDir, externalVersionOutputPkg,
groupPackageName, gv, groupGoNames[groupPackageName],
boilerplate, typesToGenerate,
args.VersionedClientSetPackage, args.ListersPackage))
}
}
if len(externalGroupVersions) != 0 {
packageList = append(packageList, factoryInterfacePackage(externalVersionPackagePath, boilerplate, customArgs.VersionedClientSetPackage))
packageList = append(packageList, factoryPackage(externalVersionPackagePath, boilerplate, groupGoNames, genutil.PluralExceptionListToMapOrDie(customArgs.PluralExceptions), externalGroupVersions,
customArgs.VersionedClientSetPackage,
typesForGroupVersion))
targetList = append(targetList,
factoryInterfaceTarget(
externalVersionOutputDir, externalVersionOutputPkg,
boilerplate, args.VersionedClientSetPackage))
targetList = append(targetList,
factoryTarget(
externalVersionOutputDir, externalVersionOutputPkg,
boilerplate, groupGoNames, genutil.PluralExceptionListToMapOrDie(args.PluralExceptions),
externalGroupVersions, args.VersionedClientSetPackage, typesForGroupVersion))
for _, gvs := range externalGroupVersions {
packageList = append(packageList, groupPackage(externalVersionPackagePath, gvs, boilerplate))
targetList = append(targetList,
groupTarget(externalVersionOutputDir, externalVersionOutputPkg, gvs, boilerplate))
}
}
if len(internalGroupVersions) != 0 {
packageList = append(packageList, factoryInterfacePackage(internalVersionPackagePath, boilerplate, customArgs.InternalClientSetPackage))
packageList = append(packageList, factoryPackage(internalVersionPackagePath, boilerplate, groupGoNames, genutil.PluralExceptionListToMapOrDie(customArgs.PluralExceptions), internalGroupVersions, customArgs.InternalClientSetPackage, typesForGroupVersion))
targetList = append(targetList,
factoryInterfaceTarget(internalVersionOutputDir, internalVersionOutputPkg, boilerplate, args.InternalClientSetPackage))
targetList = append(targetList,
factoryTarget(
internalVersionOutputDir, internalVersionOutputPkg,
boilerplate, groupGoNames, genutil.PluralExceptionListToMapOrDie(args.PluralExceptions),
internalGroupVersions, args.InternalClientSetPackage, typesForGroupVersion))
for _, gvs := range internalGroupVersions {
packageList = append(packageList, groupPackage(internalVersionPackagePath, gvs, boilerplate))
targetList = append(targetList,
groupTarget(internalVersionOutputDir, internalVersionOutputPkg, gvs, boilerplate))
}
}
return packageList
return targetList
}
func factoryPackage(basePackage string, boilerplate []byte, groupGoNames, pluralExceptions map[string]string, groupVersions map[string]clientgentypes.GroupVersions, clientSetPackage string,
typesForGroupVersion map[clientgentypes.GroupVersion][]*types.Type) generator.Package {
return &generator.DefaultPackage{
PackageName: filepath.Base(basePackage),
PackagePath: basePackage,
HeaderText: boilerplate,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
func factoryTarget(outputDirBase, outputPkgBase string, boilerplate []byte, groupGoNames, pluralExceptions map[string]string, groupVersions map[string]clientgentypes.GroupVersions, clientSetPackage string,
typesForGroupVersion map[clientgentypes.GroupVersion][]*types.Type) generator.Target {
return &generator.SimpleTarget{
PkgName: path.Base(outputDirBase),
PkgPath: outputPkgBase,
PkgDir: outputDirBase,
HeaderComment: boilerplate,
GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = append(generators, &factoryGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: "factory",
GoGenerator: generator.GoGenerator{
OutputFilename: "factory.go",
},
outputPackage: basePackage,
outputPackage: outputPkgBase,
imports: generator.NewImportTracker(),
groupVersions: groupVersions,
clientSetPackage: clientSetPackage,
internalInterfacesPackage: packageForInternalInterfaces(basePackage),
internalInterfacesPackage: path.Join(outputPkgBase, subdirForInternalInterfaces),
gvGoNames: groupGoNames,
})
generators = append(generators, &genericGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: "generic",
GoGenerator: generator.GoGenerator{
OutputFilename: "generic.go",
},
outputPackage: basePackage,
outputPackage: outputPkgBase,
imports: generator.NewImportTracker(),
groupVersions: groupVersions,
pluralExceptions: pluralExceptions,
@@ -254,19 +273,21 @@ func factoryPackage(basePackage string, boilerplate []byte, groupGoNames, plural
}
}
func factoryInterfacePackage(basePackage string, boilerplate []byte, clientSetPackage string) generator.Package {
packagePath := packageForInternalInterfaces(basePackage)
func factoryInterfaceTarget(outputDirBase, outputPkgBase string, boilerplate []byte, clientSetPackage string) generator.Target {
outputDir := filepath.Join(outputDirBase, subdirForInternalInterfaces)
outputPkg := path.Join(outputPkgBase, subdirForInternalInterfaces)
return &generator.DefaultPackage{
PackageName: filepath.Base(packagePath),
PackagePath: packagePath,
HeaderText: boilerplate,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
return &generator.SimpleTarget{
PkgName: path.Base(outputDir),
PkgPath: outputPkg,
PkgDir: outputDir,
HeaderComment: boilerplate,
GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = append(generators, &factoryInterfaceGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: "factory_interfaces",
GoGenerator: generator.GoGenerator{
OutputFilename: "factory_interfaces.go",
},
outputPackage: packagePath,
outputPackage: outputPkg,
imports: generator.NewImportTracker(),
clientSetPackage: clientSetPackage,
})
@@ -276,23 +297,25 @@ func factoryInterfacePackage(basePackage string, boilerplate []byte, clientSetPa
}
}
func groupPackage(basePackage string, groupVersions clientgentypes.GroupVersions, boilerplate []byte) generator.Package {
packagePath := filepath.Join(basePackage, groupVersions.PackageName)
func groupTarget(outputDirBase, outputPackageBase string, groupVersions clientgentypes.GroupVersions, boilerplate []byte) generator.Target {
outputDir := filepath.Join(outputDirBase, groupVersions.PackageName)
outputPkg := path.Join(outputPackageBase, groupVersions.PackageName)
groupPkgName := strings.Split(string(groupVersions.PackageName), ".")[0]
return &generator.DefaultPackage{
PackageName: groupPkgName,
PackagePath: packagePath,
HeaderText: boilerplate,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
return &generator.SimpleTarget{
PkgName: groupPkgName,
PkgPath: outputPkg,
PkgDir: outputDir,
HeaderComment: boilerplate,
GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = append(generators, &groupInterfaceGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: "interface",
GoGenerator: generator.GoGenerator{
OutputFilename: "interface.go",
},
outputPackage: packagePath,
outputPackage: outputPkg,
groupVersions: groupVersions,
imports: generator.NewImportTracker(),
internalInterfacesPackage: packageForInternalInterfaces(basePackage),
internalInterfacesPackage: path.Join(outputPackageBase, subdirForInternalInterfaces),
})
return generators
},
@@ -303,30 +326,33 @@ func groupPackage(basePackage string, groupVersions clientgentypes.GroupVersions
}
}
func versionPackage(basePackage string, groupPkgName string, gv clientgentypes.GroupVersion, groupGoName string, boilerplate []byte, typesToGenerate []*types.Type, clientSetPackage, listersPackage string) generator.Package {
packagePath := filepath.Join(basePackage, groupPkgName, strings.ToLower(gv.Version.NonEmpty()))
func versionTarget(outputDirBase, outputPkgBase string, groupPkgName string, gv clientgentypes.GroupVersion, groupGoName string, boilerplate []byte, typesToGenerate []*types.Type, clientSetPackage, listersPackage string) generator.Target {
subdir := []string{groupPkgName, strings.ToLower(gv.Version.NonEmpty())}
outputDir := filepath.Join(outputDirBase, filepath.Join(subdir...))
outputPkg := path.Join(outputPkgBase, path.Join(subdir...))
return &generator.DefaultPackage{
PackageName: strings.ToLower(gv.Version.NonEmpty()),
PackagePath: packagePath,
HeaderText: boilerplate,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
return &generator.SimpleTarget{
PkgName: strings.ToLower(gv.Version.NonEmpty()),
PkgPath: outputPkg,
PkgDir: outputDir,
HeaderComment: boilerplate,
GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = append(generators, &versionInterfaceGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: "interface",
GoGenerator: generator.GoGenerator{
OutputFilename: "interface.go",
},
outputPackage: packagePath,
outputPackage: outputPkg,
imports: generator.NewImportTracker(),
types: typesToGenerate,
internalInterfacesPackage: packageForInternalInterfaces(basePackage),
internalInterfacesPackage: path.Join(outputPkgBase, subdirForInternalInterfaces),
})
for _, t := range typesToGenerate {
generators = append(generators, &informerGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: strings.ToLower(t.Name.Name),
GoGenerator: generator.GoGenerator{
OutputFilename: strings.ToLower(t.Name.Name) + ".go",
},
outputPackage: packagePath,
outputPackage: outputPkg,
groupPkgName: groupPkgName,
groupVersion: gv,
groupGoName: groupGoName,
@@ -334,7 +360,7 @@ func versionPackage(basePackage string, groupPkgName string, gv clientgentypes.G
imports: generator.NewImportTracker(),
clientSetPackage: clientSetPackage,
listersPackage: listersPackage,
internalInterfacesPackage: packageForInternalInterfaces(basePackage),
internalInterfacesPackage: path.Join(outputPkgBase, subdirForInternalInterfaces),
})
}
return generators

View File

@@ -16,7 +16,7 @@ limitations under the License.
package generators
import "k8s.io/gengo/types"
import "k8s.io/gengo/v2/types"
var (
apiScheme = types.Name{Package: "k8s.io/kubernetes/pkg/api/legacyscheme", Name: "Scheme"}

View File

@@ -19,16 +19,16 @@ package generators
import (
"io"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
"k8s.io/code-generator/cmd/client-gen/generators/util"
)
// versionInterfaceGenerator generates the per-version interface file.
type versionInterfaceGenerator struct {
generator.DefaultGen
generator.GoGenerator
outputPackage string
imports namer.ImportTracker
types []*types.Type

View File

@@ -20,39 +20,38 @@ import (
"flag"
"github.com/spf13/pflag"
"k8s.io/code-generator/cmd/informer-gen/args"
"k8s.io/code-generator/cmd/informer-gen/generators"
"k8s.io/code-generator/pkg/util"
"k8s.io/gengo/v2"
"k8s.io/gengo/v2/generator"
"k8s.io/klog/v2"
generatorargs "k8s.io/code-generator/cmd/informer-gen/args"
)
func main() {
klog.InitFlags(nil)
genericArgs, customArgs := generatorargs.NewDefaults()
args := args.New()
// Override defaults.
// TODO: move out of informer-gen
genericArgs.OutputPackagePath = "k8s.io/kubernetes/pkg/client/informers/informers_generated"
customArgs.VersionedClientSetPackage = "k8s.io/kubernetes/pkg/client/clientset_generated/clientset"
customArgs.InternalClientSetPackage = "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset"
customArgs.ListersPackage = "k8s.io/kubernetes/pkg/client/listers"
genericArgs.AddFlags(pflag.CommandLine)
customArgs.AddFlags(pflag.CommandLine)
args.AddFlags(pflag.CommandLine)
flag.Set("logtostderr", "true")
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
pflag.Parse()
if err := generatorargs.Validate(genericArgs); err != nil {
if err := args.Validate(); err != nil {
klog.Fatalf("Error: %v", err)
}
myTargets := func(context *generator.Context) []generator.Target {
return generators.GetTargets(context, args)
}
// Run it.
if err := genericArgs.Execute(
generators.NameSystems(util.PluralExceptionListToMapOrDie(customArgs.PluralExceptions)),
if err := gengo.Execute(
generators.NameSystems(util.PluralExceptionListToMapOrDie(args.PluralExceptions)),
generators.DefaultNameSystem(),
generators.Packages,
myTargets,
gengo.StdBuildTag,
pflag.Args(),
); err != nil {
klog.Fatalf("Error: %v", err)
}

View File

@@ -18,47 +18,45 @@ package args
import (
"fmt"
"path"
"github.com/spf13/pflag"
codegenutil "k8s.io/code-generator/pkg/util"
"k8s.io/gengo/args"
)
// CustomArgs is used by the gengo framework to pass args specific to this generator.
type CustomArgs struct {
// Args is used by the gengo framework to pass args specific to this generator.
type Args struct {
OutputDir string // must be a directory path
OutputPkg string // must be a Go import-path
GoHeaderFile string
// PluralExceptions specify list of exceptions used when pluralizing certain types.
// For example 'Endpoints:Endpoints', otherwise the pluralizer will generate 'Endpointes'.
PluralExceptions []string
}
// NewDefaults returns default arguments for the generator.
func NewDefaults() (*args.GeneratorArgs, *CustomArgs) {
genericArgs := args.Default().WithoutDefaultFlagParsing()
customArgs := &CustomArgs{
PluralExceptions: []string{"Endpoints:Endpoints"},
}
genericArgs.CustomArgs = customArgs
if pkg := codegenutil.CurrentPackage(); len(pkg) != 0 {
genericArgs.OutputPackagePath = path.Join(pkg, "pkg/client/listers")
}
return genericArgs, customArgs
// New returns default arguments for the generator.
func New() *Args {
return &Args{}
}
// AddFlags add the generator flags to the flag set.
func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet) {
fs.StringSliceVar(&ca.PluralExceptions, "plural-exceptions", ca.PluralExceptions, "list of comma separated plural exception definitions in Type:PluralizedType format")
func (args *Args) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&args.OutputDir, "output-dir", "",
"the base directory under which to generate results")
fs.StringVar(&args.OutputPkg, "output-pkg", "",
"the base Go import-path under which to generate results")
fs.StringSliceVar(&args.PluralExceptions, "plural-exceptions", args.PluralExceptions,
"list of comma separated plural exception definitions in Type:PluralizedType format")
fs.StringVar(&args.GoHeaderFile, "go-header-file", "",
"the path to a file containing boilerplate header text; the string \"YEAR\" will be replaced with the current 4-digit year")
}
// Validate checks the given arguments.
func Validate(genericArgs *args.GeneratorArgs) error {
_ = genericArgs.CustomArgs.(*CustomArgs)
if len(genericArgs.OutputPackagePath) == 0 {
return fmt.Errorf("output package cannot be empty")
func (args *Args) Validate() error {
if len(args.OutputDir) == 0 {
return fmt.Errorf("--output-dir must be specified")
}
if len(args.OutputPkg) == 0 {
return fmt.Errorf("--output-pkg must be specified")
}
return nil
}

View File

@@ -22,17 +22,18 @@ import (
"path/filepath"
"strings"
"k8s.io/gengo/generator"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/types"
"k8s.io/klog/v2"
"k8s.io/code-generator/cmd/client-gen/generators/util"
)
// expansionGenerator produces a file for a expansion interfaces.
type expansionGenerator struct {
generator.DefaultGen
packagePath string
types []*types.Type
generator.GoGenerator
outputPath string
types []*types.Type
}
// We only want to call GenerateType() once per group.
@@ -44,11 +45,16 @@ func (g *expansionGenerator) GenerateType(c *generator.Context, t *types.Type, w
sw := generator.NewSnippetWriter(w, c, "$", "$")
for _, t := range g.types {
tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
if _, err := os.Stat(filepath.Join(g.packagePath, strings.ToLower(t.Name.Name+"_expansion.go"))); os.IsNotExist(err) {
manualFile := filepath.Join(g.outputPath, strings.ToLower(t.Name.Name+"_expansion.go"))
if _, err := os.Stat(manualFile); err == nil {
klog.V(4).Infof("file %q exists, not generating", manualFile)
} else if os.IsNotExist(err) {
sw.Do(expansionInterfaceTemplate, t)
if !tags.NonNamespaced {
sw.Do(namespacedExpansionInterfaceTemplate, t)
}
} else {
return err
}
}
return sw.Error()

View File

@@ -19,17 +19,17 @@ package generators
import (
"fmt"
"io"
"path"
"path/filepath"
"strings"
"k8s.io/gengo/args"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/code-generator/cmd/client-gen/generators/util"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
"k8s.io/code-generator/cmd/lister-gen/args"
"k8s.io/gengo/v2"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
"k8s.io/klog/v2"
)
@@ -59,16 +59,16 @@ func DefaultNameSystem() string {
return "public"
}
// Packages makes the client package definition.
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
boilerplate, err := arguments.LoadGoBoilerplate()
// GetTargets makes the client target definition.
func GetTargets(context *generator.Context, args *args.Args) []generator.Target {
boilerplate, err := gengo.GoBoilerplate(args.GoHeaderFile, "", gengo.StdGeneratedBy)
if err != nil {
klog.Fatalf("Failed loading boilerplate: %v", err)
}
var packageList generator.Packages
for _, inputDir := range arguments.InputDirs {
p := context.Universe.Package(inputDir)
var targetList []generator.Target
for _, inputPkg := range context.Inputs {
p := context.Universe.Package(inputPkg)
objectMeta, internal, err := objectMetaForPackage(p)
if err != nil {
@@ -101,7 +101,7 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
// If there's a comment of the form "// +groupName=somegroup" or
// "// +groupName=somegroup.foo.bar.io", use the first field (somegroup) as the name of the
// group when generating.
if override := types.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil {
if override := gengo.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil {
gv.Group = clientgentypes.Group(strings.SplitN(override[0], ".", 2)[0])
}
@@ -119,26 +119,33 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)}
typesToGenerate = orderer.OrderTypes(typesToGenerate)
packagePath := filepath.Join(arguments.OutputPackagePath, groupPackageName, strings.ToLower(gv.Version.NonEmpty()))
packageList = append(packageList, &generator.DefaultPackage{
PackageName: strings.ToLower(gv.Version.NonEmpty()),
PackagePath: packagePath,
HeaderText: boilerplate,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
subdir := []string{groupPackageName, strings.ToLower(gv.Version.NonEmpty())}
outputDir := filepath.Join(args.OutputDir, filepath.Join(subdir...))
outputPkg := path.Join(args.OutputPkg, path.Join(subdir...))
targetList = append(targetList, &generator.SimpleTarget{
PkgName: strings.ToLower(gv.Version.NonEmpty()),
PkgPath: outputPkg,
PkgDir: outputDir,
HeaderComment: boilerplate,
FilterFunc: func(c *generator.Context, t *types.Type) bool {
tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
return tags.GenerateClient && tags.HasVerb("list") && tags.HasVerb("get")
},
GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) {
generators = append(generators, &expansionGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: "expansion_generated",
GoGenerator: generator.GoGenerator{
OutputFilename: "expansion_generated.go",
},
packagePath: filepath.Join(arguments.OutputBase, packagePath),
types: typesToGenerate,
outputPath: outputDir,
types: typesToGenerate,
})
for _, t := range typesToGenerate {
generators = append(generators, &listerGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: strings.ToLower(t.Name.Name),
GoGenerator: generator.GoGenerator{
OutputFilename: strings.ToLower(t.Name.Name) + ".go",
},
outputPackage: arguments.OutputPackagePath,
outputPackage: outputPkg,
groupVersion: gv,
internalGVPkg: internalGVPkg,
typeToGenerate: t,
@@ -148,14 +155,10 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
}
return generators
},
FilterFunc: func(c *generator.Context, t *types.Type) bool {
tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...))
return tags.GenerateClient && tags.HasVerb("list") && tags.HasVerb("get")
},
})
}
return packageList
return targetList
}
// objectMetaForPackage returns the type of ObjectMeta used by package p.
@@ -187,7 +190,7 @@ func isInternal(m types.Member) bool {
// listerGenerator produces a file of listers for a given GroupVersion and
// type.
type listerGenerator struct {
generator.DefaultGen
generator.GoGenerator
outputPackage string
groupVersion clientgentypes.GroupVersion
internalGVPkg string
@@ -233,25 +236,25 @@ func (g *listerGenerator) GenerateType(c *generator.Context, t *types.Type, w io
}
if tags.NonNamespaced {
sw.Do(typeListerInterface_NonNamespaced, m)
sw.Do(typeListerInterfaceNonNamespaced, m)
} else {
sw.Do(typeListerInterface, m)
}
sw.Do(typeListerStruct, m)
sw.Do(typeListerConstructor, m)
sw.Do(typeLister_List, m)
sw.Do(typeListerList, m)
if tags.NonNamespaced {
sw.Do(typeLister_NonNamespacedGet, m)
sw.Do(typeListerNonNamespacedGet, m)
return sw.Error()
}
sw.Do(typeLister_NamespaceLister, m)
sw.Do(typeListerNamespaceLister, m)
sw.Do(namespaceListerInterface, m)
sw.Do(namespaceListerStruct, m)
sw.Do(namespaceLister_List, m)
sw.Do(namespaceLister_Get, m)
sw.Do(namespaceListerList, m)
sw.Do(namespaceListerGet, m)
return sw.Error()
}
@@ -269,7 +272,7 @@ type $.type|public$Lister interface {
}
`
var typeListerInterface_NonNamespaced = `
var typeListerInterfaceNonNamespaced = `
// $.type|public$Lister helps list $.type|publicPlural$.
// All objects returned here must be treated as read-only.
type $.type|public$Lister interface {
@@ -297,7 +300,7 @@ func New$.type|public$Lister(indexer cache.Indexer) $.type|public$Lister {
}
`
var typeLister_List = `
var typeListerList = `
// List lists all $.type|publicPlural$ in the indexer.
func (s *$.type|private$Lister) List(selector labels.Selector) (ret []*$.type|raw$, err error) {
err = cache.ListAll(s.indexer, selector, func(m interface{}) {
@@ -307,14 +310,14 @@ func (s *$.type|private$Lister) List(selector labels.Selector) (ret []*$.type|ra
}
`
var typeLister_NamespaceLister = `
var typeListerNamespaceLister = `
// $.type|publicPlural$ returns an object that can list and get $.type|publicPlural$.
func (s *$.type|private$Lister) $.type|publicPlural$(namespace string) $.type|public$NamespaceLister {
return $.type|private$NamespaceLister{indexer: s.indexer, namespace: namespace}
}
`
var typeLister_NonNamespacedGet = `
var typeListerNonNamespacedGet = `
// Get retrieves the $.type|public$ from the index for a given name.
func (s *$.type|private$Lister) Get(name string) (*$.type|raw$, error) {
obj, exists, err := s.indexer.GetByKey(name)
@@ -351,7 +354,7 @@ type $.type|private$NamespaceLister struct {
}
`
var namespaceLister_List = `
var namespaceListerList = `
// List lists all $.type|publicPlural$ in the indexer for a given namespace.
func (s $.type|private$NamespaceLister) List(selector labels.Selector) (ret []*$.type|raw$, err error) {
err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) {
@@ -361,7 +364,7 @@ func (s $.type|private$NamespaceLister) List(selector labels.Selector) (ret []*$
}
`
var namespaceLister_Get = `
var namespaceListerGet = `
// Get retrieves the $.type|public$ from the indexer for a given namespace and name.
func (s $.type|private$NamespaceLister) Get(name string) (*$.type|raw$, error) {
obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name)

View File

@@ -20,36 +20,38 @@ import (
"flag"
"github.com/spf13/pflag"
"k8s.io/code-generator/cmd/lister-gen/args"
"k8s.io/code-generator/cmd/lister-gen/generators"
"k8s.io/code-generator/pkg/util"
"k8s.io/gengo/v2"
"k8s.io/gengo/v2/generator"
"k8s.io/klog/v2"
generatorargs "k8s.io/code-generator/cmd/lister-gen/args"
)
func main() {
klog.InitFlags(nil)
genericArgs, customArgs := generatorargs.NewDefaults()
args := args.New()
// Override defaults.
// TODO: move this out of lister-gen
genericArgs.OutputPackagePath = "k8s.io/kubernetes/pkg/client/listers"
genericArgs.AddFlags(pflag.CommandLine)
customArgs.AddFlags(pflag.CommandLine)
args.AddFlags(pflag.CommandLine)
flag.Set("logtostderr", "true")
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
pflag.Parse()
if err := generatorargs.Validate(genericArgs); err != nil {
if err := args.Validate(); err != nil {
klog.Fatalf("Error: %v", err)
}
myTargets := func(context *generator.Context) []generator.Target {
return generators.GetTargets(context, args)
}
// Run it.
if err := genericArgs.Execute(
generators.NameSystems(util.PluralExceptionListToMapOrDie(customArgs.PluralExceptions)),
if err := gengo.Execute(
generators.NameSystems(util.PluralExceptionListToMapOrDie(args.PluralExceptions)),
generators.DefaultNameSystem(),
generators.Packages,
myTargets,
gengo.StdBuildTag,
pflag.Args(),
); err != nil {
klog.Fatalf("Error: %v", err)
}

View File

@@ -1,57 +0,0 @@
/*
Copyright 2018 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.
*/
// This package generates openAPI definition file to be used in open API spec generation on API servers. To generate
// definition for a specific type or package add "+k8s:openapi-gen=true" tag to the type/package comment lines. To
// exclude a type from a tagged package, add "+k8s:openapi-gen=false" tag to the type comment lines.
package main
import (
"flag"
"log"
generatorargs "k8s.io/kube-openapi/cmd/openapi-gen/args"
"k8s.io/kube-openapi/pkg/generators"
"github.com/spf13/pflag"
"k8s.io/klog/v2"
)
func main() {
klog.InitFlags(nil)
genericArgs, customArgs := generatorargs.NewDefaults()
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 {
log.Fatalf("Arguments validation error: %v", err)
}
// Generates the code for the OpenAPIDefinitions.
if err := genericArgs.Execute(
generators.NameSystems(),
generators.DefaultNameSystem(),
generators.Packages,
); err != nil {
log.Fatalf("OpenAPI code generation error: %v", err)
}
}

View File

@@ -19,19 +19,30 @@ package args
import (
"fmt"
"k8s.io/gengo/args"
"github.com/spf13/pflag"
)
// NewDefaults returns default arguments for the generator.
func NewDefaults() *args.GeneratorArgs {
genericArgs := args.Default().WithoutDefaultFlagParsing()
genericArgs.OutputFileBaseName = "zz_generated.register"
return genericArgs
type Args struct {
OutputFile string
GoHeaderFile string
}
// New returns default arguments for the generator.
func New() *Args {
return &Args{}
}
// AddFlags add the generator flags to the flag set.
func (args *Args) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&args.OutputFile, "output-file", "generated.register.go",
"the name of the file to be generated")
fs.StringVar(&args.GoHeaderFile, "go-header-file", "",
"the path to a file containing boilerplate header text; the string \"YEAR\" will be replaced with the current 4-digit year")
}
// Validate checks the given arguments.
func Validate(genericArgs *args.GeneratorArgs) error {
if len(genericArgs.OutputFileBaseName) == 0 {
func (args *Args) Validate() error {
if len(args.OutputFile) == 0 {
return fmt.Errorf("output file base name cannot be empty")
}

View File

@@ -21,13 +21,13 @@ import (
"sort"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
)
type registerExternalGenerator struct {
generator.DefaultGen
generator.GoGenerator
outputPackage string
gv clientgentypes.GroupVersion
typesToGenerate []*types.Type

View File

@@ -25,10 +25,11 @@ import (
"k8s.io/klog/v2"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
"k8s.io/gengo/args"
"k8s.io/gengo/generator"
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/code-generator/cmd/register-gen/args"
"k8s.io/gengo/v2"
"k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
)
// NameSystems returns the name system used by the generators in this package.
@@ -42,29 +43,29 @@ func DefaultNameSystem() string {
return "public"
}
// Packages makes packages to generate.
func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages {
boilerplate, err := arguments.LoadGoBoilerplate()
// GetTargets makes targets to generate.
func GetTargets(context *generator.Context, args *args.Args) []generator.Target {
boilerplate, err := gengo.GoBoilerplate(args.GoHeaderFile, gengo.StdBuildTag, gengo.StdGeneratedBy)
if err != nil {
klog.Fatalf("Failed loading boilerplate: %v", err)
}
packages := generator.Packages{}
for _, inputDir := range arguments.InputDirs {
pkg := context.Universe.Package(inputDir)
targets := []generator.Target{}
for _, input := range context.Inputs {
pkg := context.Universe.Package(input)
internal, err := isInternal(pkg)
if err != nil {
klog.V(5).Infof("skipping the generation of %s file, due to err %v", arguments.OutputFileBaseName, err)
klog.V(5).Infof("skipping the generation of %s file, due to err %v", args.OutputFile, err)
continue
}
if internal {
klog.V(5).Infof("skipping the generation of %s file because %s package contains internal types, note that internal types don't have \"json\" tags", arguments.OutputFileBaseName, pkg.Name)
klog.V(5).Infof("skipping the generation of %s file because %s package contains internal types, note that internal types don't have \"json\" tags", args.OutputFile, pkg.Name)
continue
}
registerFileName := "register.go"
searchPath := path.Join(args.DefaultSourceTree(), inputDir, registerFileName)
searchPath := path.Join(pkg.Dir, registerFileName)
if _, err := os.Stat(path.Join(searchPath)); err == nil {
klog.V(5).Infof("skipping the generation of %s file because %s already exists in the path %s", arguments.OutputFileBaseName, registerFileName, searchPath)
klog.V(5).Infof("skipping the generation of %s file because %s already exists in the path %s", args.OutputFile, registerFileName, searchPath)
continue
} else if err != nil && !os.IsNotExist(err) {
klog.Fatalf("an error %v has occurred while checking if %s exists", err, registerFileName)
@@ -82,7 +83,7 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
// if there is a comment of the form "// +groupName=somegroup" or "// +groupName=somegroup.foo.bar.io",
// extract the fully qualified API group name from it and overwrite the group inferred from the package path
if override := types.ExtractCommentTags("+", pkg.Comments)["groupName"]; override != nil {
if override := gengo.ExtractCommentTags("+", pkg.Comments)["groupName"]; override != nil {
groupName := override[0]
klog.V(5).Infof("overriding the group name with = %s", groupName)
gv.Group = clientgentypes.Group(groupName)
@@ -99,16 +100,17 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
}
}
packages = append(packages,
&generator.DefaultPackage{
PackageName: pkg.Name,
PackagePath: pkg.Path,
HeaderText: boilerplate,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
targets = append(targets,
&generator.SimpleTarget{
PkgName: pkg.Name,
PkgPath: pkg.Path, // output to same pkg as input
PkgDir: pkg.Dir, // output to same pkg as input
HeaderComment: boilerplate,
GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) {
return []generator.Generator{
&registerExternalGenerator{
DefaultGen: generator.DefaultGen{
OptionalName: arguments.OutputFileBaseName,
GoGenerator: generator.GoGenerator{
OutputFilename: args.OutputFile,
},
gv: gv,
typesToGenerate: typesToRegister,
@@ -120,7 +122,7 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
})
}
return packages
return targets
}
// isInternal determines whether the given package

View File

@@ -20,28 +20,35 @@ import (
"flag"
"github.com/spf13/pflag"
"k8s.io/klog/v2"
generatorargs "k8s.io/code-generator/cmd/register-gen/args"
"k8s.io/code-generator/cmd/register-gen/args"
"k8s.io/code-generator/cmd/register-gen/generators"
"k8s.io/gengo/v2"
"k8s.io/gengo/v2/generator"
"k8s.io/klog/v2"
)
func main() {
klog.InitFlags(nil)
genericArgs := generatorargs.NewDefaults()
genericArgs.AddFlags(pflag.CommandLine)
args := args.New()
args.AddFlags(pflag.CommandLine)
flag.Set("logtostderr", "true")
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
pflag.Parse()
if err := generatorargs.Validate(genericArgs); err != nil {
if err := args.Validate(); err != nil {
klog.Fatalf("Error: %v", err)
}
if err := genericArgs.Execute(
myTargets := func(context *generator.Context) []generator.Target {
return generators.GetTargets(context, args)
}
if err := gengo.Execute(
generators.NameSystems(),
generators.DefaultNameSystem(),
generators.Packages,
myTargets,
gengo.StdBuildTag,
pflag.Args(),
); err != nil {
klog.Fatalf("Error: %v", err)
}

View File

@@ -1 +0,0 @@
set-gen

View File

@@ -1,53 +0,0 @@
/*
Copyright 2015 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.
*/
// set-gen is an example usage of gengo.
//
// Structs in the input directories with the below line in their comments will
// have sets generated for them.
// // +genset
//
// Any builtin type referenced anywhere in the input directories will have a
// set generated for it.
package main
import (
"os"
"k8s.io/gengo/args"
"k8s.io/gengo/examples/set-gen/generators"
"k8s.io/klog/v2"
)
func main() {
klog.InitFlags(nil)
arguments := args.Default()
// Override defaults.
arguments.InputDirs = []string{"k8s.io/kubernetes/pkg/util/sets/types"}
arguments.OutputPackagePath = "k8s.io/apimachinery/pkg/util/sets"
if err := arguments.Execute(
generators.NameSystems(),
generators.DefaultNameSystem(),
generators.Packages,
); err != nil {
klog.Errorf("Error: %v", err)
os.Exit(1)
}
klog.V(2).Info("Completed successfully.")
}

View File

@@ -14,53 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
set -o errexit
set -o nounset
set -o pipefail
# generate-groups generates everything for a project with external types only, e.g. a project based
# on CustomResourceDefinitions.
if [ "$#" -lt 4 ] || [ "${1}" == "--help" ]; then
cat <<EOF
Usage: $(basename "$0") <generators> <output-package> <apis-package> <groups-versions> ...
<generators> the generators comma separated to run (deepcopy,defaulter,applyconfiguration,client,lister,informer).
<output-package> the output package name (e.g. github.com/example/project/pkg/generated).
<apis-package> the external types dir (e.g. github.com/example/api or github.com/example/project/pkg/apis).
<groups-versions> the groups and their versions in the format "groupA:v1,v2 groupB:v1 groupC:v2", relative
to <api-package>.
... arbitrary flags passed to all generator binaries.
Example:
$(basename "$0") \
deepcopy,client \
github.com/example/project/pkg/client \
github.com/example/project/pkg/apis \
"foo:v1 bar:v1alpha1,v1beta1"
EOF
exit 0
fi
GENS="$1"
OUTPUT_PKG="$2"
APIS_PKG="$3"
GROUPS_WITH_VERSIONS="$4"
shift 4
echo "WARNING: $(basename "$0") is deprecated."
echo "WARNING: Please use k8s.io/code-generator/kube_codegen.sh instead."
echo "ERROR: $(basename "$0") has been removed."
echo "ERROR: Please use k8s.io/code-generator/kube_codegen.sh instead."
echo
if [ "${GENS}" = "all" ] || grep -qw "all" <<<"${GENS}"; then
ALL="applyconfiguration,client,deepcopy,informer,lister"
echo "WARNING: Specifying \"all\" as a generator is deprecated."
echo "WARNING: Please list the specific generators needed."
echo "WARNING: \"all\" is now an alias for \"${ALL}\"; new code generators WILL NOT be added to this set"
echo
GENS="${ALL}"
fi
INT_APIS_PKG=""
exec "$(dirname "${BASH_SOURCE[0]}")/generate-internal-groups.sh" "${GENS}" "${OUTPUT_PKG}" "${INT_APIS_PKG}" "${APIS_PKG}" "${GROUPS_WITH_VERSIONS}" "$@"
exit 1

View File

@@ -14,281 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
set -o errexit
set -o nounset
set -o pipefail
# generate-internal-groups generates everything for a project with internal types, e.g. an
# user-provided API server based on k8s.io/apiserver.
if [ "$#" -lt 5 ] || [ "${1}" == "--help" ]; then
cat <<EOF
Usage: $(basename "$0") <generators> <output-package> <internal-apis-package> <extensiona-apis-package> <groups-versions> ...
<generators> the generators comma separated to run (applyconfiguration,client,conversion,deepcopy,defaulter,informer,lister,openapi).
<output-package> the output package name (e.g. github.com/example/project/pkg/generated).
<int-apis-package> the internal types dir (e.g. github.com/example/project/pkg/apis) or "" if none.
<ext-apis-package> the external types dir (e.g. github.com/example/project/pkg/apis or githubcom/example/apis).
<groups-versions> the groups and their versions in the format "groupA:v1,v2 groupB:v1 groupC:v2", relative
to <api-package>.
... arbitrary flags passed to all generator binaries.
Example:
$(basename "$0") \
deepcopy,defaulter,conversion \
github.com/example/project/pkg/client \
github.com/example/project/pkg/apis \
github.com/example/project/apis \
"foo:v1 bar:v1alpha1,v1beta1"
EOF
exit 0
fi
GENS="$1"
OUTPUT_PKG="$2"
INT_APIS_PKG="$3"
EXT_APIS_PKG="$4"
GROUPS_WITH_VERSIONS="$5"
shift 5
echo "WARNING: $(basename "$0") is deprecated."
echo "WARNING: Please use k8s.io/code-generator/kube_codegen.sh instead."
echo "ERROR: $(basename "$0") has been removed."
echo "ERROR: Please use k8s.io/code-generator/kube_codegen.sh instead."
echo
# If verification only is requested, avoid deleting files
verify_only=""
for ((i = 1; i <= $#; i++)); do
if [ "${!i}" = --verify-only ]; then verify_only=1; fi
done
if [ "${GENS}" = "all" ] || grep -qw "all" <<<"${GENS}"; then
ALL="client,conversion,deepcopy,defaulter,informer,lister,openapi"
echo "WARNING: Specifying \"all\" as a generator is deprecated."
echo "WARNING: Please list the specific generators needed."
echo "WARNING: \"all\" is now an alias for \"${ALL}\"; new code generators WILL NOT be added to this set"
echo
GENS="${ALL}"
fi
(
# To support running this script from anywhere, first cd into this directory,
# and then install with forced module mode on and fully qualified name.
cd "$(dirname "${0}")"
BINS=(
applyconfiguration-gen
client-gen
conversion-gen
deepcopy-gen
defaulter-gen
informer-gen
lister-gen
openapi-gen
)
# Compile all the tools at once - it's slightly faster but also just simpler.
# shellcheck disable=2046 # printf word-splitting is intentional
GO111MODULE=on go install $(printf "k8s.io/code-generator/cmd/%s " "${BINS[@]}")
)
# Go installs the above commands to get installed in $GOBIN if defined, and $GOPATH/bin otherwise:
GOBIN="$(go env GOBIN)"
gobin="${GOBIN:-$(go env GOPATH)/bin}"
function git_find() {
# Similar to find but faster and easier to understand. We want to include
# modified and untracked files because this might be running against code
# which is not tracked by git yet.
git ls-files -cmo --exclude-standard "$@"
}
function git_grep() {
# We want to include modified and untracked files because this might be
# running against code which is not tracked by git yet.
git grep --untracked "$@"
}
function codegen::join() { local IFS="$1"; shift; echo "$*"; }
# enumerate group versions
ALL_FQ_APIS=() # e.g. k8s.io/kubernetes/pkg/apis/apps k8s.io/api/apps/v1
EXT_FQ_APIS=() # e.g. k8s.io/api/apps/v1
GROUP_VERSIONS=() # e.g. apps/v1
for GVs in ${GROUPS_WITH_VERSIONS}; do
IFS=: read -r G Vs <<<"${GVs}"
if [ -n "${INT_APIS_PKG}" ]; then
ALL_FQ_APIS+=("${INT_APIS_PKG}/${G}")
fi
# enumerate versions
for V in ${Vs//,/ }; do
ALL_FQ_APIS+=("${EXT_APIS_PKG}/${G}/${V}")
EXT_FQ_APIS+=("${EXT_APIS_PKG}/${G}/${V}")
GROUP_VERSIONS+=("${G}/${V}")
done
done
CLIENTSET_PKG="${CLIENTSET_PKG_NAME:-clientset}"
CLIENTSET_NAME="${CLIENTSET_NAME_VERSIONED:-versioned}"
if grep -qw "deepcopy" <<<"${GENS}"; then
if [ ! "$verify_only" ]; then
# Nuke existing files
for dir in $(GO111MODULE=on go list -f '{{.Dir}}' "${ALL_FQ_APIS[@]}"); do
pushd "${dir}" >/dev/null
git_find -z ':(glob)**'/zz_generated.deepcopy.go | xargs -0 rm -f
popd >/dev/null
done
fi
echo "Generating deepcopy funcs"
"${gobin}/deepcopy-gen" \
--input-dirs "$(codegen::join , "${ALL_FQ_APIS[@]}")" \
-O zz_generated.deepcopy \
"$@"
fi
if grep -qw "defaulter" <<<"${GENS}"; then
if [ ! "$verify_only" ]; then
# Nuke existing files
for dir in $(GO111MODULE=on go list -f '{{.Dir}}' "${ALL_FQ_APIS[@]}"); do
pushd "${dir}" >/dev/null
git_find -z ':(glob)**'/zz_generated.defaults.go | xargs -0 rm -f
popd >/dev/null
done
fi
echo "Generating defaulters"
"${gobin}/defaulter-gen" \
--input-dirs "$(codegen::join , "${EXT_FQ_APIS[@]}")" \
-O zz_generated.defaults \
"$@"
fi
if grep -qw "conversion" <<<"${GENS}"; then
if [ ! "$verify_only" ]; then
# Nuke existing files
for dir in $(GO111MODULE=on go list -f '{{.Dir}}' "${ALL_FQ_APIS[@]}"); do
pushd "${dir}" >/dev/null
git_find -z ':(glob)**'/zz_generated.conversion.go | xargs -0 rm -f
popd >/dev/null
done
fi
echo "Generating conversions"
"${gobin}/conversion-gen" \
--input-dirs "$(codegen::join , "${ALL_FQ_APIS[@]}")" \
-O zz_generated.conversion \
"$@"
fi
if grep -qw "applyconfiguration" <<<"${GENS}"; then
APPLY_CONFIGURATION_PACKAGE="${OUTPUT_PKG}/${APPLYCONFIGURATION_PKG_NAME:-applyconfiguration}"
if [ ! "$verify_only" ]; then
# Nuke existing files
root="$(GO111MODULE=on go list -f '{{.Dir}}' "${APPLY_CONFIGURATION_PACKAGE}" 2>/dev/null || true)"
if [ -n "${root}" ]; then
pushd "${root}" >/dev/null
git_grep -l --null \
-e '^// Code generated by applyconfiguration-gen. DO NOT EDIT.$' \
':(glob)**/*.go' \
| xargs -0 rm -f
popd >/dev/null
fi
fi
echo "Generating apply configuration for ${GROUPS_WITH_VERSIONS} at ${APPLY_CONFIGURATION_PACKAGE}"
"${gobin}/applyconfiguration-gen" \
--input-dirs "$(codegen::join , "${EXT_FQ_APIS[@]}")" \
--output-package "${APPLY_CONFIGURATION_PACKAGE}" \
"$@"
fi
if grep -qw "client" <<<"${GENS}"; then
if [ ! "$verify_only" ]; then
# Nuke existing files
root="$(GO111MODULE=on go list -f '{{.Dir}}' "${OUTPUT_PKG}/${CLIENTSET_PKG}/${CLIENTSET_NAME}" 2>/dev/null || true)"
if [ -n "${root}" ]; then
pushd "${root}" >/dev/null
git_grep -l --null \
-e '^// Code generated by client-gen. DO NOT EDIT.$' \
':(glob)**/*.go' \
| xargs -0 rm -f
popd >/dev/null
fi
fi
echo "Generating clientset for ${GROUPS_WITH_VERSIONS} at ${OUTPUT_PKG}/${CLIENTSET_PKG}"
"${gobin}/client-gen" \
--clientset-name "${CLIENTSET_NAME}" \
--input-base "" \
--input "$(codegen::join , "${EXT_FQ_APIS[@]}")" \
--output-package "${OUTPUT_PKG}/${CLIENTSET_PKG}" \
--apply-configuration-package "${APPLY_CONFIGURATION_PACKAGE:-}" \
"$@"
fi
if grep -qw "lister" <<<"${GENS}"; then
if [ ! "$verify_only" ]; then
# Nuke existing files
for gv in "${GROUP_VERSIONS[@]}"; do
root="$(GO111MODULE=on go list -f '{{.Dir}}' "${OUTPUT_PKG}/listers/${gv}" 2>/dev/null || true)"
if [ -n "${root}" ]; then
pushd "${root}" >/dev/null
git_grep -l --null \
-e '^// Code generated by lister-gen. DO NOT EDIT.$' \
':(glob)**/*.go' \
| xargs -0 rm -f
popd >/dev/null
fi
done
fi
echo "Generating listers for ${GROUPS_WITH_VERSIONS} at ${OUTPUT_PKG}/listers"
"${gobin}/lister-gen" \
--input-dirs "$(codegen::join , "${EXT_FQ_APIS[@]}")" \
--output-package "${OUTPUT_PKG}/listers" \
"$@"
fi
if grep -qw "informer" <<<"${GENS}"; then
if [ ! "$verify_only" ]; then
# Nuke existing files
root="$(GO111MODULE=on go list -f '{{.Dir}}' "${OUTPUT_PKG}/informers/externalversions" 2>/dev/null || true)"
if [ -n "${root}" ]; then
pushd "${root}" >/dev/null
git_grep -l --null \
-e '^// Code generated by informer-gen. DO NOT EDIT.$' \
':(glob)**/*.go' \
| xargs -0 rm -f
popd >/dev/null
fi
fi
echo "Generating informers for ${GROUPS_WITH_VERSIONS} at ${OUTPUT_PKG}/informers"
"${gobin}/informer-gen" \
--input-dirs "$(codegen::join , "${EXT_FQ_APIS[@]}")" \
--versioned-clientset-package "${OUTPUT_PKG}/${CLIENTSET_PKG}/${CLIENTSET_NAME}" \
--listers-package "${OUTPUT_PKG}/listers" \
--output-package "${OUTPUT_PKG}/informers" \
"$@"
fi
if grep -qw "openapi" <<<"${GENS}"; then
if [ ! "$verify_only" ]; then
# Nuke existing files
for dir in $(GO111MODULE=on go list -f '{{.Dir}}' "${FQ_APIS[@]}"); do
pushd "${dir}" >/dev/null
git_find -z ':(glob)**'/zz_generated.openapi.go | xargs -0 rm -f
popd >/dev/null
done
fi
echo "Generating OpenAPI definitions for ${GROUPS_WITH_VERSIONS} at ${OUTPUT_PKG}/openapi"
declare -a OPENAPI_EXTRA_PACKAGES
"${gobin}/openapi-gen" \
--input-dirs "$(codegen::join , "${EXT_FQ_APIS[@]}" "${OPENAPI_EXTRA_PACKAGES[@]+"${OPENAPI_EXTRA_PACKAGES[@]}"}")" \
--input-dirs "k8s.io/apimachinery/pkg/apis/meta/v1,k8s.io/apimachinery/pkg/runtime,k8s.io/apimachinery/pkg/version" \
--output-package "${OUTPUT_PKG}/openapi" \
-O zz_generated.openapi \
"$@"
fi
exit 1

View File

@@ -45,15 +45,15 @@ function kube::codegen::internal::grep() {
# Generate tagged helper code: conversions, deepcopy, and defaults
#
# Args:
# --input-pkg-root <string>
# The root package under which to search for files which request code to be
# generated. This must be Go package syntax, e.g. "k8s.io/foo/bar".
# See note at the top about package structure below that.
# USAGE: kube::codegen::gen_helpers [FLAGS] <input-dir>
#
# --output-base <string>
# The root directory under which to emit code. The concatenation of
# <output-base> + <input-pkg-root> must be valid.
# <input-dir>
# The root directory under which to search for Go files which request code to
# be generated. This must be a local path, not a Go package.
#
# See note at the top about package structure below that.
#
# FLAGS:
#
# --boilerplate <string = path_to_kube_codegen_boilerplate>
# An optional override for the header file to insert into generated files.
@@ -63,22 +63,13 @@ function kube::codegen::internal::grep() {
# directories to consider during conversion generation.
#
function kube::codegen::gen_helpers() {
local in_pkg_root=""
local out_base="" # gengo needs the output dir must be $out_base/$out_pkg_root
local in_dir=""
local boilerplate="${KUBE_CODEGEN_ROOT}/hack/boilerplate.go.txt"
local v="${KUBE_VERBOSE:-0}"
local extra_peers=()
while [ "$#" -gt 0 ]; do
case "$1" in
"--input-pkg-root")
in_pkg_root="$2"
shift 2
;;
"--output-base")
out_base="$2"
shift 2
;;
"--boilerplate")
boilerplate="$2"
shift 2
@@ -88,18 +79,22 @@ function kube::codegen::gen_helpers() {
shift 2
;;
*)
echo "unknown argument: $1" >&2
return 1
if [[ "$1" =~ ^-- ]]; then
echo "unknown argument: $1" >&2
return 1
fi
if [ -n "$in_dir" ]; then
echo "too many arguments: $1 (already have $in_dir)" >&2
return 1
fi
in_dir="$1"
shift
;;
esac
done
if [ -z "${in_pkg_root}" ]; then
echo "--input-pkg-root is required" >&2
return 1
fi
if [ -z "${out_base}" ]; then
echo "--output-base is required" >&2
if [ -z "${in_dir}" ]; then
echo "input-dir argument is required" >&2
return 1
fi
@@ -118,11 +113,6 @@ function kube::codegen::gen_helpers() {
# Go installs in $GOBIN if defined, and $GOPATH/bin otherwise
gobin="${GOBIN:-$(go env GOPATH)/bin}"
# These tools all assume out-dir == in-dir.
root="${out_base}/${in_pkg_root}"
mkdir -p "${root}"
root="$(cd "${root}" && pwd -P)"
# Deepcopy
#
local input_pkgs=()
@@ -132,7 +122,7 @@ function kube::codegen::gen_helpers() {
done < <(
( kube::codegen::internal::grep -l --null \
-e '+k8s:deepcopy-gen=' \
-r "${root}" \
-r "${in_dir}" \
--include '*.go' \
|| true \
) | while read -r -d $'\0' F; do dirname "${F}"; done \
@@ -143,21 +133,16 @@ function kube::codegen::gen_helpers() {
echo "Generating deepcopy code for ${#input_pkgs[@]} targets"
kube::codegen::internal::findz \
"${root}" \
"${in_dir}" \
-type f \
-name zz_generated.deepcopy.go \
| xargs -0 rm -f
local input_args=()
for arg in "${input_pkgs[@]}"; do
input_args+=("--input-dirs" "$arg")
done
"${gobin}/deepcopy-gen" \
-v "${v}" \
--output-file-base zz_generated.deepcopy \
--output-file zz_generated.deepcopy.go \
--go-header-file "${boilerplate}" \
--output-base "${out_base}" \
"${input_args[@]}"
"${input_pkgs[@]}"
fi
# Defaults
@@ -169,7 +154,7 @@ function kube::codegen::gen_helpers() {
done < <(
( kube::codegen::internal::grep -l --null \
-e '+k8s:defaulter-gen=' \
-r "${root}" \
-r "${in_dir}" \
--include '*.go' \
|| true \
) | while read -r -d $'\0' F; do dirname "${F}"; done \
@@ -180,21 +165,16 @@ function kube::codegen::gen_helpers() {
echo "Generating defaulter code for ${#input_pkgs[@]} targets"
kube::codegen::internal::findz \
"${root}" \
"${in_dir}" \
-type f \
-name zz_generated.defaults.go \
| xargs -0 rm -f
local input_args=()
for arg in "${input_pkgs[@]}"; do
input_args+=("--input-dirs" "$arg")
done
"${gobin}/defaulter-gen" \
-v "${v}" \
--output-file-base zz_generated.defaults \
--output-file zz_generated.defaults.go \
--go-header-file "${boilerplate}" \
--output-base "${out_base}" \
"${input_args[@]}"
"${input_pkgs[@]}"
fi
# Conversions
@@ -206,7 +186,7 @@ function kube::codegen::gen_helpers() {
done < <(
( kube::codegen::internal::grep -l --null \
-e '+k8s:conversion-gen=' \
-r "${root}" \
-r "${in_dir}" \
--include '*.go' \
|| true \
) | while read -r -d $'\0' F; do dirname "${F}"; done \
@@ -217,47 +197,41 @@ function kube::codegen::gen_helpers() {
echo "Generating conversion code for ${#input_pkgs[@]} targets"
kube::codegen::internal::findz \
"${root}" \
"${in_dir}" \
-type f \
-name zz_generated.conversion.go \
| xargs -0 rm -f
local input_args=()
for arg in "${input_pkgs[@]}"; do
input_args+=("--input-dirs" "$arg")
done
local extra_peer_args=()
for arg in "${extra_peers[@]:+"${extra_peers[@]}"}"; do
extra_peer_args+=("--extra-peer-dirs" "$arg")
done
"${gobin}/conversion-gen" \
-v "${v}" \
--output-file-base zz_generated.conversion \
--output-file zz_generated.conversion.go \
--go-header-file "${boilerplate}" \
--output-base "${out_base}" \
"${extra_peer_args[@]:+"${extra_peer_args[@]}"}" \
"${input_args[@]}"
"${input_pkgs[@]}"
fi
}
# Generate openapi code
#
# Args:
# --input-pkg-root <string>
# The root package under which to search for files which request openapi to
# be generated. This must be Go package syntax, e.g. "k8s.io/foo/bar".
# See note at the top about package structure below that.
# USAGE: kube::codegen::gen_openapi [FLAGS] <input-dir>
#
# --output-pkg-root <string>
# The root package under which generated directories and files
# will be placed. This must be go package syntax, e.g. "k8s.io/foo/bar".
# <input-dir>
# The root directory under which to search for Go files which request openapi
# to be generated. This must be a local path, not a Go package.
#
# --output-base <string>
# The root directory under which to emit code. The concatenation of
# <output-base> + <input-pkg-root> must be valid.
# See note at the top about package structure below that.
#
# --openapi-name <string = "openapi">
# An optional override for the leaf name of the generated directory.
# FLAGS:
#
# --output-dir <string>
# The directory into which to emit code.
#
# --output-pkg <string>
# The Go package path (import path) of the --output-dir.
#
# --extra-pkgs <string>
# An optional list of additional packages to be imported during openapi
@@ -276,10 +250,9 @@ function kube::codegen::gen_helpers() {
# An optional override for the header file to insert into generated files.
#
function kube::codegen::gen_openapi() {
local in_pkg_root=""
local out_pkg_root=""
local out_base="" # gengo needs the output dir must be $out_base/$out_pkg_root
local openapi_subdir="openapi"
local in_dir=""
local out_dir=""
local out_pkg=""
local extra_pkgs=()
local report="/dev/null"
local update_report=""
@@ -288,20 +261,12 @@ function kube::codegen::gen_openapi() {
while [ "$#" -gt 0 ]; do
case "$1" in
"--input-pkg-root")
in_pkg_root="$2"
"--output-dir")
out_dir="$2"
shift 2
;;
"--output-pkg-root")
out_pkg_root="$2"
shift 2
;;
"--output-base")
out_base="$2"
shift 2
;;
"--openapi-name")
openapi_subdir="$2"
"--output-pkg")
out_pkg="$2"
shift 2
;;
"--extra-pkgs")
@@ -321,22 +286,30 @@ function kube::codegen::gen_openapi() {
shift 2
;;
*)
echo "unknown argument: $1" >&2
return 1
if [[ "$1" =~ ^-- ]]; then
echo "unknown argument: $1" >&2
return 1
fi
if [ -n "$in_dir" ]; then
echo "too many arguments: $1 (already have $in_dir)" >&2
return 1
fi
in_dir="$1"
shift
;;
esac
done
if [ -z "${in_pkg_root}" ]; then
echo "--input-pkg-root is required" >&2
if [ -z "${in_dir}" ]; then
echo "input-dir argument is required" >&2
return 1
fi
if [ -z "${out_pkg_root}" ]; then
echo "--output-pkg-root is required" >&2
if [ -z "${out_dir}" ]; then
echo "--output-dir is required" >&2
return 1
fi
if [ -z "${out_base}" ]; then
echo "--output-base is required" >&2
if [ -z "${out_pkg}" ]; then
echo "--output-pkg is required" >&2
return 1
fi
@@ -354,16 +327,11 @@ function kube::codegen::gen_openapi() {
openapi-gen
)
# shellcheck disable=2046 # printf word-splitting is intentional
GO111MODULE=on go install $(printf "k8s.io/code-generator/cmd/%s " "${BINS[@]}")
GO111MODULE=on go install $(printf "k8s.io/kube-openapi/cmd/%s " "${BINS[@]}")
)
# Go installs in $GOBIN if defined, and $GOPATH/bin otherwise
gobin="${GOBIN:-$(go env GOPATH)/bin}"
# These tools all assume out-dir == in-dir.
root="${out_base}/${in_pkg_root}"
mkdir -p "${root}"
root="$(cd "${root}" && pwd -P)"
local input_pkgs=( "${extra_pkgs[@]:+"${extra_pkgs[@]}"}")
while read -r dir; do
pkg="$(cd "${dir}" && GO111MODULE=on go list -find .)"
@@ -371,7 +339,7 @@ function kube::codegen::gen_openapi() {
done < <(
( kube::codegen::internal::grep -l --null \
-e '+k8s:openapi-gen=' \
-r "${root}" \
-r "${in_dir}" \
--include '*.go' \
|| true \
) | while read -r -d $'\0' F; do dirname "${F}"; done \
@@ -382,26 +350,22 @@ function kube::codegen::gen_openapi() {
echo "Generating openapi code for ${#input_pkgs[@]} targets"
kube::codegen::internal::findz \
"${root}" \
"${in_dir}" \
-type f \
-name zz_generated.openapi.go \
| xargs -0 rm -f
local inputs=()
for arg in "${input_pkgs[@]}"; do
inputs+=("--input-dirs" "$arg")
done
"${gobin}/openapi-gen" \
-v "${v}" \
--output-file-base zz_generated.openapi \
--output-file zz_generated.openapi.go \
--go-header-file "${boilerplate}" \
--output-base "${out_base}" \
--output-package "${out_pkg_root}/${openapi_subdir}" \
--output-dir "${out_dir}" \
--output-pkg "${out_pkg}" \
--report-filename "${new_report}" \
--input-dirs "k8s.io/apimachinery/pkg/apis/meta/v1" \
--input-dirs "k8s.io/apimachinery/pkg/runtime" \
--input-dirs "k8s.io/apimachinery/pkg/version" \
"${inputs[@]}"
"k8s.io/apimachinery/pkg/apis/meta/v1" \
"k8s.io/apimachinery/pkg/runtime" \
"k8s.io/apimachinery/pkg/version" \
"${input_pkgs[@]}"
fi
touch "${report}" # in case it doesn't exist yet
@@ -415,25 +379,27 @@ function kube::codegen::gen_openapi() {
# Generate client code
#
# Args:
# --input-pkg-root <string>
# The root package under which to search for *.go files which request
# clients to be generated. This must be Go package syntax, e.g.
# "k8s.io/foo/bar".
# See note at the top about package structure below that.
# USAGE: kube::codegen::gen_client [FLAGS] <input-dir>
#
# <input-dir>
# The root package under which to search for Go files which request clients
# to be generated. This must be a local path, not a Go package.
#
# See note at the top about package structure below that.
#
# FLAGS:
# --one-input-api <string>
# A specific API (a directory) under the --input-pkg-root for which to
# generate a client. If this is not set, clients for all APIs under the
# input root will be generated (under the --output-pkg-root).
# A specific API (a directory) under the input-dir for which to generate a
# client. If this is not set, clients for all APIs under the input-dir
# will be generated (under the --output-pkg).
#
# --output-pkg-root <string>
# The root package into which generated directories and files will be
# placed. This must be Go package syntax, e.g. "k8s.io/foo/bar".
# --output-dir <string>
# The root directory under which to emit code. Each aspect of client
# generation will make one or more subdirectories.
#
# --output-base <string>
# The root directory under which to emit code. The concatenation of
# <output-base> + <output-pkg-root> must be valid.
# --output-pkg <string>
# The Go package path (import path) of the --output-dir. Each aspect of
# client generation will make one or more sub-packages.
#
# --boilerplate <string = path_to_kube_codegen_boilerplate>
# An optional override for the header file to insert into generated files.
@@ -468,10 +434,10 @@ function kube::codegen::gen_openapi() {
# An optional list of comma separated plural exception definitions in Type:PluralizedType form.
#
function kube::codegen::gen_client() {
local in_pkg_root=""
local in_dir=""
local one_input_api=""
local out_pkg_root=""
local out_base="" # gengo needs the output dir must be $out_base/$out_pkg_root
local out_dir=""
local out_pkg=""
local clientset_subdir="clientset"
local clientset_versioned_name="versioned"
local applyconfig="false"
@@ -486,20 +452,16 @@ function kube::codegen::gen_client() {
while [ "$#" -gt 0 ]; do
case "$1" in
"--input-pkg-root")
in_pkg_root="$2"
shift 2
;;
"--one-input-api")
one_input_api="/$2"
shift 2
;;
"--output-pkg-root")
out_pkg_root="$2"
"--output-dir")
out_dir="$2"
shift 2
;;
"--output-base")
out_base="$2"
"--output-pkg")
out_pkg="$2"
shift 2
;;
"--boilerplate")
@@ -543,25 +505,34 @@ function kube::codegen::gen_client() {
shift 2
;;
*)
echo "unknown argument: $1" >&2
return 1
if [[ "$1" =~ ^-- ]]; then
echo "unknown argument: $1" >&2
return 1
fi
if [ -n "$in_dir" ]; then
echo "too many arguments: $1 (already have $in_dir)" >&2
return 1
fi
in_dir="$1"
shift
;;
esac
done
if [ -z "${in_pkg_root}" ]; then
echo "--input-pkg-root is required" >&2
if [ -z "${in_dir}" ]; then
echo "input-dir argument is required" >&2
return 1
fi
if [ -z "${out_pkg_root}" ]; then
echo "--output-pkg-root is required" >&2
if [ -z "${out_dir}" ]; then
echo "--output-dir is required" >&2
return 1
fi
if [ -z "${out_base}" ]; then
echo "--output-base is required" >&2
return 1
if [ -z "${out_pkg}" ]; then
echo "--output-pkg is required" >&2
fi
mkdir -p "${out_dir}"
(
# To support running this from anywhere, first cd into this directory,
# and then install with forced module mode on and fully qualified name.
@@ -578,13 +549,6 @@ function kube::codegen::gen_client() {
# Go installs in $GOBIN if defined, and $GOPATH/bin otherwise
gobin="${GOBIN:-$(go env GOPATH)/bin}"
in_root="${out_base}/${in_pkg_root}"
mkdir -p "${in_root}"
in_root="$(cd "${in_root}" && pwd -P)"
out_root="${out_base}/${out_pkg_root}"
mkdir -p "${out_root}"
out_root="$(cd "${out_root}" && pwd -P)"
local group_versions=()
local input_pkgs=()
while read -r dir; do
@@ -600,7 +564,7 @@ function kube::codegen::gen_client() {
done < <(
( kube::codegen::internal::grep -l --null \
-e '+genclient' \
-r "${in_root}${one_input_api}" \
-r "${in_dir}${one_input_api}" \
--include '*.go' \
|| true \
) | while read -r -d $'\0' F; do dirname "${F}"; done \
@@ -613,35 +577,31 @@ function kube::codegen::gen_client() {
applyconfig_pkg="" # set this for later use, iff enabled
if [ "${applyconfig}" == "true" ]; then
applyconfig_pkg="${out_pkg_root}/${applyconfig_subdir}"
applyconfig_pkg="${out_pkg}/${applyconfig_subdir}"
echo "Generating applyconfig code for ${#input_pkgs[@]} targets"
( kube::codegen::internal::grep -l --null \
-e '^// Code generated by applyconfiguration-gen. DO NOT EDIT.$' \
-r "${out_root}/${applyconfig_subdir}" \
-r "${out_dir}/${applyconfig_subdir}" \
--include '*.go' \
|| true \
) | xargs -0 rm -f
local inputs=()
for arg in "${input_pkgs[@]}"; do
inputs+=("--input-dirs" "$arg")
done
"${gobin}/applyconfiguration-gen" \
-v "${v}" \
--go-header-file "${boilerplate}" \
--output-base "${out_base}" \
--output-package "${out_pkg_root}/${applyconfig_subdir}" \
--output-dir "${out_dir}/${applyconfig_subdir}" \
--output-pkg "${applyconfig_pkg}" \
--external-applyconfigurations "${applyconfig_external}" \
"${inputs[@]}"
"${input_pkgs[@]}"
fi
echo "Generating client code for ${#group_versions[@]} targets"
( kube::codegen::internal::grep -l --null \
-e '^// Code generated by client-gen. DO NOT EDIT.$' \
-r "${out_root}/${clientset_subdir}" \
-r "${out_dir}/${clientset_subdir}" \
--include '*.go' \
|| true \
) | xargs -0 rm -f
@@ -650,14 +610,14 @@ function kube::codegen::gen_client() {
for arg in "${group_versions[@]}"; do
inputs+=("--input" "$arg")
done
"${gobin}/client-gen" \
"${gobin}/client-gen" \
-v "${v}" \
--go-header-file "${boilerplate}" \
--output-dir "${out_dir}/${clientset_subdir}" \
--output-pkg "${out_pkg}/${clientset_subdir}" \
--clientset-name "${clientset_versioned_name}" \
--input-base "${in_pkg_root}" \
--output-base "${out_base}" \
--output-package "${out_pkg_root}/${clientset_subdir}" \
--apply-configuration-package "${applyconfig_pkg}" \
--input-base "$(cd "${in_dir}" && pwd -P)" `# must be absolute path or Go import path"` \
--plural-exceptions "${plural_exceptions}" \
"${inputs[@]}"
@@ -666,44 +626,36 @@ function kube::codegen::gen_client() {
( kube::codegen::internal::grep -l --null \
-e '^// Code generated by lister-gen. DO NOT EDIT.$' \
-r "${out_root}/${listers_subdir}" \
-r "${out_dir}/${listers_subdir}" \
--include '*.go' \
|| true \
) | xargs -0 rm -f
local inputs=()
for arg in "${input_pkgs[@]}"; do
inputs+=("--input-dirs" "$arg")
done
"${gobin}/lister-gen" \
-v "${v}" \
--go-header-file "${boilerplate}" \
--output-base "${out_base}" \
--output-package "${out_pkg_root}/${listers_subdir}" \
--output-dir "${out_dir}/${listers_subdir}" \
--output-pkg "${out_pkg}/${listers_subdir}" \
--plural-exceptions "${plural_exceptions}" \
"${inputs[@]}"
"${input_pkgs[@]}"
echo "Generating informer code for ${#input_pkgs[@]} targets"
( kube::codegen::internal::grep -l --null \
-e '^// Code generated by informer-gen. DO NOT EDIT.$' \
-r "${out_root}/${informers_subdir}" \
-r "${out_dir}/${informers_subdir}" \
--include '*.go' \
|| true \
) | xargs -0 rm -f
local inputs=()
for arg in "${input_pkgs[@]}"; do
inputs+=("--input-dirs" "$arg")
done
"${gobin}/informer-gen" \
-v "${v}" \
--go-header-file "${boilerplate}" \
--output-base "${out_base}" \
--output-package "${out_pkg_root}/${informers_subdir}" \
--versioned-clientset-package "${out_pkg_root}/${clientset_subdir}/${clientset_versioned_name}" \
--listers-package "${out_pkg_root}/${listers_subdir}" \
--output-dir "${out_dir}/${informers_subdir}" \
--output-pkg "${out_pkg}/${informers_subdir}" \
--versioned-clientset-package "${out_pkg}/${clientset_subdir}/${clientset_versioned_name}" \
--listers-package "${out_pkg}/${listers_subdir}" \
--plural-exceptions "${plural_exceptions}" \
"${inputs[@]}"
"${input_pkgs[@]}"
fi
}

View File

@@ -17,8 +17,9 @@ limitations under the License.
package namer
import (
"k8s.io/gengo/namer"
"k8s.io/gengo/types"
"k8s.io/gengo/v2"
"k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types"
)
// TagOverrideNamer is a namer which pulls names from a given tag, if specified,
@@ -49,7 +50,7 @@ func NewTagOverrideNamer(tagName string, fallback namer.Namer) namer.Namer {
// 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 {
val, present := types.ExtractCommentTags("+", lines)[key]
val, present := gengo.ExtractCommentTags("+", lines)[key]
if !present || len(val) < 1 {
return ""
}

View File

@@ -1,60 +0,0 @@
/*
Copyright 2017 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 (
gobuild "go/build"
"path/filepath"
"strings"
)
// CurrentPackage returns the go package of the current directory, or "" if it cannot
// be derived from the GOPATH.
func CurrentPackage() string {
for _, root := range gobuild.Default.SrcDirs() {
if pkg, ok := hasSubdir(root, "."); ok {
return pkg
}
}
return ""
}
func hasSubdir(root, dir string) (rel string, ok bool) {
// ensure a tailing separator to properly compare on word-boundaries
const sep = string(filepath.Separator)
root = filepath.Clean(root)
if !strings.HasSuffix(root, sep) {
root += sep
}
// check whether root dir starts with root
dir = filepath.Clean(dir)
if !strings.HasPrefix(dir, root) {
return "", false
}
// cut off root
return filepath.ToSlash(dir[len(root):]), true
}
// Vendorless trims vendor prefix from a package path to make it canonical
func Vendorless(p string) string {
if pos := strings.LastIndex(p, "/vendor/"); pos != -1 {
return p[pos+len("/vendor/"):]
}
return p
}

View File

@@ -28,10 +28,7 @@ import (
_ "k8s.io/code-generator/cmd/deepcopy-gen"
_ "k8s.io/code-generator/cmd/defaulter-gen"
_ "k8s.io/code-generator/cmd/go-to-protobuf"
_ "k8s.io/code-generator/cmd/import-boss"
_ "k8s.io/code-generator/cmd/informer-gen"
_ "k8s.io/code-generator/cmd/lister-gen"
_ "k8s.io/code-generator/cmd/openapi-gen"
_ "k8s.io/code-generator/cmd/register-gen"
_ "k8s.io/code-generator/cmd/set-gen"
)