Skip to content

Commit

Permalink
chore: resolve applyconfig gen correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
jakobmoellerdev authored and JoelSpeed committed Sep 18, 2023
1 parent 49b2a52 commit 0aa6676
Show file tree
Hide file tree
Showing 14 changed files with 54 additions and 65 deletions.
13 changes: 10 additions & 3 deletions pkg/applyconfigurations/applyconfiguration_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"io"
"io/fs"
"os"
"path/filepath"
"strings"

. "github.com/onsi/ginkgo"
Expand Down Expand Up @@ -57,6 +58,13 @@ func (o *outputFile) Close() error {
}

var _ = Describe("CRD Generation From Parsing to CustomResourceDefinition", func() {
outputPath := "testapplyconfiguration"
masterPath := "applyconfiguration"
By("resetting the test directory")
// not using after each to allow for inspection of failed tests
BeforeEach(func() {
Expect(os.RemoveAll(filepath.Join(".", outputPath))).To(Succeed())
})
It("should be able to verify generated ApplyConfiguration types for the CronJob schema", func() {
By("switching into testdata to appease go modules")
cwd, err := os.Getwd()
Expand All @@ -79,6 +87,8 @@ var _ = Describe("CRD Generation From Parsing to CustomResourceDefinition", func
Expect(err).NotTo(HaveOccurred())
rt.OutputRules = genall.OutputRules{Default: output}

cronJobFS := os.DirFS(".")

By("running the generator and checking for errors")
hadErrs := rt.Run()

Expand All @@ -87,8 +97,6 @@ var _ = Describe("CRD Generation From Parsing to CustomResourceDefinition", func

filesInMaster := make(map[string][]byte)
masterFileNames := sets.New[string]()
cronJobFS := os.DirFS(".")
masterPath := "applyconfiguration-master"
Expect(fs.WalkDir(cronJobFS, masterPath, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
Expand All @@ -112,7 +120,6 @@ var _ = Describe("CRD Generation From Parsing to CustomResourceDefinition", func

filesInOutput := make(map[string][]byte)
outputFileNames := sets.New[string]()
outputPath := "applyconfiguration"
Expect(fs.WalkDir(cronJobFS, outputPath, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err
Expand Down
88 changes: 35 additions & 53 deletions pkg/applyconfigurations/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,8 @@ package applyconfigurations
import (
"fmt"
"go/ast"
"go/types"
"os"
"path/filepath"
"strings"

"k8s.io/apimachinery/pkg/util/sets"
generatorargs "k8s.io/code-generator/cmd/applyconfiguration-gen/args"
Expand All @@ -39,14 +37,10 @@ import (
var (
isCRDMarker = markers.Must(markers.MakeDefinition("kubebuilder:resource", markers.DescribesType, crdmarkers.Resource{}))
enablePkgMarker = markers.Must(markers.MakeDefinition("kubebuilder:ac:generate", markers.DescribesPackage, false))
outputPkgMarker = markers.Must(markers.MakeDefinition("kubebuilder:ac:output:package", markers.DescribesPackage, ""))
enableTypeMarker = markers.Must(markers.MakeDefinition("kubebuilder:ac:generate", markers.DescribesType, false))
)

var importMapping = map[string]string{
"k8s.io/apimachinery/pkg/apis/": "k8s.io/client-go/applyconfigurations/",
"k8s.io/api/": "k8s.io/client-go/applyconfigurations/",
}

const importPathSuffix = "applyconfiguration"

// +controllertools:marker:generateHelp
Expand All @@ -67,17 +61,18 @@ func (Generator) CheckFilter() loader.NodeFilter {

func (Generator) RegisterMarkers(into *markers.Registry) error {
if err := markers.RegisterAll(into,
isCRDMarker, enablePkgMarker, enableTypeMarker); err != nil {
isCRDMarker, enablePkgMarker, enableTypeMarker, outputPkgMarker); err != nil {
return err
}

into.AddHelp(isCRDMarker,
markers.SimpleHelp("apply", "enables apply configuration generation for this type"))
into.AddHelp(
enableTypeMarker, markers.SimpleHelp("apply", "overrides enabling or disabling applyconfigurations generation for the type"))

into.AddHelp(
enablePkgMarker, markers.SimpleHelp("apply", "overrides enabling or disabling applyconfigurations generation for the package"))
into.AddHelp(
outputPkgMarker, markers.SimpleHelp("apply", "overrides the default output package for the applyconfigurations generation"))
return nil

}
Expand All @@ -102,6 +97,18 @@ func enabledOnType(info *markers.TypeInfo) bool {
return isCRD(info)
}

func outputPkg(col *markers.Collector, pkg *loader.Package) (string, error) {
pkgMarkers, err := markers.PackageMarkers(col, pkg)
if err != nil {
return "", err
}
pkgMarker := pkgMarkers.Get(outputPkgMarker.Name)
if pkgMarker != nil {
return pkgMarker.(string), nil
}
return "", nil
}

// isCRD marks whether the type is a CRD based on the +kubebuilder:resource marker.
func isCRD(info *markers.TypeInfo) bool {
objectEnabled := info.Markers.Get(isCRDMarker.Name)
Expand Down Expand Up @@ -146,46 +153,6 @@ type ObjectGenCtx struct {
HeaderFilePath string
}

type Universe struct {
typeMetadata map[types.Type]*typeMetadata
}

type typeMetadata struct {
used bool
}

func (u *Universe) existingApplyConfigPath(_ *types.Named, pkgPath string) (string, bool) {
for prefix, replacePath := range importMapping {
if strings.HasPrefix(pkgPath, prefix) {
path := replacePath + strings.TrimPrefix(pkgPath, prefix)
return path, true
}
}
return "", false
}

func (u *Universe) IsApplyConfigGenerated(typeInfo *types.Named) bool {
if t, ok := u.typeMetadata[typeInfo]; ok {
return t.used
}
return false
}

func (u *Universe) GetApplyConfigPath(typeInfo *types.Named, pkgPath string) (string, bool) {
isApplyConfigGenerated := u.IsApplyConfigGenerated(typeInfo)
if path, ok := u.existingApplyConfigPath(typeInfo, pkgPath); ok {
if isApplyConfigGenerated {
return path, true
}
return pkgPath, false
}
// ApplyConfig is necessary but location is not explicitly specified. Assume the ApplyConfig exists at the below directory
if isApplyConfigGenerated {
return pkgPath + "/" + importPathSuffix, true
}
return pkgPath, false
}

// generateForPackage generates apply configuration implementations for
// types in the given package, writing the formatted result to given writer.
// May return nil if source could not be generated.
Expand All @@ -194,12 +161,27 @@ func (ctx *ObjectGenCtx) generateForPackage(root *loader.Package) error {
if !enabled {
return nil
}
if len(root.GoFiles) == 0 {
return nil
}

genericArgs, _ := generatorargs.NewDefaults()
genericArgs.InputDirs = []string{root.PkgPath}
genericArgs.OutputPackagePath = filepath.Join(root.PkgPath, importPathSuffix)
genericArgs.GoHeaderFilePath = ctx.HeaderFilePath

outpkg, _ := outputPkg(ctx.Collector, root)
if outpkg == "" {
outpkg = importPathSuffix
}
genericArgs.OutputPackagePath = filepath.Join(root.PkgPath, outpkg)

// attempts to retrieve the correct base directory to output apply configurations to by
// looking into the package and retrieving the first go file it finds, and using that as the output base.
// this is because we cannot rely on gogen calculating the correct output base.
// if we leave this empty, gogen will attempt to use GOPATH to write the files which is not wanted
genericArgs.OutputBase = filepath.Dir(root.GoFiles[0])
trimPathPrefix := filepath.Join(genericArgs.OutputBase, root.PkgPath) + "/"

// Make the generated header static so that it doesn't rely on the compiled binary name.
genericArgs.GeneratedByCommentTemplate = "// Code generated by applyconfiguration-gen. DO NOT EDIT.\n"

Expand All @@ -216,9 +198,9 @@ func (ctx *ObjectGenCtx) generateForPackage(root *loader.Package) error {
if err != nil {
return err
}

// This allows the correct output location when GOPATH is unset.
c.TrimPathPrefix = root.PkgPath + "/"
// The output package path is fully qualified. It contains the OutputBase (which is the module directory)
// that means we will have to trim the fully qualified pkg down again.
c.TrimPathPrefix = trimPathPrefix

pkg, ok := c.Universe[root.PkgPath]
if !ok {
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ limitations under the License.
// +groupName=testdata.kubebuilder.io
// +versionName=v1
// +kubebuilder:ac:generate=true
// +kubebuilder:ac:output:package="testapplyconfiguration"
package testdata

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 0 additions & 5 deletions pkg/applyconfigurations/zz_generated.markerhelp.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Empty file added pkg/oot_testsubdirectory
Empty file.
4 changes: 4 additions & 0 deletions pkg/webhook/zz_generated.markerhelp.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 0aa6676

Please sign in to comment.