Files
go-zero/tools/goctl/rpc/CHANGELOG-cn.md

118 lines
6.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 变更日志
## 未发布
### 新功能
#### 外部 Proto 导入支持(`--proto_path` / `-I`
新增通过 `-I` / `--proto_path` 标志导入外部目录中的 proto 文件,支持完整的传递性依赖解析。
**涉及文件:**
- `generator/gen.go``ZRpcContext` 新增 `ProtoPaths` 字段;新增 `resolveImportedProtos()` 在代码生成前填充 `ImportedProtos`
- `generator/genpb.go` — 新增 `buildProtocCmd()` 自动发现并追加传递性导入的 proto 文件到 `protoc` 命令;新增 `relativeToProtoPath()` 计算正确的相对路径。
- `parser/import.go` — 新文件(主要新增)。实现 `ResolveImports()` 递归解析传递性导入,`ParseImportedProtos()` 提取导入 proto 的 `go_package` / `package` 元数据,`BuildProtoPackageMap()` 构建按 proto 包名的 O(1) 查找表。
- `parser/proto.go``Proto` 结构体新增 `ImportedProtos []ImportedProto` 字段。
- `cli/cli.go``RPCNew` 传递 `ProtoPaths``ZRpcContext`
- `cli/zrpc.go` — 将 `VarStringSliceProtoPath` 传递到 `ZRpcContext.ProtoPaths`
**前后对比:**
| | 变更前 | 变更后 |
|---|---|---|
| 从外部目录导入 Proto | ❌ 不支持,所有类型必须在同一文件中定义 | ✅ 使用 `-I ./ext_protos` 添加搜索路径 |
| 传递性导入A → B → C | ❌ 仅识别直接导入 | ✅ 递归解析所有传递性依赖 |
| 导入 proto 的 `.pb.go` 生成 | ❌ 需手动为每个文件单独运行 protoc | ✅ 自动将导入的 proto 追加到 protoc 命令 |
| Proto 搜索路径 | ❌ 仅源文件所在目录 | ✅ 支持多个 `-I` 路径,与 protoc 一致 |
**行为说明:**
- 递归遍历 proto 文件中的所有 `import` 声明,跳过 `google/*` 知名类型。
- 在每个 `-I` 目录中搜索被导入的文件,未找到的系统级 proto 静默跳过。
- 将发现的 proto 文件追加到 `protoc` 命令,使其 `.pb.go` 文件与主 proto 一同生成。
---
#### 跨包类型解析
当导入的 proto 与主 proto 具有**不同**的 `go_package`goctl 现在能够自动在 server、logic 和 client 代码中生成正确的 Go 导入路径和限定类型引用。
**涉及文件:**
- `generator/typeref.go` — 新文件,核心类型解析引擎:
- `resolveRPCTypeRef()` — 将 proto RPC 类型简单类型、同包点号类型、跨包点号类型、Google WKT解析为带正确导入路径的 Go 类型引用。
- `resolveCallTypeRef()` — 客户端代码生成变体,支持类型别名。
- `googleWKTTable` — 全部 16 种 Google 知名类型到 Go 等价类型的映射表。
- `generator/genserver.go``genFunctions()` 调用 `resolveRPCTypeRef()` 解析请求/响应类型并收集额外导入路径。
- `generator/genlogic.go``genLogicFunction()` 使用 `resolveRPCTypeRef()`;新增 `addLogicImports()` 按需添加主 pb 导入和跨包导入。
- `generator/gencall.go``genFunction()``getInterfaceFuncs()` 使用 `resolveCallTypeRef()` 处理类型别名和额外导入;新增 `buildExtraImportLines()` 辅助函数。
- `generator/call.tpl` — 新增 `{{.extraImports}}` 占位符用于跨包导入行。
**前后对比:**
| Proto 类型 | 变更前 | 变更后 |
|---|---|---|
| `GetReq`(同文件) | `pb.GetReq` | `pb.GetReq`(无变化) |
| `ext.ExtReq`(相同 `go_package` | ❌ 报错:"request type must defined in" | ✅ `pb.ExtReq` — 合并到主包 |
| `common.TypesReq`(不同 `go_package` | ❌ 报错:"request type must defined in" | ✅ `common.TypesReq` + 自动生成 `import "example.com/demo/pb/common"` |
| `google.protobuf.Empty` | ❌ 报错:"request type must defined in" | ✅ `emptypb.Empty` + 自动生成导入 |
**行为说明:**
- 简单类型(如 `GetReq`)解析为 `pb.GetReq`,无额外导入。
- 同包点号类型(如 `ext.ExtReq`,其中 `ext` 与主 proto 有相同的 `go_package`)解析为 `pb.ExtReq`
- 跨包点号类型(如 `common.TypesReq`,其中 `common` 有不同的 `go_package`)解析为 `common.TypesReq`,并自动添加正确的 Go 导入路径。
---
#### Google 知名类型作为 RPC 参数
Google protobuf 知名类型现在可以直接用作 RPC 的请求/响应类型(而不仅仅是消息字段)。
**涉及文件:**
- `generator/typeref.go``resolveGoogleWKT()` + `googleWKTTable` 处理所有标准类型。
**前后对比:**
| Proto 类型 | 变更前(作为 RPC 参数) | 变更后(作为 RPC 参数) |
|---|---|---|
| `google.protobuf.Empty` | ❌ 报错 | ✅ `emptypb.Empty` |
| `google.protobuf.Timestamp` | ❌ 报错 | ✅ `timestamppb.Timestamp` |
| `google.protobuf.Duration` | ❌ 报错 | ✅ `durationpb.Duration` |
| `google.protobuf.Any` | ❌ 报错 | ✅ `anypb.Any` |
| `google.protobuf.Struct` | ❌ 报错 | ✅ `structpb.Struct` |
| `google.protobuf.FieldMask` | ❌ 报错 | ✅ `fieldmaskpb.FieldMask` |
| `google.protobuf.*Value` | ❌ 报错 | ✅ `wrapperspb.*Value` |
> 注:这些类型此前已可用作**消息字段**。本次变更使其可直接用作 **RPC 请求/响应类型**。
**完整类型映射表:**
| Proto 类型 | Go 类型 |
|---|---|
| `google.protobuf.Empty` | `emptypb.Empty` |
| `google.protobuf.Timestamp` | `timestamppb.Timestamp` |
| `google.protobuf.Duration` | `durationpb.Duration` |
| `google.protobuf.Any` | `anypb.Any` |
| `google.protobuf.Struct` | `structpb.Struct` |
| `google.protobuf.Value` | `structpb.Value` |
| `google.protobuf.ListValue` | `structpb.ListValue` |
| `google.protobuf.FieldMask` | `fieldmaskpb.FieldMask` |
| `google.protobuf.*Value`(包装类型) | `wrapperspb.*Value` |
---
### 不兼容变更
#### RPC 定义中允许使用点号类型名
此前 goctl 会拒绝 RPC 请求/响应类型中包含点号的情况(如 `base.Req`),要求所有类型必须定义在同一个 proto 文件中。此限制已移除。
**前后对比:**
| Proto 定义 | 变更前 | 变更后 |
|---|---|---|
| `rpc Fetch(base.Req) returns (base.Reply)` | ❌ 解析错误:"request type must defined in xxx.proto" | ✅ 解析成功,`base.Req` 通过导入的 proto 解析 |
| `rpc Ping(google.protobuf.Empty) returns (Reply)` | ❌ 解析错误:"request type must defined in xxx.proto" | ✅ 解析成功,解析为 `emptypb.Empty` |
**涉及文件:**
- `parser/service.go` — 移除了拒绝点号类型名的验证循环(原错误信息为 `"request type must defined in"` / `"returns type must defined in"`)。
- `parser/parser_test.go``TestDefaultProtoParseCaseInvalidRequestType``TestDefaultProtoParseCaseInvalidResponseType` 重命名并更新,验证点号类型现在可以正常解析。