1 回答
TA贡献1809条经验 获得超8个赞
protobuf 没有远程导入路径的本机概念。因此导入路径必须相对于某些指定的本地文件系统基本路径(通过-I/指定--proto_path)。
选项1
通常,最简单的方法是为您的组织拥有一个包含 protobuf 定义的存储库——例如,一个名为acme-contract
.
└── protos
└── acme
├── api
│ └── data
│ ├── dto1.proto
│ └── dto2.proto
└── timestamp
└── timestamp.proto
你的 dto1.proto 看起来像:
syntax = "proto3";
package acme.api.data;
import "acme/timestamp/timestamp.proto";
message DTO1 {
string id = 1;
acme.timestamp.Timestamp timestamp = 2;
}
只要您生成与protos/此存储库目录相关的代码,就不会有问题。
选项 2
有多种选择,您可以继续将定义拆分到不同的存储库,但您无法真正逃避导入是文件系统相关的事实。
从历史上看,这可以通过手动克隆各种存储库和安排目录来处理,这样路径是相对的,或者通过使用-I指向可能有意或偶然包含原型文件的各种位置(例如在 $GOPATH 中)。这些策略最终往往会变得相当混乱且难以维护。
buf现在让事情变得更容易了。如果你有你的timestamp回购协议:
.
├── buf.gen.yaml
├── buf.work.yaml
├── gen
│ └── acme
│ └── timestamp
│ └── timestamp.pb.go
├── go.mod
├── go.sum
└── protos
├── acme
│ └── timestamp
│ └── timestamp.proto
├── buf.lock
└── buf.yaml
timestamp.proto看起来像:
syntax = "proto3";
package acme.timestamp;
option go_package = "github.com/my-user/timestamp/gen/acme/timestamp";
message Timestamp {
int64 unix = 1;
}
buf.gen.yaml看起来像:
version: v1
plugins:
- name: go
out: gen
opt: paths=source_relative
- name: go-grpc
out: gen
opt:
- paths=source_relative
- require_unimplemented_servers=false
- name: grpc-gateway
out: gen
opt:
- paths=source_relative
- generate_unbound_methods=true
... 并且下面的所有内容gen/都是通过生成的buf generate。
然后在您的api存储库中:
.
├── buf.gen.yaml
├── buf.work.yaml
├── gen
│ └── acme
│ └── api
│ └── data
│ ├── dto1.pb.go
│ └── dto2.pb.go
└── protos
├── acme
│ └── api
│ └── data
│ ├── dto1.proto
│ └── dto2.proto
├── buf.lock
└── buf.yaml
看起来buf.yaml像:
version: v1
name: buf.build/your-user/api
deps:
- buf.build/your-user/timestamp
breaking:
use:
- FILE
lint:
use:
- DEFAULT
dto1.proto看起来像:
syntax = "proto3";
package acme.api.data;
import "acme/timestamp/timestamp.proto";
option go_package = "github.com/your-user/api/gen/acme/api/data";
message DTO1 {
string id = 1;
acme.timestamp.Timestamp timestamp = 2;
}
和回购buf.gen.yaml中的一样timestamp。
通过生成的代码buf generate将取决于timestamp通过 Go 模块的存储库:
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc (unknown)
// source: acme/api/data/dto1.proto
package data
import (
timestamp "github.com/your-user/timestamp/gen/acme/timestamp"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
// <snip>
请注意,如果对依赖项进行了更改,您需要确保 buf 和 Go 模块保持相对同步。
选项 3
如果您不想利用 Go 模块来导入生成的 pb 代码,您也可以使用与 类似的设置Option 2,而是将所有代码生成到一个单独的存储库中(听起来与您现在所做的类似) . 这最容易通过使用buf托管模式来实现,这将本质上使其不需要 + 忽略任何go_modules指令。
在api-go:
.
├── buf.gen.yaml
├── go.mod
└── go.sum
含有buf.gen.yaml:
version: v1
managed:
enabled: true
go_package_prefix:
default: github.com/your-user/api-go/gen
plugins:
- name: go
out: gen
opt: paths=source_relative
- name: go-grpc
out: gen
opt:
- paths=source_relative
- require_unimplemented_servers=false
- name: grpc-gateway
out: gen
opt:
- paths=source_relative
- generate_unbound_methods=true
然后,您需要为每个相应的回购生成代码(传送到 BSR):
$ buf generate buf.build/your-user/api
$ buf generate buf.build/your-user/timestamp
之后你应该为两者生成一些代码:
.
├── buf.gen.yaml
├── gen
│ └── acme
│ ├── api
│ │ └── data
│ │ ├── dto1.pb.go
│ │ └── dto2.pb.go
│ └── timestamp
│ └── timestamp.pb.go
├── go.mod
└── go.sum
并且导入将相对于当前模块:
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.28.1
// protoc (unknown)
// source: acme/api/data/dto1.proto
package data
import (
timestamp "github.com/your-user/api-go/gen/acme/timestamp"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
)
// <snip>
总而言之,我推荐选项 1——将你的 protobuf 定义整合到一个单一的存储库中(包括 vendoring 3rd party 定义)——除非有特别强烈的理由不这样做。
- 1 回答
- 0 关注
- 156 浏览
添加回答
举报