Skip to content

Commit c983e8b

Browse files
committed
infer apiVersion, no need for -api-prefix or apiGroups in config
Signed-off-by: Ahmet Alp Balkan <ahmetb@google.com>
1 parent 252a7df commit c983e8b

4 files changed

Lines changed: 45 additions & 39 deletions

File tree

README.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ generate API documentation from it.
3434
$ refdocs \
3535
-config "/path/to/knative-config.json" \
3636
-api-dir "github.com/knative/build/pkg/apis/build/v1alpha1" \
37-
-api-prefix "github.com/knative/build/pkg/apis/" \
3837
-out-file docs.html
3938
```
4039

knative-config.json

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,4 @@
11
{
2-
"apiGroups": {
3-
"github.com/knative/build/pkg/apis/build/v1alpha1": "build.knative.dev/v1alpha1",
4-
"github.com/knative/serving/pkg/apis/autoscaling/v1alpha1": "autoscaling.knative.dev/v1alpha1",
5-
"github.com/knative/serving/pkg/apis/networking/v1alpha1": "networking.internal.knative.dev/v1alpha1",
6-
"github.com/knative/serving/pkg/apis/serving/v1alpha1": "serving.knative.dev/v1alpha1",
7-
"github.com/knative/eventing/pkg/apis/eventing/v1alpha1": "eventing.knative.dev/v1alpha1",
8-
"github.com/knative/eventing/pkg/apis/duck/v1alpha1": "duck.knative.dev/v1alpha1",
9-
"github.com/knative/eventing-sources/pkg/apis/sources/v1alpha1": "sources.eventing.knative.dev/v1alpha1"
10-
},
112
"hideMemberFields": [
123
"TypeMeta"
134
],

main.go

Lines changed: 44 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,17 @@ import (
2626
)
2727

2828
var (
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

3939
type 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

256254
func 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.
288286
func 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-
}
390385
func 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+
454464
func 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 {

template/pkg.tpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ table, td, th {
99

1010
{{ range .packages }}
1111
<h2>
12-
{{ packageDisplayName . }}
12+
{{- packageDisplayName . -}}
1313
</h2>
1414

1515
{{ with .DocComments }}

0 commit comments

Comments
 (0)