Компилятор Protobuf для Go не генерирует правильное имя пакета для импорта? - PullRequest
1 голос
/ 04 марта 2020

Рассмотрим следующий пример проекта с Go модулем github.com/kurtpeek/proto-example и следующей структурой каталогов (с .proto файлами в каталоге proto и сгенерированным Go кодом в gen/go):

.
├── gen
│   └── go
│       ├── author
│       │   └── author.pb.go
│       └── book
│           └── book.pb.go
├── go.mod
├── go.sum
├── main.go
└── proto
    ├── author
    │   └── author.proto
    └── book
        └── book.proto

Здесь author.proto читает

syntax="proto3";
package author;

message Author {
    string name = 1;
}

и book.proto импортирует author.proto примерно так:

syntax="proto3";
package book;

import "author/author.proto";

message Book {
    string title = 1;
    author.Author author = 2;
}

Я сгенерировал файлы .pb.go, в каталог proto/, работающий

protoc book/book.proto --go_out=../gen/go

и

protoc author/author.proto --go_out=../gen/go

Проблема заключается в том, что имя пакета, под которым author импортируется в book.pb.go, просто "author":

// Code generated by protoc-gen-go. DO NOT EDIT.
// source: book/book.proto

package book

import (
    author "author"
    fmt "fmt"
    proto "github.com/golang/protobuf/proto"
    math "math"
)

// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf

// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package

type Book struct {
    Title                string         `protobuf:"bytes,1,opt,name=title,proto3" json:"title,omitempty"`
    Author               *author.Author `protobuf:"bytes,2,opt,name=author,proto3" json:"author,omitempty"`
    XXX_NoUnkeyedLiteral struct{}       `json:"-"`
    XXX_unrecognized     []byte         `json:"-"`
    XXX_sizecache        int32          `json:"-"`
}

func (m *Book) Reset()         { *m = Book{} }
func (m *Book) String() string { return proto.CompactTextString(m) }
func (*Book) ProtoMessage()    {}
func (*Book) Descriptor() ([]byte, []int) {
    return fileDescriptor_ee9082fb44230b1b, []int{0}
}

func (m *Book) XXX_Unmarshal(b []byte) error {
    return xxx_messageInfo_Book.Unmarshal(m, b)
}
func (m *Book) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
    return xxx_messageInfo_Book.Marshal(b, m, deterministic)
}
func (m *Book) XXX_Merge(src proto.Message) {
    xxx_messageInfo_Book.Merge(m, src)
}
func (m *Book) XXX_Size() int {
    return xxx_messageInfo_Book.Size(m)
}
func (m *Book) XXX_DiscardUnknown() {
    xxx_messageInfo_Book.DiscardUnknown(m)
}

var xxx_messageInfo_Book proto.InternalMessageInfo

func (m *Book) GetTitle() string {
    if m != nil {
        return m.Title
    }
    return ""
}

func (m *Book) GetAuthor() *author.Author {
    if m != nil {
        return m.Author
    }
    return nil
}

func init() {
    proto.RegisterType((*Book)(nil), "book.Book")
}

func init() { proto.RegisterFile("book/book.proto", fileDescriptor_ee9082fb44230b1b) }

var fileDescriptor_ee9082fb44230b1b = []byte{
    // 108 bytes of a gzipped FileDescriptorProto
    0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4f, 0xca, 0xcf, 0xcf,
    0xd6, 0x07, 0x11, 0x7a, 0x05, 0x45, 0xf9, 0x25, 0xf9, 0x42, 0x2c, 0x20, 0xb6, 0x94, 0x70, 0x62,
    0x69, 0x49, 0x46, 0x7e, 0x91, 0x3e, 0x84, 0x82, 0x48, 0x29, 0xb9, 0x70, 0xb1, 0x38, 0xe5, 0xe7,
    0x67, 0x0b, 0x89, 0x70, 0xb1, 0x96, 0x64, 0x96, 0xe4, 0xa4, 0x4a, 0x30, 0x2a, 0x30, 0x6a, 0x70,
    0x06, 0x41, 0x38, 0x42, 0x6a, 0x5c, 0x6c, 0x10, 0xd5, 0x12, 0x4c, 0x0a, 0x8c, 0x1a, 0xdc, 0x46,
    0x7c, 0x7a, 0x50, 0xcd, 0x8e, 0x60, 0x2a, 0x08, 0x2a, 0x9b, 0xc4, 0x06, 0x36, 0xcc, 0x18, 0x10,
    0x00, 0x00, 0xff, 0xff, 0x2c, 0x89, 0x1f, 0x45, 0x7a, 0x00, 0x00, 0x00,
}

Я бы хотел, чтобы сгенерированный код go вместо этого импортировал друг друга с правильным именем пакета, чтобы book.pb.go начинался следующим образом:

package book

import (
    fmt "fmt"
    math "math"

    proto "github.com/golang/protobuf/proto"
    author "github.com/kurtpeek/proto-example/gen/go/author"
)

Как можно Я заставляю компилятор Protobuf «знать» о модуле Go, в котором находится сгенерированный код?

(подозреваю, что мне нужно указать option go_package (ср. https://developers.google.com/protocol-buffers/docs/gotutorial ), но это, похоже, не меняет сгенерированный код).

1 Ответ

1 голос
/ 04 марта 2020

Ты почти у цели! Я подозреваю, что вас могут укусить относительные пути ...


При условии, что ваши прото-файлы начинаются примерно так:

package author;
option go_package = "github.com/kurtpeek/proto-example/gen/go/author";

и

package book;
import "author/author.proto";
option go_package = "github.com/kurtpeek/proto-example/gen/go/book";

и используя команды построения (с относительными путями)

mkdir -p gen/go
protoc book/book.proto --go_out=gen/go
protoc author/author.proto --go_out=gen/go

ваш сгенерированный код будет отображаться по следующим относительным путям (к вашему CWD):

gen/go/github.com/kurtpeek/proto-example/gen/go/author/author.pb.go
gen/go/github.com/kurtpeek/proto-example/gen/go/book/book.pb.go

Сгенерированный пакет book должен иметь требуемый импорт:

package book

import (
        fmt "fmt"
        proto "github.com/golang/protobuf/proto"
        author "github.com/kurtpeek/proto-example/gen/go/author"
        math "math"
)

Если вы хотите, чтобы сгенерированный код был помещен в указанную директорию c, используйте абсолютный путь:

mkdir -p /some/absolute/path
protoc my.proto --go_out=/some/absolute/path
...