github.com/galaxyobe/gen@v0.0.0-20220910125335-392fa8f0990f/cmd/getter-gen/generators/generator.go (about) 1 /* 2 Copyright 2022 Galaxyobe. 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 generators 18 19 import ( 20 "io" 21 "strings" 22 23 "k8s.io/gengo/generator" 24 "k8s.io/gengo/namer" 25 "k8s.io/gengo/types" 26 "k8s.io/klog/v2" 27 28 "github.com/galaxyobe/gen/pkg/util" 29 30 "github.com/galaxyobe/gen/third_party/gengo/parser" 31 ) 32 33 type GenType struct { 34 *types.Type 35 AllowFields []string 36 } 37 38 func NewGenTypes(pkg *types.Package) (pkgEnabled bool, list GenTypes) { 39 pkgAllowed := util.CheckTag(tagPackageName, pkg.Comments, util.Package) 40 for _, t := range pkg.Types { 41 ut := util.UnderlyingType(t) 42 if ut.Kind != types.Struct { 43 continue 44 } 45 comments := t.CommentLines 46 set, enabled := util.GetTagBoolStatus(tagPackageName, comments) 47 allowedFields := util.GetTagValues(tagSelectFieldsName, comments) 48 if len(allowedFields) > 0 { 49 set = true 50 enabled = true 51 } 52 if (!pkgAllowed && !set) || !enabled { 53 continue // ignore type 54 } 55 pkgEnabled = true 56 list = append(list, &GenType{ 57 Type: t, 58 AllowFields: allowedFields, 59 }) 60 } 61 if len(list) == 0 { 62 pkgEnabled = false 63 } 64 return 65 } 66 67 type GenTypes []*GenType 68 69 func (list GenTypes) allowed(t *types.Type) bool { 70 for _, item := range list { 71 if item.Name.Name == t.Name.Name && item.Name.Package == t.Name.Package { 72 return true 73 } 74 } 75 return false 76 } 77 78 // allowedField allowed type's field to generate Getter func. 79 // will be ignored field enabled status when it's in +gen:getter:fields allowed fields. 80 func (list GenTypes) allowedField(t *types.Type, m int) bool { 81 for _, item := range list { 82 if item.Name.Name == t.Name.Name && item.Name.Package == t.Name.Package { 83 if len(t.Members) == 0 { 84 return true 85 } 86 field := t.Members[m] 87 set, enable := util.GetTagBoolStatus(tagFieldName, field.CommentLines) 88 if set && !enable && len(item.AllowFields) == 0 { 89 return false 90 } 91 if len(item.AllowFields) == 0 { 92 return true 93 } 94 return util.Exist(item.AllowFields, field.Name) 95 } 96 } 97 return false 98 } 99 100 type genGetter struct { 101 generator.DefaultGen 102 build *parser.Builder 103 targetPackage string 104 boundingDirs []string 105 imports namer.ImportTracker 106 types GenTypes 107 packageTypes util.PackageTypes 108 } 109 110 func NewGenGetter(build *parser.Builder, sanitizedName, targetPackage string, boundingDirs []string, types []*GenType, sourcePath string) generator.Generator { 111 return &genGetter{ 112 DefaultGen: generator.DefaultGen{ 113 OptionalName: sanitizedName, 114 }, 115 build: build, 116 targetPackage: targetPackage, 117 boundingDirs: boundingDirs, 118 imports: generator.NewImportTracker(), 119 types: types, 120 packageTypes: util.NewPackageTypes(build), 121 } 122 } 123 124 func (g *genGetter) Name() string { 125 return "getter" 126 } 127 128 func (g *genGetter) Filter(c *generator.Context, t *types.Type) bool { 129 ok := g.types.allowed(t) 130 if !ok { 131 klog.V(5).Infof("Ignore generate getter function for type %v", t) 132 } 133 return ok 134 } 135 136 func (g *genGetter) Namers(c *generator.Context) namer.NameSystems { 137 // Have the raw namer for this file track what it imports. 138 return namer.NameSystems{ 139 "raw": namer.NewRawNamer(g.targetPackage, g.imports), 140 } 141 } 142 143 func (g *genGetter) Init(c *generator.Context, w io.Writer) error { 144 return nil 145 } 146 147 func (g *genGetter) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { 148 klog.V(5).Infof("Generating getter function for type %v", t) 149 150 sw := generator.NewSnippetWriter(w, c, "", "") 151 g.genGetFunc(sw, t) 152 sw.Do("\n", nil) 153 154 return sw.Error() 155 } 156 157 func (g *genGetter) isOtherPackage(pkg string) bool { 158 if pkg == g.targetPackage { 159 return false 160 } 161 if strings.HasSuffix(pkg, "\""+g.targetPackage+"\"") { 162 return false 163 } 164 return true 165 } 166 167 func (g *genGetter) Imports(c *generator.Context) (imports []string) { 168 var importLines []string 169 for _, singleImport := range g.imports.ImportLines() { 170 if g.isOtherPackage(singleImport) { 171 importLines = append(importLines, singleImport) 172 } 173 } 174 return importLines 175 } 176 177 func (g *genGetter) genGetFunc(sw *generator.SnippetWriter, t *types.Type) { 178 receiver := strings.ToLower(t.Name.Name[:1]) 179 isExternalType := g.packageTypes.IsExternalType(t.Name.Package, t.Name.Name) 180 var methodSet = util.NewMethodSet() 181 var methodGen = util.NewMethodGenerate(util.GenName("Get", "")) 182 183 for idx, m := range t.Members { 184 if util.IsLower(m.Name) && isExternalType { 185 continue 186 } 187 methods := util.GetTagValues(tagMethodName, m.CommentLines) 188 methodSet.AddMethods("Get", methods, t.Members[idx]) 189 if !g.types.allowedField(t, idx) { 190 continue 191 } 192 method := methodGen.GenName(m.Name) 193 if _, ok := t.Methods[method]; ok { 194 continue 195 } 196 args := generator.Args{ 197 "type": t, 198 "field": m, 199 "receiver": receiver, 200 "method": method, 201 } 202 sw.Do("func ({{.receiver}} *{{.type|public}}) {{.method}} () {{.field.Type|raw}} {\n", args) 203 sw.Do("return {{.receiver}}.{{.field.Name}}\n", args) 204 sw.Do("}\n\n", nil) 205 } 206 // add exist methods 207 methodGen.AddExistNames(func() []string { 208 var existMethods []string 209 for name := range t.Methods { 210 existMethods = append(existMethods, name) 211 } 212 return existMethods 213 }()...) 214 // gen aggregate method 215 for method, members := range methodSet { 216 if ok := methodGen.ExistName(method); ok { 217 klog.Fatalf("exist method: %s when generate aggregate method", method) 218 } 219 args := generator.Args{ 220 "type": t, 221 "receiver": receiver, 222 "method": method, 223 "fields": members, 224 } 225 sw.Do("func ({{.receiver}} *{{.type|public}}) {{.method}} () ({{ range $i, $field := .fields }} in{{$i}} {{$field.Type|raw}}, {{end}}) {\n", args) 226 sw.Do("{{ range $i, $field := .fields }} in{{$i}} = {{$.receiver}}.{{$field.Name}}\n {{ end }}", args) 227 sw.Do("return", nil) 228 sw.Do("}\n\n", nil) 229 } 230 }