@@ -19,10 +19,8 @@ package applyconfigurations
1919import (
2020 "fmt"
2121 "go/ast"
22- "go/types"
2322 "os"
2423 "path/filepath"
25- "strings"
2624
2725 "k8s.io/apimachinery/pkg/util/sets"
2826 generatorargs "k8s.io/code-generator/cmd/applyconfiguration-gen/args"
@@ -39,14 +37,10 @@ import (
3937var (
4038 isCRDMarker = markers .Must (markers .MakeDefinition ("kubebuilder:resource" , markers .DescribesType , crdmarkers.Resource {}))
4139 enablePkgMarker = markers .Must (markers .MakeDefinition ("kubebuilder:ac:generate" , markers .DescribesPackage , false ))
40+ outputPkgMarker = markers .Must (markers .MakeDefinition ("kubebuilder:ac:output:package" , markers .DescribesPackage , "" ))
4241 enableTypeMarker = markers .Must (markers .MakeDefinition ("kubebuilder:ac:generate" , markers .DescribesType , false ))
4342)
4443
45- var importMapping = map [string ]string {
46- "k8s.io/apimachinery/pkg/apis/" : "k8s.io/client-go/applyconfigurations/" ,
47- "k8s.io/api/" : "k8s.io/client-go/applyconfigurations/" ,
48- }
49-
5044const importPathSuffix = "applyconfiguration"
5145
5246// +controllertools:marker:generateHelp
@@ -67,17 +61,18 @@ func (Generator) CheckFilter() loader.NodeFilter {
6761
6862func (Generator ) RegisterMarkers (into * markers.Registry ) error {
6963 if err := markers .RegisterAll (into ,
70- isCRDMarker , enablePkgMarker , enableTypeMarker ); err != nil {
64+ isCRDMarker , enablePkgMarker , enableTypeMarker , outputPkgMarker ); err != nil {
7165 return err
7266 }
7367
7468 into .AddHelp (isCRDMarker ,
7569 markers .SimpleHelp ("apply" , "enables apply configuration generation for this type" ))
7670 into .AddHelp (
7771 enableTypeMarker , markers .SimpleHelp ("apply" , "overrides enabling or disabling applyconfigurations generation for the type" ))
78-
7972 into .AddHelp (
8073 enablePkgMarker , markers .SimpleHelp ("apply" , "overrides enabling or disabling applyconfigurations generation for the package" ))
74+ into .AddHelp (
75+ outputPkgMarker , markers .SimpleHelp ("apply" , "overrides the default output package for the applyconfigurations generation" ))
8176 return nil
8277
8378}
@@ -102,6 +97,18 @@ func enabledOnType(info *markers.TypeInfo) bool {
10297 return isCRD (info )
10398}
10499
100+ func outputPkg (col * markers.Collector , pkg * loader.Package ) (string , error ) {
101+ pkgMarkers , err := markers .PackageMarkers (col , pkg )
102+ if err != nil {
103+ return "" , err
104+ }
105+ pkgMarker := pkgMarkers .Get (outputPkgMarker .Name )
106+ if pkgMarker != nil {
107+ return pkgMarker .(string ), nil
108+ }
109+ return "" , nil
110+ }
111+
105112// isCRD marks whether the type is a CRD based on the +kubebuilder:resource marker.
106113func isCRD (info * markers.TypeInfo ) bool {
107114 objectEnabled := info .Markers .Get (isCRDMarker .Name )
@@ -146,46 +153,6 @@ type ObjectGenCtx struct {
146153 HeaderFilePath string
147154}
148155
149- type Universe struct {
150- typeMetadata map [types.Type ]* typeMetadata
151- }
152-
153- type typeMetadata struct {
154- used bool
155- }
156-
157- func (u * Universe ) existingApplyConfigPath (_ * types.Named , pkgPath string ) (string , bool ) {
158- for prefix , replacePath := range importMapping {
159- if strings .HasPrefix (pkgPath , prefix ) {
160- path := replacePath + strings .TrimPrefix (pkgPath , prefix )
161- return path , true
162- }
163- }
164- return "" , false
165- }
166-
167- func (u * Universe ) IsApplyConfigGenerated (typeInfo * types.Named ) bool {
168- if t , ok := u .typeMetadata [typeInfo ]; ok {
169- return t .used
170- }
171- return false
172- }
173-
174- func (u * Universe ) GetApplyConfigPath (typeInfo * types.Named , pkgPath string ) (string , bool ) {
175- isApplyConfigGenerated := u .IsApplyConfigGenerated (typeInfo )
176- if path , ok := u .existingApplyConfigPath (typeInfo , pkgPath ); ok {
177- if isApplyConfigGenerated {
178- return path , true
179- }
180- return pkgPath , false
181- }
182- // ApplyConfig is necessary but location is not explicitly specified. Assume the ApplyConfig exists at the below directory
183- if isApplyConfigGenerated {
184- return pkgPath + "/" + importPathSuffix , true
185- }
186- return pkgPath , false
187- }
188-
189156// generateForPackage generates apply configuration implementations for
190157// types in the given package, writing the formatted result to given writer.
191158// May return nil if source could not be generated.
@@ -194,12 +161,27 @@ func (ctx *ObjectGenCtx) generateForPackage(root *loader.Package) error {
194161 if ! enabled {
195162 return nil
196163 }
164+ if len (root .GoFiles ) == 0 {
165+ return nil
166+ }
197167
198168 genericArgs , _ := generatorargs .NewDefaults ()
199169 genericArgs .InputDirs = []string {root .PkgPath }
200- genericArgs .OutputPackagePath = filepath .Join (root .PkgPath , importPathSuffix )
201170 genericArgs .GoHeaderFilePath = ctx .HeaderFilePath
202171
172+ outpkg , _ := outputPkg (ctx .Collector , root )
173+ if outpkg == "" {
174+ outpkg = importPathSuffix
175+ }
176+ genericArgs .OutputPackagePath = filepath .Join (root .PkgPath , outpkg )
177+
178+ // attempts to retrieve the correct base directory to output apply configurations to by
179+ // looking into the package and retrieving the first go file it finds, and using that as the output base.
180+ // this is because we cannot rely on gogen calculating the correct output base.
181+ // if we leave this empty, gogen will attempt to use GOPATH to write the files which is not wanted
182+ genericArgs .OutputBase = filepath .Dir (root .GoFiles [0 ])
183+ trimPathPrefix := filepath .Join (genericArgs .OutputBase , root .PkgPath ) + "/"
184+
203185 // Make the generated header static so that it doesn't rely on the compiled binary name.
204186 genericArgs .GeneratedByCommentTemplate = "// Code generated by applyconfiguration-gen. DO NOT EDIT.\n "
205187
@@ -216,9 +198,9 @@ func (ctx *ObjectGenCtx) generateForPackage(root *loader.Package) error {
216198 if err != nil {
217199 return err
218200 }
219-
220- // This allows the correct output location when GOPATH is unset .
221- c .TrimPathPrefix = root . PkgPath + "/"
201+ // The output package path is fully qualified. It contains the OutputBase (which is the module directory)
202+ // that means we will have to trim the fully qualified pkg down again .
203+ c .TrimPathPrefix = trimPathPrefix
222204
223205 pkg , ok := c .Universe [root .PkgPath ]
224206 if ! ok {
0 commit comments