From 6dec8cedac1959aa2e3c62a07f4412b22072aea1 Mon Sep 17 00:00:00 2001 From: Michael Darakananda Date: Thu, 20 Sep 2018 17:41:48 -0700 Subject: [PATCH] use shared utility code The delete code were moved into internal/ when bootstrapping samplegen. --- gengapic/client_init.go | 36 ++++----- gengapic/client_init_test.go | 11 +-- gengapic/doc_file_test.go | 2 +- gengapic/example.go | 17 +++-- gengapic/example_test.go | 13 ++-- gengapic/gengapic.go | 143 +++++++---------------------------- gengapic/gengapic_test.go | 19 ++--- gengapic/imports.go | 20 +++-- gengapic/lro.go | 23 +++--- gengapic/paging.go | 37 ++++----- gengapic/paging_test.go | 114 ++++++++++++++-------------- gengapic/stream.go | 6 +- internal/printer/printer.go | 4 + 13 files changed, 182 insertions(+), 263 deletions(-) diff --git a/gengapic/client_init.go b/gengapic/client_init.go index c7aa1d5def9..ac155f38fc3 100644 --- a/gengapic/client_init.go +++ b/gengapic/client_init.go @@ -20,6 +20,7 @@ import ( "github.com/golang/protobuf/proto" "github.com/golang/protobuf/protoc-gen-go/descriptor" "github.com/googleapis/gapic-generator-go/internal/errors" + "github.com/googleapis/gapic-generator-go/internal/pbinfo" "google.golang.org/genproto/googleapis/api/annotations" ) @@ -28,22 +29,15 @@ func (g *generator) clientOptions(serv *descriptor.ServiceDescriptorProto, servN // CallOptions struct { - var maxNameLen int - for _, m := range serv.Method { - if l := len(*m.Name); maxNameLen < l { - maxNameLen = l - } - } - p("// %[1]sCallOptions contains the retry settings for each method of %[1]sClient.", servName) p("type %sCallOptions struct {", servName) for _, m := range serv.Method { - p("%s%s[]gax.CallOption", *m.Name, spaces(maxNameLen-len(*m.Name)+1)) + p("%s []gax.CallOption", *m.Name) } p("}") p("") - g.imports[importSpec{"gax", "github.com/googleapis/gax-go"}] = true + g.imports[pbinfo.ImportSpec{"gax", "github.com/googleapis/gax-go"}] = true } // defaultClientOptions @@ -61,7 +55,7 @@ func (g *generator) clientOptions(serv *descriptor.ServiceDescriptorProto, servN p("}") p("") - g.imports[importSpec{path: "google.golang.org/api/option"}] = true + g.imports[pbinfo.ImportSpec{Path: "google.golang.org/api/option"}] = true } // defaultCallOptions @@ -98,8 +92,8 @@ func (g *generator) clientOptions(serv *descriptor.ServiceDescriptorProto, servN p("}") p("") - g.imports[importSpec{path: "time"}] = true - g.imports[importSpec{path: "google.golang.org/grpc/codes"}] = true + g.imports[pbinfo.ImportSpec{Path: "time"}] = true + g.imports[pbinfo.ImportSpec{Path: "google.golang.org/grpc/codes"}] = true } p(" return &%sCallOptions{", servName) @@ -125,7 +119,7 @@ func (g *generator) clientInit(serv *descriptor.ServiceDescriptorProto, servName } } - imp, err := g.importSpec(serv) + imp, err := g.descInfo.ImportSpec(serv) if err != nil { return err } @@ -142,7 +136,7 @@ func (g *generator) clientInit(serv *descriptor.ServiceDescriptorProto, servName p("") p("// The gRPC API client.") - p("%s %s.%sClient", grpcClientField(servName), imp.name, serv.GetName()) + p("%s %s.%sClient", grpcClientField(servName), imp.Name, serv.GetName()) p("") if hasLRO { @@ -152,7 +146,7 @@ func (g *generator) clientInit(serv *descriptor.ServiceDescriptorProto, servName p("LROClient *lroauto.OperationsClient") p("") - g.imports[importSpec{name: "lroauto", path: "cloud.google.com/go/longrunning/autogen"}] = true + g.imports[pbinfo.ImportSpec{Name: "lroauto", Path: "cloud.google.com/go/longrunning/autogen"}] = true } p("// The call options for this service.") @@ -164,8 +158,8 @@ func (g *generator) clientInit(serv *descriptor.ServiceDescriptorProto, servName p("}") p("") - g.imports[importSpec{path: "google.golang.org/grpc"}] = true - g.imports[importSpec{path: "google.golang.org/grpc/metadata"}] = true + g.imports[pbinfo.ImportSpec{Path: "google.golang.org/grpc"}] = true + g.imports[pbinfo.ImportSpec{Path: "google.golang.org/grpc/metadata"}] = true } // Client constructor @@ -185,7 +179,7 @@ func (g *generator) clientInit(serv *descriptor.ServiceDescriptorProto, servName p(" conn: conn,") p(" CallOptions: default%sCallOptions(),", servName) p("") - p(" %s: %s.New%sClient(conn),", grpcClientField(servName), imp.name, serv.GetName()) + p(" %s: %s.New%sClient(conn),", grpcClientField(servName), imp.Name, serv.GetName()) p(" }") p(" c.setGoogleClientInfo()") p("") @@ -207,8 +201,8 @@ func (g *generator) clientInit(serv *descriptor.ServiceDescriptorProto, servName p("}") p("") - g.imports[importSpec{path: "google.golang.org/api/transport"}] = true - g.imports[importSpec{path: "golang.org/x/net/context"}] = true + g.imports[pbinfo.ImportSpec{Path: "google.golang.org/api/transport"}] = true + g.imports[pbinfo.ImportSpec{Path: "golang.org/x/net/context"}] = true } // Connection() @@ -242,7 +236,7 @@ func (g *generator) clientInit(serv *descriptor.ServiceDescriptorProto, servName p("}") p("") - g.imports[importSpec{path: "cloud.google.com/go/internal/version"}] = true + g.imports[pbinfo.ImportSpec{Path: "cloud.google.com/go/internal/version"}] = true } return nil } diff --git a/gengapic/client_init_test.go b/gengapic/client_init_test.go index f0c58b53361..be69986d017 100644 --- a/gengapic/client_init_test.go +++ b/gengapic/client_init_test.go @@ -23,6 +23,7 @@ import ( "github.com/golang/protobuf/proto" "github.com/golang/protobuf/protoc-gen-go/descriptor" "github.com/google/go-cmp/cmp" + "github.com/googleapis/gapic-generator-go/internal/pbinfo" "google.golang.org/genproto/googleapis/api/annotations" ) @@ -47,7 +48,7 @@ func diff(t *testing.T, name, got, goldenFile string) { func TestClientOpt(t *testing.T) { var g generator - g.imports = map[importSpec]bool{} + g.imports = map[pbinfo.ImportSpec]bool{} serv := &descriptor.ServiceDescriptorProto{ Method: []*descriptor.MethodDescriptorProto{ @@ -78,14 +79,14 @@ func TestClientOpt(t *testing.T) { t.Error(err) continue } - diff(t, tst.tstName, g.sb.String(), filepath.Join("testdata", tst.tstName+".want")) + diff(t, tst.tstName, g.pt.String(), filepath.Join("testdata", tst.tstName+".want")) } } func TestClientInit(t *testing.T) { var g generator g.apiName = "Awesome Foo" - g.imports = map[importSpec]bool{} + g.imports = map[pbinfo.ImportSpec]bool{} servPlain := &descriptor.ServiceDescriptorProto{ Name: proto.String("Foo"), @@ -110,7 +111,7 @@ func TestClientInit(t *testing.T) { {tstName: "empty_client_init", servName: "", serv: servPlain}, {tstName: "lro_client_init", servName: "Foo", serv: servLRO}, } { - g.parentFile = map[proto.Message]*descriptor.FileDescriptorProto{ + g.descInfo.ParentFile = map[proto.Message]*descriptor.FileDescriptorProto{ tst.serv: &descriptor.FileDescriptorProto{ Options: &descriptor.FileOptions{ GoPackage: proto.String("mypackage"), @@ -123,6 +124,6 @@ func TestClientInit(t *testing.T) { g.reset() g.clientInit(tst.serv, tst.servName) - diff(t, tst.tstName, g.sb.String(), filepath.Join("testdata", tst.tstName+".want")) + diff(t, tst.tstName, g.pt.String(), filepath.Join("testdata", tst.tstName+".want")) } } diff --git a/gengapic/doc_file_test.go b/gengapic/doc_file_test.go index 1e0e87b0e27..210398242e2 100644 --- a/gengapic/doc_file_test.go +++ b/gengapic/doc_file_test.go @@ -23,5 +23,5 @@ func TestDocFile(t *testing.T) { var g generator g.apiName = "Awesome Foo" g.genDocFile("path/to/awesome", "awesome", 42, []string{"https://foo.bar.com/auth", "https://zip.zap.com/auth"}) - diff(t, "doc_file", g.sb.String(), filepath.Join("testdata", "doc_file.want")) + diff(t, "doc_file", g.pt.String(), filepath.Join("testdata", "doc_file.want")) } diff --git a/gengapic/example.go b/gengapic/example.go index 25b1e05307f..2400ff457d6 100644 --- a/gengapic/example.go +++ b/gengapic/example.go @@ -17,6 +17,7 @@ package gengapic import ( "github.com/golang/protobuf/protoc-gen-go/descriptor" "github.com/googleapis/gapic-generator-go/internal/errors" + "github.com/googleapis/gapic-generator-go/internal/pbinfo" ) func (g *generator) genExampleFile(serv *descriptor.ServiceDescriptorProto, pkgName string) error { @@ -29,7 +30,7 @@ func (g *generator) genExampleFile(serv *descriptor.ServiceDescriptorProto, pkgN p(" _ = c") p("}") p("") - g.imports[importSpec{path: "golang.org/x/net/context"}] = true + g.imports[pbinfo.ImportSpec{Path: "golang.org/x/net/context"}] = true for _, m := range serv.Method { if err := g.exampleMethod(pkgName, servName, m); err != nil { @@ -52,12 +53,12 @@ func (g *generator) exampleInitClient(pkgName, servName string) { func (g *generator) exampleMethod(pkgName, servName string, m *descriptor.MethodDescriptorProto) error { p := g.printf - inType := g.types[m.GetInputType()] + inType := g.descInfo.Type[m.GetInputType()] if inType == nil { return errors.E(nil, "cannot find type %q, malformed descriptor?", m.GetInputType()) } - inSpec, err := g.importSpec(inType) + inSpec, err := g.descInfo.ImportSpec(inType) if err != nil { return err } @@ -69,7 +70,7 @@ func (g *generator) exampleMethod(pkgName, servName string, m *descriptor.Method if !m.GetClientStreaming() && !m.GetServerStreaming() { p("") - p("req := &%s.%s{", inSpec.name, *inType.Name) + p("req := &%s.%s{", inSpec.Name, *inType.Name) p(" // TODO: Fill request struct fields.") p("}") } @@ -146,10 +147,10 @@ func (g *generator) examplePagingCall(m *descriptor.MethodDescriptorProto) { p(" _ = resp") p("}") - g.imports[importSpec{path: "google.golang.org/api/iterator"}] = true + g.imports[pbinfo.ImportSpec{Path: "google.golang.org/api/iterator"}] = true } -func (g *generator) exampleBidiCall(m *descriptor.MethodDescriptorProto, inType *descriptor.DescriptorProto, inSpec importSpec) { +func (g *generator) exampleBidiCall(m *descriptor.MethodDescriptorProto, inType *descriptor.DescriptorProto, inSpec pbinfo.ImportSpec) { p := g.printf p("stream, err := c.%s(ctx)", m.GetName()) @@ -158,7 +159,7 @@ func (g *generator) exampleBidiCall(m *descriptor.MethodDescriptorProto, inType p("}") p("go func() {") - p(" reqs := []*%s.%s{", inSpec.name, inType.GetName()) + p(" reqs := []*%s.%s{", inSpec.Name, inType.GetName()) p(" // TODO: Create requests.") p(" }") p(" for _, req := range reqs {") @@ -181,5 +182,5 @@ func (g *generator) exampleBidiCall(m *descriptor.MethodDescriptorProto, inType p(" _ = resp") p("}") - g.imports[importSpec{path: "io"}] = true + g.imports[pbinfo.ImportSpec{Path: "io"}] = true } diff --git a/gengapic/example_test.go b/gengapic/example_test.go index 31f23228b49..7d3d50b50c4 100644 --- a/gengapic/example_test.go +++ b/gengapic/example_test.go @@ -20,11 +20,12 @@ import ( "github.com/golang/protobuf/proto" "github.com/golang/protobuf/protoc-gen-go/descriptor" + "github.com/googleapis/gapic-generator-go/internal/pbinfo" ) func TestExample(t *testing.T) { var g generator - g.imports = map[importSpec]bool{} + g.imports = map[pbinfo.ImportSpec]bool{} inputType := &descriptor.DescriptorProto{ Name: proto.String("InputType"), @@ -81,8 +82,8 @@ func TestExample(t *testing.T) { for _, typ := range []*descriptor.DescriptorProto{ inputType, outputType, pageInputType, pageOutputType, } { - g.types[".my.pkg."+*typ.Name] = typ - g.parentFile[typ] = file + g.descInfo.Type[".my.pkg."+*typ.Name] = typ + g.descInfo.ParentFile[typ] = file } serv := &descriptor.ServiceDescriptorProto{ @@ -125,7 +126,7 @@ func TestExample(t *testing.T) { } { g.reset() g.genExampleFile(serv, tst.pkgName) - diff(t, tst.tstName, g.sb.String(), filepath.Join("testdata", tst.tstName+".want")) + diff(t, tst.tstName, g.pt.String(), filepath.Join("testdata", tst.tstName+".want")) } } @@ -137,11 +138,11 @@ func commonTypes(g *generator) { Name: proto.String("Operation"), } - g.types = map[string]*descriptor.DescriptorProto{ + g.descInfo.Type = map[string]*descriptor.DescriptorProto{ emptyType: empty, lroType: lro, } - g.parentFile = map[proto.Message]*descriptor.FileDescriptorProto{ + g.descInfo.ParentFile = map[proto.Message]*descriptor.FileDescriptorProto{ empty: &descriptor.FileDescriptorProto{ Options: &descriptor.FileOptions{ GoPackage: proto.String("github.com/golang/protobuf/ptypes/empty"), diff --git a/gengapic/gengapic.go b/gengapic/gengapic.go index cff193a70a6..59c54855778 100644 --- a/gengapic/gengapic.go +++ b/gengapic/gengapic.go @@ -27,6 +27,8 @@ import ( "github.com/golang/protobuf/protoc-gen-go/descriptor" plugin "github.com/golang/protobuf/protoc-gen-go/plugin" "github.com/googleapis/gapic-generator-go/internal/errors" + "github.com/googleapis/gapic-generator-go/internal/pbinfo" + "github.com/googleapis/gapic-generator-go/internal/printer" "google.golang.org/genproto/googleapis/api/annotations" ) @@ -36,9 +38,6 @@ const ( lroType = ".google.longrunning.Operation" ) -var tabsCache = strings.Repeat("\t", 20) -var spacesCache = strings.Repeat(" ", 100) - func Gen(genReq *plugin.CodeGeneratorRequest) (*plugin.CodeGeneratorResponse, error) { var pkgPath, pkgName string if genReq.Parameter == nil { @@ -94,7 +93,7 @@ func Gen(genReq *plugin.CodeGeneratorRequest) (*plugin.CodeGeneratorResponse, er if err := g.genExampleFile(s, pkgName); err != nil { return nil, errors.E(err, "example: %s", s.GetName()) } - g.imports[importSpec{path: pkgPath}] = true + g.imports[pbinfo.ImportSpec{Path: pkgPath}] = true g.commit(outFile+"_client_example_test.go", pkgName+"_test") } @@ -106,7 +105,7 @@ func Gen(genReq *plugin.CodeGeneratorRequest) (*plugin.CodeGeneratorResponse, er g.genDocFile(pkgPath, pkgName, time.Now().Year(), scopes) g.resp.File = append(g.resp.File, &plugin.CodeGeneratorResponse_File{ Name: proto.String(filepath.Join(outDir, "doc.go")), - Content: proto.String(g.sb.String()), + Content: proto.String(g.pt.String()), }) return &g.resp, nil @@ -122,52 +121,28 @@ func strContains(a []string, s string) bool { } type generator struct { - sb strings.Builder - - // current indentation level - in int - - resp plugin.CodeGeneratorResponse - - // Maps services and messages to the file containing them, - // so we can figure out the import. - parentFile map[proto.Message]*descriptor.FileDescriptorProto + pt printer.P - // Maps type names to their messages - types map[string]*descriptor.DescriptorProto + descInfo pbinfo.Info // Maps proto elements to their comments comments map[proto.Message]string - imports map[importSpec]bool + resp plugin.CodeGeneratorResponse + + imports map[pbinfo.ImportSpec]bool // Human-readable name of the API used in docs apiName string } func (g *generator) init(files []*descriptor.FileDescriptorProto) { - g.parentFile = map[proto.Message]*descriptor.FileDescriptorProto{} - g.types = map[string]*descriptor.DescriptorProto{} + g.descInfo = pbinfo.Of(files) + g.comments = map[proto.Message]string{} - g.imports = map[importSpec]bool{} + g.imports = map[pbinfo.ImportSpec]bool{} for _, f := range files { - // parentFile - for _, m := range f.MessageType { - g.parentFile[m] = f - } - for _, s := range f.Service { - g.parentFile[s] = f - } - - // types - for _, m := range f.MessageType { - // In descriptors, putting the dot in front means the name is fully-qualified. - fullyQualifiedName := fmt.Sprintf(".%s.%s", f.GetPackage(), m.GetName()) - g.types[fullyQualifiedName] = m - } - - // comment for _, loc := range f.GetSourceCodeInfo().GetLocation() { // p is an array with format [f1, i1, f2, i2, ...] // - f1 refers to the protobuf field tag @@ -188,38 +163,6 @@ func (g *generator) init(files []*descriptor.FileDescriptorProto) { } } -// importSpec reports the importSpec for package containing protobuf element e. -func (g *generator) importSpec(e proto.Message) (importSpec, error) { - fdesc := g.parentFile[e] - - pkg := fdesc.GetOptions().GetGoPackage() - if pkg == "" { - var eTxt interface{} = e - if et, ok := eTxt.(interface{ GetName() string }); ok { - eTxt = et.GetName() - } - return importSpec{}, errors.E(nil, "can't determine import path for %v, file %q missing `option go_package`", eTxt, fdesc.GetName()) - } - - if p := strings.IndexByte(pkg, ';'); p >= 0 { - return importSpec{path: pkg[:p], name: pkg[p+1:] + "pb"}, nil - } - - for { - p := strings.LastIndexByte(pkg, '/') - if p < 0 { - return importSpec{path: pkg, name: pkg + "pb"}, nil - } - elem := pkg[p+1:] - if len(elem) >= 2 && elem[0] == 'v' && elem[1] >= '0' && elem[1] <= '9' { - // It's a version number; skip so we get a more meaningful name - pkg = pkg[:p] - continue - } - return importSpec{path: pkg, name: elem + "pb"}, nil - } -} - // printf formatted-prints to sb, using the print syntax from fmt package. // // It automatically keeps track of indentation caused by curly-braces. @@ -230,29 +173,7 @@ func (g *generator) importSpec(e proto.Message) (importSpec, error) { // Currently it's not terribly difficult to confuse the auto-indenter. // To fix-up, manipulate g.in or write to g.sb directly. func (g *generator) printf(s string, a ...interface{}) { - s = strings.TrimSpace(s) - if s == "" { - g.sb.WriteByte('\n') - return - } - - for i := 0; i < len(s) && s[i] == '}'; i++ { - g.in-- - } - - in := g.in - for in > len(tabsCache) { - g.sb.WriteString(tabsCache) - in -= len(tabsCache) - } - g.sb.WriteString(tabsCache[:in]) - - fmt.Fprintf(&g.sb, s, a...) - g.sb.WriteByte('\n') - - for i := len(s) - 1; i >= 0 && s[i] == '{'; i-- { - g.in++ - } + g.pt.Printf(s, a...) } func (g *generator) commit(fileName, pkgName string) { @@ -260,18 +181,18 @@ func (g *generator) commit(fileName, pkgName string) { fmt.Fprintf(&header, apacheLicense, time.Now().Year()) fmt.Fprintf(&header, "package %s\n\n", pkgName) - var imps []importSpec + var imps []pbinfo.ImportSpec for imp := range g.imports { imps = append(imps, imp) } impDiv := sortImports(imps) - writeImp := func(is importSpec) { + writeImp := func(is pbinfo.ImportSpec) { s := "\t%[2]q\n" - if is.name != "" { + if is.Name != "" { s = "\t%s %q\n" } - fmt.Fprintf(&header, s, is.name, is.path) + fmt.Fprintf(&header, s, is.Name, is.Path) } header.WriteString("import (\n") @@ -294,7 +215,7 @@ func (g *generator) commit(fileName, pkgName string) { // Trim trailing newlines so we have only one. // NOTE(pongad): This might be an overkill since we have gofmt, // but the rest of the file already conforms to gofmt, so we might as well? - body := g.sb.String() + body := g.pt.String() if !strings.HasSuffix(body, "\n") { body += "\n" } @@ -311,8 +232,7 @@ func (g *generator) commit(fileName, pkgName string) { } func (g *generator) reset() { - g.sb.Reset() - g.in = 0 + g.pt.Reset() for k := range g.imports { delete(g.imports, k) } @@ -406,14 +326,14 @@ func (g *generator) genMethod(servName string, serv *descriptor.ServiceDescripto } func (g *generator) unaryCall(servName string, m *descriptor.MethodDescriptorProto) error { - inType := g.types[*m.InputType] - outType := g.types[*m.OutputType] + inType := g.descInfo.Type[*m.InputType] + outType := g.descInfo.Type[*m.OutputType] - inSpec, err := g.importSpec(inType) + inSpec, err := g.descInfo.ImportSpec(inType) if err != nil { return err } - outSpec, err := g.importSpec(outType) + outSpec, err := g.descInfo.ImportSpec(outType) if err != nil { return err } @@ -421,11 +341,11 @@ func (g *generator) unaryCall(servName string, m *descriptor.MethodDescriptorPro p := g.printf p("func (c *%sClient) %s(ctx context.Context, req *%s.%s, opts ...gax.CallOption) (*%s.%s, error) {", - servName, *m.Name, inSpec.name, *inType.Name, outSpec.name, *outType.Name) + servName, *m.Name, inSpec.Name, *inType.Name, outSpec.Name, *outType.Name) g.insertMetadata() g.appendCallOpts(m) - p("var resp *%s.%s", outSpec.name, *outType.Name) + p("var resp *%s.%s", outSpec.Name, *outType.Name) p("err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {") p(" var err error") p(" resp, err = %s", grpcClientCall(servName, *m.Name)) @@ -446,9 +366,9 @@ func (g *generator) unaryCall(servName string, m *descriptor.MethodDescriptorPro } func (g *generator) emptyUnaryCall(servName string, m *descriptor.MethodDescriptorProto) error { - inType := g.types[*m.InputType] + inType := g.descInfo.Type[*m.InputType] - inSpec, err := g.importSpec(inType) + inSpec, err := g.descInfo.ImportSpec(inType) if err != nil { return err } @@ -456,7 +376,7 @@ func (g *generator) emptyUnaryCall(servName string, m *descriptor.MethodDescript p := g.printf p("func (c *%sClient) %s(ctx context.Context, req *%s.%s, opts ...gax.CallOption) error {", - servName, m.GetName(), inSpec.name, inType.GetName()) + servName, m.GetName(), inSpec.Name, inType.GetName()) g.insertMetadata() g.appendCallOpts(m) @@ -513,13 +433,6 @@ func (g *generator) comment(s string) { } } -func spaces(n int) string { - if n > len(spacesCache) { - return strings.Repeat(" ", n) - } - return spacesCache[:n] -} - // reduceServName removes redundant components from the service name. // For example, FooServiceV2 -> Foo. // The returned name is used as part of longer names, like FooClient. diff --git a/gengapic/gengapic_test.go b/gengapic/gengapic_test.go index 57c5955ab63..22bdad20730 100644 --- a/gengapic/gengapic_test.go +++ b/gengapic/gengapic_test.go @@ -20,6 +20,7 @@ import ( "github.com/golang/protobuf/proto" "github.com/golang/protobuf/protoc-gen-go/descriptor" + "github.com/googleapis/gapic-generator-go/internal/pbinfo" ) func TestComment(t *testing.T) { @@ -37,9 +38,9 @@ func TestComment(t *testing.T) { want: "// abc\n// def\n", }, } { - g.sb.Reset() + g.pt.Reset() g.comment(tst.in) - if got := g.sb.String(); got != tst.want { + if got := g.pt.String(); got != tst.want { t.Errorf("comment(%q) = %q, want %q", tst.in, got, tst.want) } } @@ -66,9 +67,9 @@ func TestMethodDoc(t *testing.T) { }, } { g.comments[m] = tst.in - g.sb.Reset() + g.pt.Reset() g.methodDoc(m) - if got := g.sb.String(); got != tst.want { + if got := g.pt.String(); got != tst.want { t.Errorf("comment(%q) = %q, want %q", tst.in, got, tst.want) } } @@ -168,16 +169,16 @@ func TestGenMethod(t *testing.T) { serv := &descriptor.ServiceDescriptorProto{} var g generator - g.imports = map[importSpec]bool{} + g.imports = map[pbinfo.ImportSpec]bool{} commonTypes(&g) for _, typ := range []*descriptor.DescriptorProto{ inputType, outputType, pageInputType, pageOutputType, } { - g.types[".my.pkg."+*typ.Name] = typ - g.parentFile[typ] = file + g.descInfo.Type[".my.pkg."+*typ.Name] = typ + g.descInfo.ParentFile[typ] = file } - g.parentFile[serv] = file + g.descInfo.ParentFile[serv] = file meths := []*descriptor.MethodDescriptorProto{ { @@ -216,7 +217,7 @@ func TestGenMethod(t *testing.T) { if err := g.genMethod("Foo", serv, m, &aux); err != nil { t.Error(err) } else { - diff(t, m.GetName(), g.sb.String(), filepath.Join("testdata", "method_"+m.GetName()+".want")) + diff(t, m.GetName(), g.pt.String(), filepath.Join("testdata", "method_"+m.GetName()+".want")) } } } diff --git a/gengapic/imports.go b/gengapic/imports.go index 791b05c21e2..18afb8a465b 100644 --- a/gengapic/imports.go +++ b/gengapic/imports.go @@ -17,30 +17,28 @@ package gengapic import ( "sort" "strings" -) -type importSpec struct { - name, path string -} + "github.com/googleapis/gapic-generator-go/internal/pbinfo" +) // sortImports sorts the import specs, // and returns the index of the first non-standard import. -func sortImports(a []importSpec) int { +func sortImports(a []pbinfo.ImportSpec) int { sort.Slice(a, func(i, j int) bool { - iDot := strings.IndexByte(a[i].path, '.') >= 0 - jDot := strings.IndexByte(a[j].path, '.') >= 0 + iDot := strings.IndexByte(a[i].Path, '.') >= 0 + jDot := strings.IndexByte(a[j].Path, '.') >= 0 // standard import (without dots) comes first if iDot != jDot { return jDot } - if a[i].path != a[j].path { - return a[i].path < a[j].path + if a[i].Path != a[j].Path { + return a[i].Path < a[j].Path } - return a[i].name < a[j].name + return a[i].Name < a[j].Name }) return sort.Search(len(a), func(i int) bool { - return strings.IndexByte(a[i].path, '.') >= 0 + return strings.IndexByte(a[i].Path, '.') >= 0 }) } diff --git a/gengapic/lro.go b/gengapic/lro.go index ee471bd1112..5e1769fdc5f 100644 --- a/gengapic/lro.go +++ b/gengapic/lro.go @@ -14,18 +14,21 @@ package gengapic -import "github.com/golang/protobuf/protoc-gen-go/descriptor" +import ( + "github.com/golang/protobuf/protoc-gen-go/descriptor" + "github.com/googleapis/gapic-generator-go/internal/pbinfo" +) func (g *generator) lroCall(servName string, m *descriptor.MethodDescriptorProto) error { - inType := g.types[m.GetInputType()] - outType := g.types[m.GetOutputType()] + inType := g.descInfo.Type[m.GetInputType()] + outType := g.descInfo.Type[m.GetOutputType()] - inSpec, err := g.importSpec(inType) + inSpec, err := g.descInfo.ImportSpec(inType) if err != nil { return err } - outSpec, err := g.importSpec(outType) + outSpec, err := g.descInfo.ImportSpec(outType) if err != nil { return err } @@ -34,11 +37,11 @@ func (g *generator) lroCall(servName string, m *descriptor.MethodDescriptorProto p := g.printf p("func (c *%sClient) %s(ctx context.Context, req *%s.%s, opts ...gax.CallOption) (*%s, error) {", - servName, *m.Name, inSpec.name, *inType.Name, lroType) + servName, *m.Name, inSpec.Name, *inType.Name, lroType) g.insertMetadata() g.appendCallOpts(m) - p(" var resp *%s.%s", outSpec.name, *outType.Name) + p(" var resp *%s.%s", outSpec.Name, *outType.Name) p(" err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {") p(" var err error") p(" resp, err = %s", grpcClientCall(servName, *m.Name)) @@ -54,7 +57,7 @@ func (g *generator) lroCall(servName string, m *descriptor.MethodDescriptorProto p("}") p("") - g.imports[importSpec{path: "cloud.google.com/go/longrunning"}] = true + g.imports[pbinfo.ImportSpec{Path: "cloud.google.com/go/longrunning"}] = true g.imports[inSpec] = true g.imports[outSpec] = true return nil @@ -89,7 +92,7 @@ func (g *generator) lroType(servName string, m *descriptor.MethodDescriptorProto p("}") p("") - g.imports[importSpec{name: "longrunningpb", path: "google.golang.org/genproto/googleapis/longrunning"}] = true + g.imports[pbinfo.ImportSpec{Name: "longrunningpb", Path: "google.golang.org/genproto/googleapis/longrunning"}] = true } // Wait @@ -106,7 +109,7 @@ func (g *generator) lroType(servName string, m *descriptor.MethodDescriptorProto p("}") p("") - g.imports[importSpec{path: "time"}] = true + g.imports[pbinfo.ImportSpec{Path: "time"}] = true } // Poll diff --git a/gengapic/paging.go b/gengapic/paging.go index cc070c7a0ad..f3e9e1a899e 100644 --- a/gengapic/paging.go +++ b/gengapic/paging.go @@ -20,6 +20,7 @@ import ( "github.com/golang/protobuf/protoc-gen-go/descriptor" "github.com/googleapis/gapic-generator-go/internal/errors" + "github.com/googleapis/gapic-generator-go/internal/pbinfo" ) var primitiveFieldToGoType = [...]string{ @@ -44,9 +45,9 @@ var primitiveFieldToGoType = [...]string{ type iterType struct { iterTypeName, elemTypeName string - // If the elem type is a message, elemImports contains importSpec for the type. + // If the elem type is a message, elemImports contains pbinfo.ImportSpec for the type. // Otherwise, len(elemImports)==0. - elemImports []importSpec + elemImports []pbinfo.ImportSpec } // iterTypeOf deduces iterType from a field to be iterated over. @@ -56,17 +57,17 @@ func (g *generator) iterTypeOf(elemField *descriptor.FieldDescriptorProto) (iter switch t := *elemField.Type; { case t == descriptor.FieldDescriptorProto_TYPE_MESSAGE: - eType := g.types[elemField.GetTypeName()] + eType := g.descInfo.Type[elemField.GetTypeName()] - imp, err := g.importSpec(eType) + imp, err := g.descInfo.ImportSpec(eType) if err != nil { return iterType{}, err } - pt.elemTypeName = fmt.Sprintf("*%s.%s", imp.name, eType.GetName()) + pt.elemTypeName = fmt.Sprintf("*%s.%s", imp.Name, eType.GetName()) pt.iterTypeName = *eType.Name + "Iterator" - pt.elemImports = []importSpec{imp} + pt.elemImports = []pbinfo.ImportSpec{imp} case t == descriptor.FieldDescriptorProto_TYPE_ENUM: log.Panic("iterating enum not supported yet") @@ -96,11 +97,11 @@ func (g *generator) pagingField(m *descriptor.MethodDescriptorProto) (*descripto elemFields []*descriptor.FieldDescriptorProto ) - inType := g.types[m.GetInputType()] + inType := g.descInfo.Type[m.GetInputType()] if inType == nil { return nil, errors.E(nil, "cannot find message type %q, malformed descriptor?", m.GetInputType()) } - outType := g.types[m.GetOutputType()] + outType := g.descInfo.Type[m.GetOutputType()] if outType == nil { return nil, errors.E(nil, "cannot find message type %q, malformed descriptor?", m.GetOutputType()) } @@ -134,29 +135,29 @@ func (g *generator) pagingField(m *descriptor.MethodDescriptorProto) (*descripto } func (g *generator) pagingCall(servName string, m *descriptor.MethodDescriptorProto, elemField *descriptor.FieldDescriptorProto, pt iterType) error { - inType := g.types[*m.InputType] - outType := g.types[*m.OutputType] + inType := g.descInfo.Type[*m.InputType] + outType := g.descInfo.Type[*m.OutputType] - inSpec, err := g.importSpec(inType) + inSpec, err := g.descInfo.ImportSpec(inType) if err != nil { return err } - outSpec, err := g.importSpec(outType) + outSpec, err := g.descInfo.ImportSpec(outType) if err != nil { return err } p := g.printf p("func (c *%sClient) %s(ctx context.Context, req *%s.%s, opts ...gax.CallOption) *%s {", - servName, *m.Name, inSpec.name, *inType.Name, pt.iterTypeName) + servName, *m.Name, inSpec.Name, *inType.Name, pt.iterTypeName) g.insertMetadata() g.appendCallOpts(m) p("it := &%s{}", pt.iterTypeName) - p("req = proto.Clone(req).(*%s.%s)", inSpec.name, *inType.Name) + p("req = proto.Clone(req).(*%s.%s)", inSpec.Name, *inType.Name) p("it.InternalFetch = func(pageSize int, pageToken string) ([]%s, string, error) {", pt.elemTypeName) - p(" var resp *%s.%s", outSpec.name, *outType.Name) + p(" var resp *%s.%s", outSpec.Name, *outType.Name) p(" req.PageToken = pageToken") p(" if pageSize > math.MaxInt32 {") p(" req.PageSize = math.MaxInt32") @@ -190,9 +191,9 @@ func (g *generator) pagingCall(servName string, m *descriptor.MethodDescriptorPr p("}") p("") - g.imports[importSpec{path: "math"}] = true - g.imports[importSpec{path: "github.com/golang/protobuf/proto"}] = true - g.imports[importSpec{path: "google.golang.org/api/iterator"}] = true + g.imports[pbinfo.ImportSpec{Path: "math"}] = true + g.imports[pbinfo.ImportSpec{Path: "github.com/golang/protobuf/proto"}] = true + g.imports[pbinfo.ImportSpec{Path: "google.golang.org/api/iterator"}] = true g.imports[inSpec] = true g.imports[outSpec] = true for _, spec := range pt.elemImports { diff --git a/gengapic/paging_test.go b/gengapic/paging_test.go index f176f2c1869..62a2906f98a 100644 --- a/gengapic/paging_test.go +++ b/gengapic/paging_test.go @@ -20,6 +20,7 @@ import ( "github.com/golang/protobuf/proto" "github.com/golang/protobuf/protoc-gen-go/descriptor" "github.com/google/go-cmp/cmp" + "github.com/googleapis/gapic-generator-go/internal/pbinfo" ) func TestPagingField(t *testing.T) { @@ -36,60 +37,59 @@ func TestPagingField(t *testing.T) { Label: labelp(descriptor.FieldDescriptorProto_LABEL_REPEATED), } - g := &generator{ - types: map[string]*descriptor.DescriptorProto{ - "Foo": &descriptor.DescriptorProto{ - Name: proto.String("Foo"), - }, - "PageIn": &descriptor.DescriptorProto{ - Name: proto.String("PageIn"), - Field: []*descriptor.FieldDescriptorProto{ - { - Name: proto.String("page_size"), - Type: typep(descriptor.FieldDescriptorProto_TYPE_INT32), - Label: labelp(descriptor.FieldDescriptorProto_LABEL_OPTIONAL), - }, - { - Name: proto.String("page_token"), - Type: typep(descriptor.FieldDescriptorProto_TYPE_STRING), - Label: labelp(descriptor.FieldDescriptorProto_LABEL_OPTIONAL), - }, + g := &generator{} + g.descInfo.Type = map[string]*descriptor.DescriptorProto{ + "Foo": &descriptor.DescriptorProto{ + Name: proto.String("Foo"), + }, + "PageIn": &descriptor.DescriptorProto{ + Name: proto.String("PageIn"), + Field: []*descriptor.FieldDescriptorProto{ + { + Name: proto.String("page_size"), + Type: typep(descriptor.FieldDescriptorProto_TYPE_INT32), + Label: labelp(descriptor.FieldDescriptorProto_LABEL_OPTIONAL), + }, + { + Name: proto.String("page_token"), + Type: typep(descriptor.FieldDescriptorProto_TYPE_STRING), + Label: labelp(descriptor.FieldDescriptorProto_LABEL_OPTIONAL), }, }, - "PageOut": &descriptor.DescriptorProto{ - Name: proto.String("PageOut"), - Field: []*descriptor.FieldDescriptorProto{ - { - Name: proto.String("next_page_token"), - Type: typep(descriptor.FieldDescriptorProto_TYPE_STRING), - Label: labelp(descriptor.FieldDescriptorProto_LABEL_OPTIONAL), - }, - resField, + }, + "PageOut": &descriptor.DescriptorProto{ + Name: proto.String("PageOut"), + Field: []*descriptor.FieldDescriptorProto{ + { + Name: proto.String("next_page_token"), + Type: typep(descriptor.FieldDescriptorProto_TYPE_STRING), + Label: labelp(descriptor.FieldDescriptorProto_LABEL_OPTIONAL), }, + resField, }, - "BadPageOut1": &descriptor.DescriptorProto{ - Name: proto.String("BadPageOut1"), - Field: []*descriptor.FieldDescriptorProto{ - { - Name: proto.String("next_page_token"), - Type: typep(descriptor.FieldDescriptorProto_TYPE_STRING), - Label: labelp(descriptor.FieldDescriptorProto_LABEL_OPTIONAL), - }, - // No repeated field + }, + "BadPageOut1": &descriptor.DescriptorProto{ + Name: proto.String("BadPageOut1"), + Field: []*descriptor.FieldDescriptorProto{ + { + Name: proto.String("next_page_token"), + Type: typep(descriptor.FieldDescriptorProto_TYPE_STRING), + Label: labelp(descriptor.FieldDescriptorProto_LABEL_OPTIONAL), }, + // No repeated field }, - "BadPageOut2": &descriptor.DescriptorProto{ - Name: proto.String("BadPageOut2"), - Field: []*descriptor.FieldDescriptorProto{ - { - Name: proto.String("next_page_token"), - Type: typep(descriptor.FieldDescriptorProto_TYPE_STRING), - Label: labelp(descriptor.FieldDescriptorProto_LABEL_OPTIONAL), - }, - // Too many repeated field - resField, - resField, + }, + "BadPageOut2": &descriptor.DescriptorProto{ + Name: proto.String("BadPageOut2"), + Field: []*descriptor.FieldDescriptorProto{ + { + Name: proto.String("next_page_token"), + Type: typep(descriptor.FieldDescriptorProto_TYPE_STRING), + Label: labelp(descriptor.FieldDescriptorProto_LABEL_OPTIONAL), }, + // Too many repeated field + resField, + resField, }, }, } @@ -151,13 +151,15 @@ func TestIterTypeOf(t *testing.T) { Name: proto.String("Foo"), } g := &generator{ - types: map[string]*descriptor.DescriptorProto{ - *msgType.Name: msgType, - }, - parentFile: map[proto.Message]*descriptor.FileDescriptorProto{ - msgType: &descriptor.FileDescriptorProto{ - Options: &descriptor.FileOptions{ - GoPackage: proto.String("path/to/foo;foo"), + descInfo: pbinfo.Info{ + Type: map[string]*descriptor.DescriptorProto{ + *msgType.Name: msgType, + }, + ParentFile: map[proto.Message]*descriptor.FileDescriptorProto{ + msgType: &descriptor.FileDescriptorProto{ + Options: &descriptor.FileOptions{ + GoPackage: proto.String("path/to/foo;foo"), + }, }, }, }, @@ -193,14 +195,14 @@ func TestIterTypeOf(t *testing.T) { want: iterType{ iterTypeName: "FooIterator", elemTypeName: "*foopb.Foo", - elemImports: []importSpec{{name: "foopb", path: "path/to/foo"}}, + elemImports: []pbinfo.ImportSpec{{Name: "foopb", Path: "path/to/foo"}}, }, }, } { got, err := g.iterTypeOf(tst.field) if err != nil { t.Error(err) - } else if diff := cmp.Diff(tst.want, got, cmp.AllowUnexported(got, importSpec{})); diff != "" { + } else if diff := cmp.Diff(tst.want, got, cmp.AllowUnexported(got, pbinfo.ImportSpec{})); diff != "" { t.Errorf("%d: (got=-, want=+):\n%s", i, diff) } } diff --git a/gengapic/stream.go b/gengapic/stream.go index 3a6c51bb50b..5f9ed9f9e55 100644 --- a/gengapic/stream.go +++ b/gengapic/stream.go @@ -19,17 +19,17 @@ import "github.com/golang/protobuf/protoc-gen-go/descriptor" func (g *generator) bidiCall(servName string, s *descriptor.ServiceDescriptorProto, m *descriptor.MethodDescriptorProto) error { p := g.printf - servSpec, err := g.importSpec(s) + servSpec, err := g.descInfo.ImportSpec(s) if err != nil { return err } g.imports[servSpec] = true p("func (c *%sClient) %s(ctx context.Context, opts ...gax.CallOption) (%s.%s_%sClient, error) {", - servName, m.GetName(), servSpec.name, s.GetName(), m.GetName()) + servName, m.GetName(), servSpec.Name, s.GetName(), m.GetName()) g.insertMetadata() g.appendCallOpts(m) - p(" var resp %s.%s_%sClient", servSpec.name, s.GetName(), m.GetName()) + p(" var resp %s.%s_%sClient", servSpec.Name, s.GetName(), m.GetName()) p(" err := gax.Invoke(ctx, func(ctx context.Context, settings gax.CallSettings) error {") p(" var err error") diff --git a/internal/printer/printer.go b/internal/printer/printer.go index 42dbee2a56d..37a7d7d97e4 100644 --- a/internal/printer/printer.go +++ b/internal/printer/printer.go @@ -69,3 +69,7 @@ func (p *P) Printf(s string, args ...interface{}) { func (p *P) Bytes() []byte { return p.buf.Bytes() } + +func (p *P) String() string { + return p.buf.String() +}