Skip to content

Commit

Permalink
feat: split doc.go generation into comments and code portions
Browse files Browse the repository at this point in the history
  • Loading branch information
shollyman committed Nov 4, 2024
1 parent 6249624 commit 7fdfe93
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 65 deletions.
55 changes: 1 addition & 54 deletions internal/gengapic/doc_file.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,19 @@
package gengapic

import (
"sort"
"strings"

"github.com/googleapis/gapic-generator-go/internal/license"
"github.com/googleapis/gapic-generator-go/internal/pbinfo"
"github.com/googleapis/gapic-generator-go/internal/printer"
"google.golang.org/genproto/googleapis/api/annotations"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/descriptorpb"
)

// genDocFile generates doc.go
//
// Since it's the only file that needs to write package documentation and canonical import,
// it does not use g.commit().
func (g *generator) genDocFile(year int, scopes []string, serv *descriptorpb.ServiceDescriptorProto) {
func (g *generator) genDocFile(year int, serv *descriptorpb.ServiceDescriptorProto) {
p := g.printf

p(license.Apache, year)
Expand Down Expand Up @@ -125,56 +122,6 @@ func (g *generator) genDocFile(year int, scopes []string, serv *descriptorpb.Ser
p("// [Inspecting errors]: https://pkg.go.dev/cloud.google.com/go#hdr-Inspecting_errors")
p("package %s // import %q", g.opts.pkgName, g.opts.pkgPath)
p("")

p("import (")
p("%s%q", "\t", "context")
p("")
p("%s%q", "\t", "google.golang.org/api/option")
p(")")
p("")

p("// For more information on implementing a client constructor hook, see")
p("// https://github.com/googleapis/google-cloud-go/wiki/Customizing-constructors.")
p("type clientHookParams struct{}")
p("type clientHook func(context.Context, clientHookParams) ([]option.ClientOption, error)")
p("")

p("var versionClient string")
p("")
p("func getVersionClient() string {")
p(` if versionClient == "" {`)
p(` return "UNKNOWN"`)
p(" }")
p(" return versionClient")
p("}")
p("")

p("// DefaultAuthScopes reports the default set of authentication scopes to use with this package.")
p("func DefaultAuthScopes() []string {")
p(" return []string{")
for _, sc := range scopes {
p("%q,", sc)
}
p(" }")
p("}")
}

func collectScopes(servs []*descriptorpb.ServiceDescriptorProto) []string {
scopeSet := map[string]bool{}
for _, s := range servs {
eOauthScopes := proto.GetExtension(s.Options, annotations.E_OauthScopes)
scopes := strings.Split(eOauthScopes.(string), ",")
for _, sc := range scopes {
scopeSet[sc] = true
}
}

var scopes []string
for sc := range scopeSet {
scopes = append(scopes, sc)
}
sort.Strings(scopes)
return scopes
}

func wrapString(str string, max int) []string {
Expand Down
4 changes: 2 additions & 2 deletions internal/gengapic/doc_file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func TestDocFile(t *testing.T) {
} {
t.Run(tst.want, func(t *testing.T) {
g.opts.relLvl = tst.relLvl
g.genDocFile(sample.Year, []string{sample.ServiceOAuthScope}, serv)
g.genDocFile(sample.Year, serv)
txtdiff.Diff(t, g.pt.String(), tst.want)
g.reset()
})
Expand Down Expand Up @@ -121,7 +121,7 @@ func TestDocFileEmptyService(t *testing.T) {
} {
t.Run(tst.want, func(t *testing.T) {
g.opts.relLvl = tst.relLvl
g.genDocFile(sample.Year, []string{sample.ServiceOAuthScope}, serv)
g.genDocFile(sample.Year, serv)
txtdiff.Diff(t, g.pt.String(), tst.want)
g.reset()
})
Expand Down
76 changes: 70 additions & 6 deletions internal/gengapic/gengapic.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"net/url"
"path/filepath"
"regexp"
"sort"
"strings"
"time"

Expand Down Expand Up @@ -69,7 +70,7 @@ func gen(genReq *pluginpb.CodeGeneratorRequest) (*pluginpb.CodeGeneratorResponse
return nil, err
}

genServs := g.collectServices(genReq)
genServs, scopes := g.collectServicesAndScopes(genReq)
if len(genServs) == 0 {
return &g.resp, nil
}
Expand Down Expand Up @@ -100,6 +101,11 @@ func gen(genReq *pluginpb.CodeGeneratorRequest) (*pluginpb.CodeGeneratorResponse
// Initialize the model that will collect snippet metadata.
g.snippetMetadata = g.newSnippetsMetadata(protoPkg)

// generate shared code such as client hooks and scopes.
if err := g.genAndCommitSharedCode(scopes); err != nil {
return &g.resp, fmt.Errorf("error generating shared code file: %v", err)
}

for _, s := range genServs {
// TODO(pongad): gapic-generator does not remove the package name here,
// so even though the client for LoggingServiceV2 is just "Client"
Expand Down Expand Up @@ -150,10 +156,8 @@ func gen(genReq *pluginpb.CodeGeneratorRequest) (*pluginpb.CodeGeneratorResponse
return nil, err
}
g.reset()
scopes := collectScopes(genServs)
serv := genServs[0]

g.genDocFile(time.Now().Year(), scopes, serv)
g.genDocFile(time.Now().Year(), serv)
g.resp.File = append(g.resp.File, &pluginpb.CodeGeneratorResponse_File{
Name: proto.String(filepath.Join(g.opts.outDir, "doc.go")),
Content: proto.String(g.pt.String()),
Expand Down Expand Up @@ -184,20 +188,80 @@ func gen(genReq *pluginpb.CodeGeneratorRequest) (*pluginpb.CodeGeneratorResponse
return &g.resp, nil
}

// Collects the proto services to generate GAPICs for from the CodeGeneratorRequest.
func (g *generator) collectServices(genReq *pluginpb.CodeGeneratorRequest) (genServs []*descriptorpb.ServiceDescriptorProto) {
// Collects the proto services and scopes to generate GAPICs for from the CodeGeneratorRequest.
func (g *generator) collectServicesAndScopes(genReq *pluginpb.CodeGeneratorRequest) (genServs []*descriptorpb.ServiceDescriptorProto, scopes []string) {
scopeSet := map[string]bool{}
for _, f := range genReq.GetProtoFile() {
if !strContains(genReq.GetFileToGenerate(), f.GetName()) {
continue
}
if !g.includeMixinInputFile(f.GetName()) {
continue
}
servs := f.GetService()
// record service(s) present in each file.
genServs = append(genServs, f.GetService()...)

// record encountered scopes in each service.
for _, s := range servs {
eOauthScopes := proto.GetExtension(s.Options, annotations.E_OauthScopes)
scopes := strings.Split(eOauthScopes.(string), ",")
for _, sc := range scopes {
scopeSet[sc] = true
}
}
}

// transform scope map to list
for sc := range scopeSet {
scopes = append(scopes, sc)
}
sort.Strings(scopes)
return
}

func (g *generator) genAndCommitSharedCode(scopes []string) error {
p := g.printf
g.reset()
p("import (")
p("%s%q", "\t", "context")
p("")
p("%s%q", "\t", "google.golang.org/api/option")
p(")")
p("")

p("// For more information on implementing a client constructor hook, see")
p("// https://github.com/googleapis/google-cloud-go/wiki/Customizing-constructors.")
p("type clientHookParams struct{}")
p("type clientHook func(context.Context, clientHookParams) ([]option.ClientOption, error)")
p("")

p("var versionClient string")
p("")
p("func getVersionClient() string {")
p(` if versionClient == "" {`)
p(` return "UNKNOWN"`)
p(" }")
p(" return versionClient")
p("}")
p("")

if len(scopes) > 0 {
p("// DefaultAuthScopes reports the default set of authentication scopes to use with this package.")
p("func DefaultAuthScopes() []string {")
p(" return []string{")
for _, sc := range scopes {
p("%q,", sc)
}
p(" }")
p("}")
}

outFile := filepath.Join(g.opts.outDir, "shared_common_code.go")
g.commit(outFile, g.opts.pkgName)
return nil
}

// gen generates client for the given service.
func (g *generator) gen(serv *descriptorpb.ServiceDescriptorProto) error {
servName := pbinfo.ReduceServName(serv.GetName(), g.opts.pkgName)
Expand Down
6 changes: 3 additions & 3 deletions internal/gengapic/gengapic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1252,7 +1252,7 @@ func TestReturnType(t *testing.T) {
}
}

func TestCollectServices(t *testing.T) {
func TestCollectServicesAndScopes(t *testing.T) {
libraryServ := &descriptorpb.ServiceDescriptorProto{
Name: proto.String("Library"),
}
Expand Down Expand Up @@ -1302,11 +1302,11 @@ func TestCollectServices(t *testing.T) {
},
} {
g := &generator{opts: &options{pkgPath: tst.goPkgPath}}
got := g.collectServices(&pluginpb.CodeGeneratorRequest{
gotServices, _ := g.collectServicesAndScopes(&pluginpb.CodeGeneratorRequest{
FileToGenerate: tst.toGen,
ProtoFile: tst.fileSet,
})
if diff := cmp.Diff(got, tst.want, cmp.Comparer(proto.Equal)); diff != "" {
if diff := cmp.Diff(gotServices, tst.want, cmp.Comparer(proto.Equal)); diff != "" {
t.Errorf("%s: got(-),want(+):\n%s", tst.name, diff)
}
}
Expand Down

0 comments on commit 7fdfe93

Please sign in to comment.