From f01db539b7ea359dbe4e5cbb71c0ff39e5fca6d0 Mon Sep 17 00:00:00 2001 From: Julie Qiu Date: Sun, 3 Nov 2024 21:18:08 -0500 Subject: [PATCH] impl: simplify protobuf translator --- generator/cmd/protoc-gen-gclient/main.go | 5 +- .../genclient/translator/protobuf/protobuf.go | 122 ++++++++---------- 2 files changed, 55 insertions(+), 72 deletions(-) diff --git a/generator/cmd/protoc-gen-gclient/main.go b/generator/cmd/protoc-gen-gclient/main.go index cc21e5c62..8ae62d76a 100644 --- a/generator/cmd/protoc-gen-gclient/main.go +++ b/generator/cmd/protoc-gen-gclient/main.go @@ -84,12 +84,11 @@ func run(inputPath, outDir, templateDir string) error { } } - req, err := protobuf.NewTranslator(&protobuf.Options{ - Request: genReq, + req, err := protobuf.Translate(genReq, &protobuf.Options{ OutDir: outDir, Language: opts.Language, TemplateDir: templateDir, - }).Translate() + }) if err != nil { return err } diff --git a/generator/internal/genclient/translator/protobuf/protobuf.go b/generator/internal/genclient/translator/protobuf/protobuf.go index d7eecc531..e1f299844 100644 --- a/generator/internal/genclient/translator/protobuf/protobuf.go +++ b/generator/internal/genclient/translator/protobuf/protobuf.go @@ -15,6 +15,7 @@ package protobuf import ( + "fmt" "log/slog" "strings" @@ -25,47 +26,26 @@ import ( "google.golang.org/protobuf/types/pluginpb" ) -type Translator struct { - request *pluginpb.CodeGeneratorRequest - language string - - // Only used for local testing - outDir string - templateDir string - - // State by FQN - state *genclient.APIState -} - type Options struct { - Request *pluginpb.CodeGeneratorRequest Language string // Only used for local testing OutDir string TemplateDir string } -func NewTranslator(opts *Options) *Translator { - return &Translator{ - outDir: opts.OutDir, - request: opts.Request, - language: opts.Language, - templateDir: opts.TemplateDir, - state: &genclient.APIState{ - ServiceByID: make(map[string]*genclient.Service), - MessageByID: make(map[string]*genclient.Message), - EnumByID: make(map[string]*genclient.Enum), - }, +// Translate translates proto representation into a [genclienGenerateRequest]. +func Translate(req *pluginpb.CodeGeneratorRequest, opts *Options) (*genclient.GenerateRequest, error) { + state := &genclient.APIState{ + ServiceByID: make(map[string]*genclient.Service), + MessageByID: make(map[string]*genclient.Message), + EnumByID: make(map[string]*genclient.Enum), } -} -// Translates proto representation into a [genclient.GenerateRequest]. -func (t *Translator) Translate() (*genclient.GenerateRequest, error) { api := &genclient.API{ //TODO(codyoss): https://github.com/googleapis/google-cloud-rust/issues/38 Name: "secretmanager", } - files := t.request.GetSourceFileDescriptors() + files := req.GetSourceFileDescriptors() for _, f := range files { var fileServices []*genclient.Service fFQN := "." + f.GetPackage() @@ -73,18 +53,18 @@ func (t *Translator) Translate() (*genclient.GenerateRequest, error) { // Messages for _, m := range f.MessageType { mFQN := fFQN + "." + m.GetName() - msg := t.processMessage(m, mFQN, nil) + msg := processMessage(state, m, mFQN, nil) api.Messages = append(api.Messages, msg) } // Services for _, s := range f.Service { - service := &genclient.Service{} - sFQN := fFQN + "." + s.GetName() - t.state.ServiceByID[sFQN] = service - service.Name = s.GetName() - service.ID = sFQN - service.DefaultHost = parseDefaultHost(s.GetOptions()) + service := &genclient.Service{ + Name: s.GetName(), + ID: fmt.Sprintf("%s.%s", fFQN, s.GetName()), + DefaultHost: parseDefaultHost(s.GetOptions()), + } + state.ServiceByID[service.ID] = service for _, m := range s.Method { method := &genclient.Method{} method.HTTPInfo = parseHTTPInfo(m.GetOptions()) @@ -111,10 +91,11 @@ func (t *Translator) Translate() (*genclient.GenerateRequest, error) { // Because of message nesting we need to call recursively and // strip out parts of the path. m := f.MessageType[p[1]] - t.addMessageDocumentation(m, p[2:], strings.TrimSpace(loc.GetLeadingComments()), fFQN+"."+m.GetName()) + addMessageDocumentation(state, m, p[2:], strings.TrimSpace(loc.GetLeadingComments()), fFQN+"."+m.GetName()) case 6: sFQN := fFQN + "." + f.GetService()[p[1]].GetName() - t.addServiceDocumentation(p[2:], strings.TrimSpace(loc.GetLeadingComments()), sFQN) + addServiceDocumentation(state, p[2:], + strings.TrimSpace(loc.GetLeadingComments()), sFQN) default: slog.Warn("file dropped documentation", "loc", p, "docs", loc.GetLeadingComments()) } @@ -122,16 +103,16 @@ func (t *Translator) Translate() (*genclient.GenerateRequest, error) { api.Services = append(api.Services, fileServices...) } - codec, err := language.NewCodec(t.language) + codec, err := language.NewCodec(opts.Language) if err != nil { return nil, err } - api.State = t.state + api.State = state return &genclient.GenerateRequest{ API: api, Codec: codec, - OutDir: t.outDir, - TemplateDir: t.templateDir, + OutDir: opts.OutDir, + TemplateDir: opts.TemplateDir, }, nil } @@ -190,24 +171,25 @@ func normalizeTypes(in *descriptorpb.FieldDescriptorProto, field *genclient.Fiel } } -func (t *Translator) processMessage(m *descriptorpb.DescriptorProto, mFQN string, parent *genclient.Message) *genclient.Message { - message := &genclient.Message{} - t.state.MessageByID[mFQN] = message - message.Name = m.GetName() - message.ID = mFQN - message.Parent = parent +func processMessage(state *genclient.APIState, m *descriptorpb.DescriptorProto, mFQN string, parent *genclient.Message) *genclient.Message { + message := &genclient.Message{ + Name: m.GetName(), + ID: mFQN, + Parent: parent, + } + state.MessageByID[mFQN] = message if opts := m.GetOptions(); opts != nil && opts.GetMapEntry() { message.IsMap = true } if len(m.GetNestedType()) > 0 { for _, nm := range m.GetNestedType() { nmFQN := mFQN + "." + nm.GetName() - nmsg := t.processMessage(nm, nmFQN, message) + nmsg := processMessage(state, nm, nmFQN, message) message.Messages = append(message.Messages, nmsg) } } for _, e := range m.GetEnumType() { - e := t.processEnum(e, mFQN, message) + e := processEnum(state, e, mFQN, message) message.Enums = append(message.Enums, e) } // TODO(codyoss): https://github.com/googleapis/google-cloud-rust/issues/39 @@ -222,55 +204,57 @@ func (t *Translator) processMessage(m *descriptorpb.DescriptorProto, mFQN string return message } -func (t *Translator) processEnum(e *descriptorpb.EnumDescriptorProto, baseFQN string, parent *genclient.Message) *genclient.Enum { - enum := &genclient.Enum{} - t.state.EnumByID[baseFQN+"."+e.GetName()] = enum - enum.Name = e.GetName() - enum.Parent = parent +func processEnum(state *genclient.APIState, e *descriptorpb.EnumDescriptorProto, baseFQN string, parent *genclient.Message) *genclient.Enum { + enum := &genclient.Enum{ + Name: e.GetName(), + Parent: parent, + } + state.EnumByID[baseFQN+"."+e.GetName()] = enum for _, ev := range e.Value { - enumValue := &genclient.EnumValue{} - enumValue.Name = ev.GetName() - enumValue.Number = ev.GetNumber() - enumValue.Parent = enum + enumValue := &genclient.EnumValue{ + Name: ev.GetName(), + Number: ev.GetNumber(), + Parent: enum, + } enum.Values = append(enum.Values, enumValue) } return enum } -func (t *Translator) addServiceDocumentation(p []int32, doc string, sFQN string) { +func addServiceDocumentation(state *genclient.APIState, p []int32, doc string, sFQN string) { // These magic numbers come from reading the proto docs. They come // from field numbers of the different descriptor types. See struct // tags on https://pkg.go.dev/google.golang.org/protobuf/types/descriptorpb#ServiceDescriptorProto. if len(p) == 0 { // This is a comment for a service - t.state.ServiceByID[sFQN].Documentation = doc + state.ServiceByID[sFQN].Documentation = doc } else if len(p) == 2 && p[0] == 2 { // This is a comment for a method - t.state.ServiceByID[sFQN].Methods[p[1]].Documentation = doc + state.ServiceByID[sFQN].Methods[p[1]].Documentation = doc } else { slog.Warn("service dropped documentation", "loc", p, "docs", doc) } } -func (t *Translator) addMessageDocumentation(m *descriptorpb.DescriptorProto, p []int32, doc string, mFQN string) { +func addMessageDocumentation(state *genclient.APIState, m *descriptorpb.DescriptorProto, p []int32, doc string, mFQN string) { // These magic numbers come from reading the proto docs. They come // from field numbers of the different descriptor types. See struct // tags on https://pkg.go.dev/google.golang.org/protobuf/types/descriptorpb#DescriptorProto. if len(p) == 0 { // This is a comment for a top level message - t.state.MessageByID[mFQN].Documentation = doc + state.MessageByID[mFQN].Documentation = doc } else if p[0] == 3 { // This indicates a nested message, recurse. nmsg := m.GetNestedType()[p[1]] nmFQN := mFQN + "." + nmsg.GetName() - t.addMessageDocumentation(nmsg, p[2:], doc, nmFQN) + addMessageDocumentation(state, nmsg, p[2:], doc, nmFQN) } else if len(p) == 2 && p[0] == 2 { // This is a comment for a field of a message - t.state.MessageByID[mFQN].Fields[p[1]].Documentation = doc + state.MessageByID[mFQN].Fields[p[1]].Documentation = doc } else if p[0] == 4 { // This is a comment for a enum of a message eFQN := mFQN + "." + m.GetEnumType()[p[1]].GetName() - t.addEnumDocumentation(p[2:], doc, eFQN) + addEnumDocumentation(state, p[2:], doc, eFQN) } else if len(p) == 2 && p[0] == 8 { // This is a comment for a field of a message one-of, skipping } else { @@ -279,13 +263,13 @@ func (t *Translator) addMessageDocumentation(m *descriptorpb.DescriptorProto, p } // addEnumDocumentation adds documentation to an enum. -func (t *Translator) addEnumDocumentation(p []int32, doc string, eFQN string) { +func addEnumDocumentation(state *genclient.APIState, p []int32, doc string, eFQN string) { if len(p) == 0 { // This is a comment for an enum - t.state.EnumByID[eFQN].Documentation = doc + state.EnumByID[eFQN].Documentation = doc } else if len(p) == 2 { // This is a comment for an enum value - t.state.EnumByID[eFQN].Values[p[1]].Documentation = doc + state.EnumByID[eFQN].Values[p[1]].Documentation = doc } else { slog.Warn("enum dropped documentation", "loc", p, "docs", doc) }