Fix conversion-gen wrt gengo/v2

This commit is contained in:
Tim Hockin 2023-12-24 09:54:56 -08:00
parent 1e96f4e50a
commit ed35118664
No known key found for this signature in database

View File

@ -136,7 +136,7 @@ func getManualConversionFunctions(context *generator.Context, pkg *types.Package
klog.Warning("Skipping nil package passed to getManualConversionFunctions") klog.Warning("Skipping nil package passed to getManualConversionFunctions")
return return
} }
klog.V(5).Infof("Scanning for conversion functions in %v", pkg.Name) klog.V(5).Infof("Scanning for conversion functions in %v", pkg.Path)
scopeName := types.Ref(conversionPackagePath, "Scope").Name scopeName := types.Ref(conversionPackagePath, "Scope").Name
errorName := types.Ref("", "error").Name errorName := types.Ref("", "error").Name
@ -219,58 +219,45 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
// have non-trivial conversion // have non-trivial conversion
memoryEquivalentTypes := equalMemoryTypes{} memoryEquivalentTypes := equalMemoryTypes{}
// We are generating conversions only for packages that are explicitly // First load other "input" packages. We do this as a single call because
// passed as InputDir. // it is MUCH faster.
processed := map[string]bool{} 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 { for _, i := range context.Inputs {
// skip duplicates klog.V(5).Infof("pre-processing pkg %q", i)
if processed[i] {
continue
}
processed[i] = true
klog.V(5).Infof("considering pkg %q", i)
pkg := context.Universe[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 pkg == nil {
// If the input had no Go files, for example. // If the input had no Go files, for example.
continue continue
} }
// Add conversion and defaulting functions.
getManualConversionFunctions(context, pkg, manualConversions)
// Only generate conversions for packages which explicitly request it // Only generate conversions for packages which explicitly request it
// by specifying one or more "+k8s:conversion-gen=<peer-pkg>" // by specifying one or more "+k8s:conversion-gen=<peer-pkg>"
// in their doc.go file. // in their doc.go file.
peerPkgs := extractTag(pkg.Comments) peerPkgs := extractTag(pkg.Comments)
if peerPkgs != nil { 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") klog.V(5).Infof(" no tag")
continue continue
} }
skipUnsafe := false klog.V(5).Infof(" tags: %q", peerPkgs)
extraDirs := []string{} if len(peerPkgs) == 1 && peerPkgs[0] == "false" {
if customArgs, ok := arguments.CustomArgs.(*conversionargs.CustomArgs); ok { // If a single +k8s:conversion-gen=false tag is defined, we still want
if len(peerPkgs) > 0 { // the generator to fire for this package for explicit conversions, but
peerPkgs = append(peerPkgs, customArgs.BasePeerDirs...) // we are clearing the peerPkgs to not generate any standard conversions.
peerPkgs = append(peerPkgs, customArgs.ExtraPeerDirs...) peerPkgs = nil
} } else {
extraDirs = customArgs.ExtraDirs // Save peers for each input
skipUnsafe = customArgs.SkipUnsafe 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) externalTypesValues := extractExternalTypesTag(pkg.Comments)
if externalTypesValues != nil { if externalTypesValues != nil {
if len(externalTypesValues) != 1 { if len(externalTypesValues) != 1 {
@ -278,39 +265,76 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
} }
externalTypes := externalTypesValues[0] externalTypes := externalTypesValues[0]
klog.V(5).Infof(" external types tags: %q", externalTypes) klog.V(5).Infof(" external types tags: %q", externalTypes)
var err error otherPkgs = append(otherPkgs, externalTypes)
typesPkg, err = context.AddDirectory(externalTypes) pkgToExternal[i] = externalTypes
if err != nil { } else {
klog.Fatalf("cannot import package %s", externalTypes) pkgToExternal[i] = i
}
// update context.Order to the latest context.Universe
orderer := namer.Orderer{Namer: namer.NewPublicNamer(1)}
context.Order = orderer.OrderUniverse(context.Universe)
} }
}
// if the source path is within a /vendor/ directory (for example, // Make sure explicit peer-packages are added.
// k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/apis/meta/v1), allow var sanitizedPeerPkgs []string
// generation to output to the proper relative path (under vendor). if customArgs, ok := arguments.CustomArgs.(*conversionargs.CustomArgs); ok {
// Otherwise, the generator will create the file in the wrong location all := append(customArgs.BasePeerDirs, customArgs.ExtraPeerDirs...)
// in the output directory. for _, pkg := range all {
// TODO: build a more fundamental concept in gengo for dealing with modifications // if the source path is within a /vendor/ directory (for example,
// to vendored packages. // k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/apis/meta/v1), allow
for i := range peerPkgs { // generation to output to the proper relative path (under vendor).
peerPkgs[i] = genutil.Vendorless(peerPkgs[i]) // Otherwise, the generator will create the file in the wrong location
// in the output directory.
pkg = genutil.Vendorless(pkg)
sanitizedPeerPkgs = append(sanitizedPeerPkgs, pkg)
} }
for i := range extraDirs { if expanded, err := context.FindPackages(sanitizedPeerPkgs...); err != nil {
extraDirs[i] = genutil.Vendorless(extraDirs[i]) klog.Fatalf("cannot find peer packages: %v", err)
} } else {
otherPkgs = append(otherPkgs, expanded...)
// Make sure our peer-packages are added and fully parsed. // for each pkg, add these extras, too
for _, pp := range append(peerPkgs, extraDirs...) { for k := range pkgToPeers {
context.AddDir(pp) pkgToPeers[k] = append(pkgToPeers[k], expanded...)
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)
}
skipUnsafe := false
if customArgs, ok := arguments.CustomArgs.(*conversionargs.CustomArgs); ok {
skipUnsafe = customArgs.SkipUnsafe
}
// We are generating conversions only for packages that are explicitly
// passed as InputDir.
for _, i := range filteredInputs {
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
// 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) unsafeEquality := TypesEqual(memoryEquivalentTypes)
if skipUnsafe { if skipUnsafe {
@ -335,10 +359,11 @@ func Packages(context *generator.Context, arguments *args.GeneratorArgs) generat
&generator.DefaultPackage{ &generator.DefaultPackage{
PackageName: filepath.Base(pkg.Path), PackageName: filepath.Base(pkg.Path),
PackagePath: path, PackagePath: path,
Source: pkg.SourcePath, // output pkg is the same as the input
HeaderText: header, HeaderText: header,
GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) {
return []generator.Generator{ return []generator.Generator{
NewGenConversion(arguments.OutputFileBaseName, typesPkg.Path, pkg.Path, manualConversions, peerPkgs, unsafeEquality), NewGenConversion(arguments.OutputFileBaseName, typesPkg.Path, pkg.Path, manualConversions, pkgToPeers[path], unsafeEquality),
} }
}, },
FilterFunc: func(c *generator.Context, t *types.Type) bool { FilterFunc: func(c *generator.Context, t *types.Type) bool {