@@ -26,20 +26,17 @@ import (
2626)
2727
2828var (
29- flConfig = flag .String ("config" , "" , "path to config file" )
30- flAPIDir = flag .String ("api-dir" , "" , "api directory (or import path), point this to pkg/apis" )
31- flAPIPrefix = flag .String ("api-prefix" , "" , "(optional) match only APIs with this package prefix" )
29+ flConfig = flag .String ("config" , "" , "path to config file" )
30+ flAPIDir = flag .String ("api-dir" , "" , "api directory (or import path), point this to pkg/apis" )
3231
3332 flHTTPAddr = flag .String ("http-addr" , "" , "start an HTTP server on specified addr to view the result (e.g. :8080)" )
3433 flOutFile = flag .String ("out-file" , "" , "path to output file to save the result" )
3534
36- tplDir string
35+ tplDir string
36+ apiPackages []* types.Package
3737)
3838
3939type generatorConfig struct {
40- // APIGroups maps package import paths to Kubernetes API Groups.
41- APIGroups map [string ]string `json:"apiGroups"`
42-
4340 // HiddenMemberFields hides fields with specified names on all types.
4441 HiddenMemberFields []string `json:"hideMemberFields"`
4542
@@ -76,9 +73,6 @@ func init() {
7673 if * flAPIDir == "" {
7774 panic ("-api-dir not specified" )
7875 }
79- if * flAPIPrefix == "" {
80- panic ("-api-prefix not specified" )
81- }
8276 if * flHTTPAddr == "" && * flOutFile == "" {
8377 panic ("-out-file or -http-addr must be specified" )
8478 }
@@ -116,19 +110,15 @@ func main() {
116110 panic (errors .Wrap (err , "failed to parse config file" ))
117111 }
118112
119- klog .Infof ("using api directory %s" , * flAPIDir )
113+ klog .Infof ("parsing go packages in directory %s" , * flAPIDir )
120114 pkgs , err := parseAPIPackages (* flAPIDir )
121115 if err != nil {
122116 klog .Fatal (err )
123117 }
124118 if len (pkgs ) == 0 {
125119 klog .Fatalf ("no API packages found in %s" , * flAPIDir )
126120 }
127- for _ , pkg := range pkgs {
128- if _ , ok := config .APIGroups [pkg .Path ]; ! ok {
129- klog .Fatalf ("config.APIGroups don't define an api group for package=%s" , pkg .Path )
130- }
131- }
121+ apiPackages = pkgs
132122
133123 mkOutput := func () (string , error ) {
134124 var b bytes.Buffer
@@ -197,14 +187,16 @@ func parseAPIPackages(dir string) ([]*types.Package, error) {
197187 }
198188 var pkgNames []string
199189 for p := range scan {
200- klog .V (3 ).Infof ("trying package=%v" , p )
201- if strings . HasPrefix ( p , * flAPIPrefix ) && len (scan [p ].Types ) > 0 {
202- klog .V (3 ).Infof ("package=%v is part of the API and has types" , p )
190+ klog .V (3 ).Infof ("trying package=%v groupName=%s " , p , groupName ( scan [ p ]) )
191+ if groupName ( scan [ p ]) != "" && len (scan [p ].Types ) > 0 {
192+ klog .V (3 ).Infof ("package=%v has groupName and has types" , p )
203193 pkgNames = append (pkgNames , p )
204194 }
205195 }
196+ sort .Strings (pkgNames )
206197 var pkgs []* types.Package
207198 for _ , p := range pkgNames {
199+ klog .Infof ("using package=%s" , p )
208200 pkgs = append (pkgs , scan [p ])
209201 }
210202 return pkgs , nil
@@ -246,11 +238,17 @@ func fieldEmbedded(m types.Member) bool {
246238 return strings .Contains (reflect .StructTag (m .Tags ).Get ("json" ), ",inline" )
247239}
248240
249- func isLocalType (t * types.Type , c generatorConfig ) bool {
241+ func isLocalType (t * types.Type ) bool {
250242 if t .Elem != nil {
251243 t = t .Elem
252244 }
253- return strings .HasPrefix (t .Name .Package , * flAPIPrefix )
245+ pkg := t .Name .Package
246+ for _ , p := range apiPackages { // TODO(ahmetb) eliminate need for global var
247+ if pkg == p .Path {
248+ return true
249+ }
250+ }
251+ return false
254252}
255253
256254func showComments (s []string ) string {
@@ -277,7 +275,7 @@ func typeIdentifier(t *types.Type, c generatorConfig) string {
277275 if t .Elem != nil {
278276 tt = t .Elem
279277 }
280- if ! isLocalType (t , c ) {
278+ if ! isLocalType (t ) {
281279 return tt .Name .String () // {PackagePath.Name}
282280 }
283281 return tt .Name .Name // just {Name}
@@ -286,7 +284,7 @@ func typeIdentifier(t *types.Type, c generatorConfig) string {
286284// linkForType returns an anchor to the type if it can be generated. returns
287285// empty string if it is not a local type or unrecognized external type.
288286func linkForType (t * types.Type , c generatorConfig ) (string , error ) {
289- if isLocalType (t , c ) {
287+ if isLocalType (t ) {
290288 return "#" + typeIdentifier (t , c ), nil
291289 }
292290
@@ -384,9 +382,6 @@ func hideType(t *types.Type, c generatorConfig) bool {
384382 return false
385383}
386384
387- func apiGroup (t * types.Type , c generatorConfig ) string {
388- return c .APIGroups [t .Name .Package ]
389- }
390385func typeReferences (t * types.Type , c generatorConfig , references map [* types.Type ][]* types.Type ) []* types.Type {
391386 var out []* types.Type
392387 m := make (map [* types.Type ]struct {})
@@ -451,9 +446,29 @@ func isOptionalMember(m types.Member) bool {
451446 return ok
452447}
453448
449+ func apiVersionMap (pkgs []* types.Package ) (map [string ]string , error ) {
450+ m := make (map [string ]string )
451+ for _ , pkg := range pkgs {
452+ group := groupName (pkg )
453+ version := pkg .Name // assumes last part (i.e. v1 in core/v1) is apiVersion
454+ r := `^v\d+((alpha|beta)\d+)?$`
455+ if ! regexp .MustCompile (r ).MatchString (version ) {
456+ return nil , errors .Errorf ("cannot infer api version from package path %s (%q doesn't match %s)" , pkg .Path , version , r )
457+ }
458+
459+ m [pkg .Path ] = fmt .Sprintf ("%s/%s" , group , version )
460+ }
461+ return m , nil
462+ }
463+
454464func render (w io.Writer , pkgs []* types.Package , config generatorConfig ) error {
455465 references := findTypeReferences (pkgs )
456466
467+ apiVersions , err := apiVersionMap (pkgs )
468+ if err != nil {
469+ return errors .Wrap (err , "failed to infer apiVersions" )
470+ }
471+
457472 t , err := template .New ("" ).Funcs (map [string ]interface {}{
458473 "isExportedType" : isExportedType ,
459474 "fieldName" : fieldName ,
@@ -464,19 +479,20 @@ func render(w io.Writer, pkgs []*types.Package, config generatorConfig) error {
464479 "showComments" : showComments ,
465480 "nl2br" : nl2br ,
466481 "packageDisplayName" : packageDisplayName ,
467- "apiGroup" : func (t * types.Type ) string { return apiGroup ( t , config ) },
482+ "apiGroup" : func (t * types.Type ) string { return apiVersions [ t . Name . Package ] },
468483 "linkForType" : func (t * types.Type ) string {
469484 v , err := linkForType (t , config )
470485 if err != nil {
471486 klog .Fatal (errors .Wrapf (err , "error getting link for type=%s" , t .Name ))
487+ return ""
472488 }
473489 return v
474490 },
475491 "safe" : safe ,
476492 "sortedTypes" : sortedTypes ,
477493 "typeReferences" : func (t * types.Type ) []* types.Type { return typeReferences (t , config , references ) },
478494 "hiddenMember" : func (m types.Member ) bool { return hiddenMember (m , config ) },
479- "isLocalType" : func ( t * types. Type ) bool { return isLocalType ( t , config ) } ,
495+ "isLocalType" : isLocalType ,
480496 "isOptionalMember" : isOptionalMember ,
481497 }).ParseGlob (filepath .Join (tplDir , "*.tpl" ))
482498 if err != nil {
0 commit comments