knative.dev/pkg@v0.0.0-20260602142205-ac97e43f6622/codegen/cmd/injection-gen/generators/reconciler/targets.go (about) 1 /* 2 Copyright 2024 The Knative Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package reconciler 18 19 import ( 20 "path/filepath" 21 "strings" 22 23 clientgentypes "k8s.io/code-generator/cmd/client-gen/types" 24 "k8s.io/gengo/v2/generator" 25 "k8s.io/gengo/v2/types" 26 "knative.dev/pkg/codegen/cmd/injection-gen/args" 27 "knative.dev/pkg/codegen/cmd/injection-gen/tags" 28 ) 29 30 func Targets( 31 args *args.Args, 32 groupPkgName string, 33 gv clientgentypes.GroupVersion, 34 groupGoName string, 35 typesToGenerate []*types.Type, 36 ) []generator.Target { 37 basePackage := args.GetOutputPackagePath() 38 packagePath := filepath.Join(basePackage, "reconciler", groupPkgName, strings.ToLower(gv.Version.NonEmpty())) 39 packageDir := filepath.Join(args.GetOutputDir(), "reconciler", groupPkgName, strings.ToLower(gv.Version.NonEmpty())) 40 41 clientPackagePath := filepath.Join(basePackage, "client") 42 43 vers := make([]generator.Target, 0, 4*len(typesToGenerate)) 44 45 for _, t := range typesToGenerate { 46 extracted := extractCommentTags(t) 47 reconcilerClasses, hasReconcilerClass := extractReconcilerClassesTag(extracted) 48 nonNamespaced := isNonNamespaced(extracted) 49 isKRShaped := isKRShaped(extracted) 50 stubs := stubs(extracted) 51 52 packagePath := filepath.Join(packagePath, strings.ToLower(t.Name.Name)) 53 packageDir := filepath.Join(packageDir, strings.ToLower(t.Name.Name)) 54 55 informerPackagePath := filepath.Join(basePackage, "informers", groupPkgName, strings.ToLower(gv.Version.NonEmpty()), strings.ToLower(t.Name.Name)) 56 listerPackagePath := filepath.Join(args.ListersPackage, groupPkgName, strings.ToLower(gv.Version.NonEmpty())) 57 58 // Controller 59 vers = append(vers, &generator.SimpleTarget{ 60 PkgName: strings.ToLower(t.Name.Name), 61 PkgPath: packagePath, 62 PkgDir: packageDir, 63 HeaderComment: args.Boilerplate, 64 GeneratorsFunc: func(c *generator.Context) []generator.Generator { 65 // Impl 66 return []generator.Generator{&reconcilerControllerGenerator{ 67 GoGenerator: generator.GoGenerator{ 68 OutputFilename: "controller.go", 69 }, 70 typeToGenerate: t, 71 outputPackage: packagePath, 72 imports: generator.NewImportTracker(), 73 groupName: gv.Group.String(), 74 clientPkg: clientPackagePath, 75 informerPackagePath: informerPackagePath, 76 schemePkg: filepath.Join(args.VersionedClientSetPackage, "scheme"), 77 reconcilerClasses: reconcilerClasses, 78 hasReconcilerClass: hasReconcilerClass, 79 hasStatus: hasStatus(t), 80 }} 81 }, 82 FilterFunc: func(c *generator.Context, t *types.Type) bool { 83 tags := tags.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) 84 return tags.NeedsReconciler(t, args) 85 }, 86 }) 87 88 if stubs { 89 // Controller Stub 90 vers = append(vers, &generator.SimpleTarget{ 91 PkgName: strings.ToLower(t.Name.Name), 92 PkgPath: filepath.Join(packagePath, "stub"), 93 PkgDir: filepath.Join(packageDir, "stub"), 94 HeaderComment: args.Boilerplate, 95 GeneratorsFunc: func(c *generator.Context) []generator.Generator { 96 // Impl 97 return []generator.Generator{&reconcilerControllerStubGenerator{ 98 GoGenerator: generator.GoGenerator{ 99 OutputFilename: "controller.go", 100 }, 101 typeToGenerate: t, 102 reconcilerPkg: packagePath, 103 outputPackage: filepath.Join(packagePath, "stub"), 104 imports: generator.NewImportTracker(), 105 informerPackagePath: informerPackagePath, 106 reconcilerClasses: reconcilerClasses, 107 hasReconcilerClass: hasReconcilerClass, 108 }} 109 }, 110 FilterFunc: func(c *generator.Context, t *types.Type) bool { 111 tags := tags.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) 112 return tags.NeedsReconciler(t, args) 113 }, 114 }) 115 } 116 117 // Reconciler 118 vers = append(vers, &generator.SimpleTarget{ 119 PkgName: strings.ToLower(t.Name.Name), 120 PkgPath: packagePath, 121 PkgDir: packageDir, 122 HeaderComment: args.Boilerplate, 123 GeneratorsFunc: func(c *generator.Context) []generator.Generator { 124 // Impl 125 return []generator.Generator{&reconcilerReconcilerGenerator{ 126 GoGenerator: generator.GoGenerator{ 127 OutputFilename: "reconciler.go", 128 }, 129 typeToGenerate: t, 130 outputPackage: packagePath, 131 imports: generator.NewImportTracker(), 132 clientsetPkg: args.VersionedClientSetPackage, 133 listerName: t.Name.Name + "Lister", 134 listerPkg: listerPackagePath, 135 groupGoName: groupGoName, 136 groupVersion: gv, 137 reconcilerClasses: reconcilerClasses, 138 hasReconcilerClass: hasReconcilerClass, 139 nonNamespaced: nonNamespaced, 140 isKRShaped: isKRShaped, 141 hasStatus: hasStatus(t), 142 }} 143 }, 144 FilterFunc: func(c *generator.Context, t *types.Type) bool { 145 tags := tags.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) 146 return tags.NeedsReconciler(t, args) 147 }, 148 }) 149 150 if stubs { 151 // Reconciler Stub 152 vers = append(vers, &generator.SimpleTarget{ 153 PkgName: strings.ToLower(t.Name.Name), 154 PkgPath: filepath.Join(packagePath, "stub"), 155 PkgDir: filepath.Join(packageDir, "stub"), 156 HeaderComment: args.Boilerplate, 157 GeneratorsFunc: func(c *generator.Context) []generator.Generator { 158 // Impl 159 return []generator.Generator{&reconcilerReconcilerStubGenerator{ 160 GoGenerator: generator.GoGenerator{ 161 OutputFilename: "reconciler.go", 162 }, 163 typeToGenerate: t, 164 reconcilerPkg: packagePath, 165 outputPackage: filepath.Join(packagePath, "stub"), 166 imports: generator.NewImportTracker(), 167 }} 168 }, 169 FilterFunc: func(c *generator.Context, t *types.Type) bool { 170 tags := tags.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) 171 return tags.NeedsReconciler(t, args) 172 }, 173 }) 174 } 175 176 // Reconciler State 177 vers = append(vers, &generator.SimpleTarget{ 178 PkgName: strings.ToLower(t.Name.Name), 179 PkgPath: packagePath, 180 PkgDir: packageDir, 181 HeaderComment: args.Boilerplate, 182 GeneratorsFunc: func(c *generator.Context) []generator.Generator { 183 // state 184 return []generator.Generator{&reconcilerStateGenerator{ 185 GoGenerator: generator.GoGenerator{ 186 OutputFilename: "state.go", 187 }, 188 typeToGenerate: t, 189 outputPackage: packagePath, 190 imports: generator.NewImportTracker(), 191 }} 192 }, 193 FilterFunc: func(c *generator.Context, t *types.Type) bool { 194 tags := tags.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) 195 return tags.NeedsReconciler(t, args) 196 }, 197 }) 198 } 199 return vers 200 } 201 202 func extractCommentTags(t *types.Type) tags.CommentTags { 203 comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...) 204 return tags.ExtractCommentTags("+", comments) 205 } 206 207 func extractReconcilerClassesTag(tags tags.CommentTags) ([]string, bool) { 208 vals, ok := tags["genreconciler"] 209 if !ok { 210 return nil, false 211 } 212 classnames, has := vals["class"] 213 if has && len(classnames) == 0 { 214 return nil, false 215 } 216 return classnames, has 217 } 218 219 func isKRShaped(tags tags.CommentTags) bool { 220 vals, has := tags["genreconciler"] 221 if !has { 222 return false 223 } 224 stringVals, has := vals["krshapedlogic"] 225 if !has || len(vals) == 0 { 226 return true // Default is true 227 } 228 return stringVals[0] != "false" 229 } 230 231 func isNonNamespaced(tags tags.CommentTags) bool { 232 vals, has := tags["genclient"] 233 if !has { 234 return false 235 } 236 _, has = vals["nonNamespaced"] 237 return has 238 } 239 240 func stubs(tags tags.CommentTags) bool { 241 vals, has := tags["genreconciler"] 242 if !has { 243 return false 244 } 245 _, has = vals["stubs"] 246 return has 247 } 248 249 func hasStatus(t *types.Type) bool { 250 for _, member := range t.Members { 251 if member.Name == "Status" { 252 return true 253 } 254 } 255 return false 256 }