Skip to content

Commit

Permalink
fix generation process with libprotoc
Browse files Browse the repository at this point in the history
  • Loading branch information
borosr committed Oct 31, 2022
1 parent 4581625 commit 7e4dc73
Show file tree
Hide file tree
Showing 10 changed files with 233 additions and 26 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,8 @@ message TimeTime {}

#### Important

Currently the generator not importing the `time` package automatically. Temporary solution can be: `goimports -w *.pb.go`.
Currently the overwritten FieldOptions (go_type, go_import, go_import_alias) must be paired with these numbers:
go_type = 1001
go_import = 1002
go_import_alias = 1003
Because `protoc` can't process the extended options, so we can't find the by name, just by place.
77 changes: 60 additions & 17 deletions cmd/protoc-gen-go/internal_gengo/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ import (
"github.com/infiniteloopcloud/protoc-gen-go-types/compiler/protogen"
"github.com/infiniteloopcloud/protoc-gen-go-types/internal/encoding/tag"
"github.com/infiniteloopcloud/protoc-gen-go-types/internal/genid"
"github.com/infiniteloopcloud/protoc-gen-go-types/internal/impl"
"github.com/infiniteloopcloud/protoc-gen-go-types/internal/version"
"github.com/infiniteloopcloud/protoc-gen-go-types/log"
"github.com/infiniteloopcloud/protoc-gen-go-types/reflect/protoreflect"
"github.com/infiniteloopcloud/protoc-gen-go-types/runtime/protoimpl"

Expand All @@ -31,10 +33,6 @@ import (
const (
EnvSkipProtobufSpecific = "SKIP_PROTOBUF_SPECIFIC"
EnvTypeOverride = "TYPE_OVERRIDE"

fieldOptionGoType = "go_type"
fieldOptionGoImport = "go_import"
fieldOptionGoImportAlias = "go_import_alias"
)

type overrideParams struct {
Expand All @@ -53,6 +51,8 @@ var SupportedFeatures = uint64(pluginpb.CodeGeneratorResponse_FEATURE_PROTO3_OPT
var GenerateProtobufSpecific = true
var TypeOverride = false

var lookupExtensionNames = []string{"go_type", "go_import", "go_import_alias"}

// Standard library dependencies.
const (
base64Package = protogen.GoImportPath("encoding/base64")
Expand Down Expand Up @@ -93,6 +93,8 @@ func GenerateFile(gen *protogen.Plugin, file *protogen.File) *protogen.Generated
TypeOverride = true
}

log.Log("GenerateFile>> SkipProtobufSpecific:%v | TypeOverride:%v\n", GenerateProtobufSpecific, TypeOverride)

filename := file.GeneratedFilenamePrefix + ".pb.go"
g := gen.NewGeneratedFile(filename, file.GoImportPath)
f := newFileInfo(file)
Expand All @@ -119,6 +121,7 @@ func GenerateFile(gen *protogen.Plugin, file *protogen.File) *protogen.Generated
for _, message := range f.allMessages {
buildOverrides(message)
}
log.Log("overrides count: %d\t data: %#v", len(overrideFields), overrideFields)
genOverrideImports(g)
for i, imps := 0, f.Desc.Imports(); i < imps.Len(); i++ {
genImport(gen, g, f, imps.Get(i))
Expand Down Expand Up @@ -159,22 +162,18 @@ func buildOverrides(message *messageInfo) {
return
}

log.Log("processing message: %s", message.Desc.FullName())

for _, field := range message.Fields {
var override overrideParams
for _, o := range field.Desc.Options().(*descriptorpb.FieldOptions).GetUninterpretedOption() {
for _, namePart := range o.Name {
if namePart != nil {
switch namePart.GetNamePart() {
case fieldOptionGoType:
override.goType = string(o.GetStringValue())
case fieldOptionGoImport:
override.goImport = string(o.GetStringValue())
case fieldOptionGoImportAlias:
override.goImportAlias = string(o.GetStringValue())
}
}
}
log.Log("processing field: %s", field.GoName)

if uop, uok := processUninterpretedOptions(field); uok {
override = uop
} else if eop, eok := processExtensions(field); eok {
override = eop
}

if override.goType != "" {
if _, ok := overrideFields[message.GoIdent.GoName]; !ok {
overrideFields[message.GoIdent.GoName] = make(map[string]overrideParams)
Expand All @@ -184,6 +183,50 @@ func buildOverrides(message *messageInfo) {
}
}

func processExtensions(field *protogen.Field) (overrideParams, bool) {
var override overrideParams
var ok bool
for _, ex := range field.Desc.Options().(*descriptorpb.FieldOptions).GetExtensionFields() {
switch string(ex.Type().TypeDescriptor().FullName()) {
case impl.FieldOptionGoType:
override.goType = ex.Value().String()
ok = true
case impl.FieldOptionGoImport:
override.goImport = ex.Value().String()
ok = true
case impl.FieldOptionGoImportAlias:
override.goImportAlias = ex.Value().String()
ok = true
}
}
return override, ok
}

func processUninterpretedOptions(field *protogen.Field) (overrideParams, bool) {
var override overrideParams
var ok bool
for _, o := range field.Desc.Options().(*descriptorpb.FieldOptions).GetUninterpretedOption() {
for _, namePart := range o.Name {
if namePart != nil {
log.Log("message field: %s", namePart.GetNamePart())
switch namePart.GetNamePart() {
case impl.FieldOptionGoType:
override.goType = string(o.GetStringValue())
ok = true
case impl.FieldOptionGoImport:
override.goImport = string(o.GetStringValue())
ok = true
case impl.FieldOptionGoImportAlias:
override.goImportAlias = string(o.GetStringValue())
ok = true
}
}
}
}

return override, ok
}

// genStandaloneComments prints all leading comments for a FileDescriptorProto
// location identified by the field number n.
func genStandaloneComments(g *protogen.GeneratedFile, f *fileInfo, n int32) {
Expand Down
8 changes: 5 additions & 3 deletions cmd/protoc-gen-go/internal_gengo/test_data/config.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ syntax = "proto3";

package proto;

option go_package = ".;proto";

import "google/protobuf/descriptor.proto";

extend google.protobuf.FieldOptions {
optional string go_type = 1000;
optional string go_import = 1001;
optional string go_import_alias = 1002;
optional string go_type = 1001;
optional string go_import = 1002;
optional string go_import_alias = 1003;
}
16 changes: 13 additions & 3 deletions cmd/protoc-gen-go/internal_gengo/test_data/test.proto
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,20 @@ package proto;

option go_package = ".;proto";

import "./test_data/config.proto";
//import "./test_data/config.proto";
// to test with other languages, switch to this import and run
// protoc -I=test_data --java_out=test_data test_data/*.proto
// import "config.proto";
// cd cmd/protoc-gen-go/internal_gengo
// TYPE_OVERRIDE=true DEBUG=true protoc --go_out=test_data -I test_data test_data/test.proto
import "config.proto";

// Or use the following hard coded field option extension
//import "google/protobuf/descriptor.proto";
//
//extend google.protobuf.FieldOptions {
// optional string go_type = 1001;
// optional string go_import = 1002;
// optional string go_import_alias = 1003;
//}

message RepeatedString {
}
Expand Down
10 changes: 10 additions & 0 deletions compiler/protogen/protogen.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/infiniteloopcloud/protoc-gen-go-types/encoding/prototext"
"github.com/infiniteloopcloud/protoc-gen-go-types/internal/genid"
"github.com/infiniteloopcloud/protoc-gen-go-types/internal/strs"
"github.com/infiniteloopcloud/protoc-gen-go-types/log"
"github.com/infiniteloopcloud/protoc-gen-go-types/proto"
"github.com/infiniteloopcloud/protoc-gen-go-types/reflect/protodesc"
"github.com/infiniteloopcloud/protoc-gen-go-types/reflect/protoreflect"
Expand Down Expand Up @@ -63,10 +64,19 @@ func run(opts Options, f func(*Plugin) error) error {
if err != nil {
return err
}
log.Log("\n\nRaw request byte: []byte{")
for i, b := range in {
if i > 0 {
log.Log(", ")
}
log.Log("%d", b)
}
log.Log("}")
req := &pluginpb.CodeGeneratorRequest{}
if err := proto.Unmarshal(in, req); err != nil {
return err
}
log.Log("Unmarshalled Request: %s", req.String())
gen, err := opts.New(req)
if err != nil {
return err
Expand Down
3 changes: 3 additions & 0 deletions compiler/protogen/protogen_input_test.go

Large diffs are not rendered by default.

35 changes: 35 additions & 0 deletions compiler/protogen/protogen_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,3 +344,38 @@ var _ = bar.X
t.Fatalf("content mismatch (-want +got):\n%s", diff)
}
}

func TestUnmarshal(t *testing.T) {
req := &pluginpb.CodeGeneratorRequest{}
err := proto.Unmarshal(unmarshalIn, req)
if err != nil {
t.Fatal(err)
}
var msg *descriptorpb.DescriptorProto
for _, descriptorProto := range req.GetProtoFile() {
if *descriptorProto.Name == "test.proto" {
for _, msgTyp := range descriptorProto.MessageType {
if *msgTyp.Name == "Test" {
msg = msgTyp
}
}
}
}
if msg == nil {
t.Fatal("missing message")
}
for _, f := range msg.GetField() {
extensions := f.Options.GetExtensionFields()
if len(extensions) == 0 {
continue
}
if len(extensions) > 3 {
t.Error("too many extensions")
}
if goType, ok := extensions[1001]; ok {
if goType.Value().String() == "" {
t.Errorf("missing go_type field option, at field %s", *f.Name)
}
}
}
}
56 changes: 54 additions & 2 deletions internal/impl/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,29 @@ package impl

import (
"math/bits"
"reflect"

"github.com/infiniteloopcloud/protoc-gen-go-types/encoding/protowire"
"github.com/infiniteloopcloud/protoc-gen-go-types/internal/errors"
"github.com/infiniteloopcloud/protoc-gen-go-types/internal/filedesc"
"github.com/infiniteloopcloud/protoc-gen-go-types/internal/flags"
"github.com/infiniteloopcloud/protoc-gen-go-types/log"
"github.com/infiniteloopcloud/protoc-gen-go-types/proto"
"github.com/infiniteloopcloud/protoc-gen-go-types/reflect/protoreflect"
"github.com/infiniteloopcloud/protoc-gen-go-types/reflect/protoregistry"
"github.com/infiniteloopcloud/protoc-gen-go-types/runtime/protoiface"
)

const (
FieldOptionGoType = "go_type"
FieldOptionGoImport = "go_import"
FieldOptionGoImportAlias = "go_import_alias"

FieldOptionGoTypeNum = 1001
FieldOptionGoImportNum = 1002
FieldOptionGoImportAliasNum = 1003
)

var errDecode = errors.New("cannot parse invalid wire-format data")
var errRecursionDepth = errors.New("exceeded maximum recursion depth")

Expand Down Expand Up @@ -210,10 +223,12 @@ func (mi *MessageInfo) unmarshalExtension(b []byte, num protowire.Number, wtyp p
if xt == nil {
var err error
xt, err = opts.resolver.FindExtensionByNumber(mi.Desc.FullName(), num)
if err != nil {
if err == protoregistry.NotFound {
if err == protoregistry.NotFound {
xt, err = mi.fallbackCreateExtension(num)
if err != nil {
return out, errUnknown
}
} else if err != nil {
return out, errors.New("%v: unable to resolve extension %v: %v", mi.Desc.FullName(), num, err)
}
}
Expand Down Expand Up @@ -256,6 +271,43 @@ func (mi *MessageInfo) unmarshalExtension(b []byte, num protowire.Number, wtyp p
return out, nil
}

func (mi *MessageInfo) fallbackCreateExtension(num protowire.Number) (protoreflect.ExtensionType, error) {
// FIXME: not the best solution, figure out something later
var name string
switch int32(num) {
case FieldOptionGoTypeNum:
name = FieldOptionGoType
case FieldOptionGoImportNum:
name = FieldOptionGoImport
case FieldOptionGoImportAliasNum:
name = FieldOptionGoImportAlias
default:
return nil, errors.New("invalid name")
}

exInf := &ExtensionInfo{}
xd := &filedesc.Field{
Base: filedesc.Base{
L0: filedesc.BaseL0{
ParentFile: filedesc.SurrogateProto3,
Parent: mi.Desc,
FullName: protoreflect.FullName(name),
},
},
L1: filedesc.FieldL1{
Number: num,
Cardinality: protoreflect.Optional,
Kind: protoreflect.StringKind,
},
}
InitExtensionInfo(exInf, xd, reflect.TypeOf(""))
if err := protoregistry.GlobalTypes.RegisterExtension(exInf); err != nil {
log.Log("GlobalTypes.RegisterExtension::%v", err)
return nil, err
}
return exInf, nil
}

func skipExtension(b []byte, xi *extensionFieldInfo, num protowire.Number, wtyp protowire.Type, opts unmarshalOptions) (out unmarshalOutput, _ ValidationStatus) {
if xi.validation.mi == nil {
return out, ValidationUnknown
Expand Down
36 changes: 36 additions & 0 deletions log/log.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package log

import (
"fmt"
"os"
)

const (
logfilePathEnv = "LOGFILE_PATH"
logEnabled = "DEBUG"
)

var logFilePath = os.Getenv(logfilePathEnv)

var logFile *os.File

func init() {
if os.Getenv(logEnabled) != "true" {
return
}
var err error
if logFilePath == "" {
logFilePath = "/tmp/proto.log"
}
logFile, err = os.Create(logFilePath)
if err != nil {
panic(err)
}
}

func Log(format string, args ...any) {
if os.Getenv(logEnabled) != "true" {
return
}
fmt.Fprintf(logFile, format+"\n", args...)
}
12 changes: 12 additions & 0 deletions types/descriptorpb/extends.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package descriptorpb

import protoimpl "github.com/infiniteloopcloud/protoc-gen-go-types/runtime/protoimpl"

// GetExtensionFields returns the extension fields of the field options
// this function is needed when we want to read the field options, passed by protoc
func (x *FieldOptions) GetExtensionFields() protoimpl.ExtensionFields {
if x != nil {
return x.extensionFields
}
return nil
}

0 comments on commit 7e4dc73

Please sign in to comment.