修复批量 update 多个 idl 时只生成最后一个 handler/router 的问题
原 protobuf 插件只取 FileToGenerate 的最后一个 idl 生成 http package,导致 hz_gen 批量脚本一次传入多个 --idl 时,除最后一个外其余 proto 只生成 model、不生成 handler/router。 - protobuf/plugin.go: Handle() 改为遍历全部 FileToGenerate;每个 idl 生成后立即写盘, 使后续 idl 的 register.go/middleware.go/handler 合并能读到累积内容,保证多个新服务 同批生成不互相覆盖注册。 - util/data.go: 新增 ResetUniqueNameSets() - generator/router.go: 新增 ResetRouterState() 每个 idl 生成前重置进程级命名状态,使单进程批量输出与逐文件生成逐字节一致, 避免中间件分组变量名带全局序号后缀(_v1->_v184)造成大面积无谓 diff。
This commit is contained in:
parent
4fa9841009
commit
a407e10ebe
@ -194,6 +194,13 @@ func (routerNode *RouterNode) DFS(i int, hook func(layer int, node *RouterNode)
|
||||
|
||||
var handlerPkgMap map[string]string
|
||||
|
||||
// ResetRouterState 清空路由生成的进程级累积状态(handler 包别名映射)。
|
||||
// 与 util.ResetUniqueNameSets 配合,使「单进程循环处理多个 idl」时,每个 idl 的
|
||||
// 命名都从干净状态起算,结果与旧版「逐文件单进程」生成完全一致。
|
||||
func ResetRouterState() {
|
||||
handlerPkgMap = nil
|
||||
}
|
||||
|
||||
func (routerNode *RouterNode) Insert(name string, method *HttpMethod, handlerType string, paths []string, handlerPkg string) {
|
||||
cur := routerNode
|
||||
for i, p := range paths {
|
||||
|
||||
@ -239,21 +239,34 @@ func (plugin *Plugin) Handle(req *pluginpb.CodeGeneratorRequest, args *config.Ar
|
||||
for _, file := range files {
|
||||
maps[file.GetName()] = file
|
||||
}
|
||||
main := maps[gen.Request.FileToGenerate[len(gen.Request.FileToGenerate)-1]]
|
||||
// 为 FileToGenerate 中的「每一个」idl 生成 http package(handler/router/register/middleware)。
|
||||
// 原实现只取最后一个 idl,导致一次传入多个 --idl 时,除最后一个外其余 proto 都只生成
|
||||
// model、不生成 handler/router(hz_gen 批量脚本正是踩了这个坑)。
|
||||
//
|
||||
// 关键点:handler 追加、register.go、middleware.go 都是「读磁盘现有内容再合并」。插件进程内
|
||||
// 默认不落盘(最终交给 protoc 写),因此若只在内存里循环,后一个 idl 读到的仍是旧文件,会丢掉
|
||||
// 前一个 idl 新增的路由/中间件注册。所以每生成完一个 idl 就「立即写盘」,保证下一轮合并读到的是
|
||||
// 累积后的最新内容。这样多个新服务同批生成也不会互相覆盖注册。
|
||||
for _, idlName := range gen.Request.FileToGenerate {
|
||||
// 每个 idl 开始前重置进程级命名状态,使其行为与「逐文件单进程」一致,
|
||||
// 避免中间件分组变量名带上跨 idl 的全局序号后缀(如 _v184)造成大面积无谓 diff。
|
||||
util.ResetUniqueNameSets()
|
||||
generator.ResetRouterState()
|
||||
|
||||
main := maps[idlName]
|
||||
deps := make(map[string]*descriptorpb.FileDescriptorProto, len(main.GetDependency()))
|
||||
for _, dep := range main.GetDependency() {
|
||||
if f, ok := maps[dep]; !ok {
|
||||
f, ok := maps[dep]
|
||||
if !ok {
|
||||
err := fmt.Errorf("dependency file not found: %s", dep)
|
||||
gen.Error(err)
|
||||
resp := gen.Response()
|
||||
err2 := plugin.Response(resp)
|
||||
if err2 != nil {
|
||||
if err2 := plugin.Response(resp); err2 != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
deps[dep] = f
|
||||
}
|
||||
deps[dep] = f
|
||||
}
|
||||
|
||||
pkgFiles, err := plugin.genHttpPackage(main, deps, args)
|
||||
@ -261,29 +274,30 @@ func (plugin *Plugin) Handle(req *pluginpb.CodeGeneratorRequest, args *config.Ar
|
||||
err := fmt.Errorf("generate package files failed: %s", err.Error())
|
||||
gen.Error(err)
|
||||
resp := gen.Response()
|
||||
err2 := plugin.Response(resp)
|
||||
if err2 != nil {
|
||||
if err2 := plugin.Response(resp); err2 != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// construct plugin response
|
||||
resp := gen.Response()
|
||||
// all files that need to be generated are returned to protoc
|
||||
// 立即落盘,使后续 idl 的 register.go/middleware.go/handler 合并读到最新内容。
|
||||
for _, pkgFile := range pkgFiles {
|
||||
filePath := pkgFile.Path
|
||||
content := pkgFile.Content
|
||||
renderFile := &pluginpb.CodeGeneratorResponse_File{
|
||||
Name: &filePath,
|
||||
Content: &content,
|
||||
absPath := pkgFile.Path
|
||||
if !filepath.IsAbs(absPath) {
|
||||
absPath = filepath.Join(args.OutDir, pkgFile.Path)
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(absPath), 0o755); err != nil {
|
||||
return fmt.Errorf("create dir for '%s' failed: %s", absPath, err.Error())
|
||||
}
|
||||
if err := ioutil.WriteFile(absPath, []byte(pkgFile.Content), 0o644); err != nil {
|
||||
return fmt.Errorf("write http package file '%s' failed: %s", absPath, err.Error())
|
||||
}
|
||||
}
|
||||
resp.File = append(resp.File, renderFile)
|
||||
}
|
||||
|
||||
// plugin stop working
|
||||
err = plugin.Response(resp)
|
||||
if err != nil {
|
||||
// http package 已直接写盘;响应里只回模型文件(交给 protoc 写)。
|
||||
resp := gen.Response()
|
||||
if err := plugin.Response(resp); err != nil {
|
||||
return fmt.Errorf("write response failed: %s", err.Error())
|
||||
}
|
||||
|
||||
|
||||
11
util/data.go
11
util/data.go
@ -364,6 +364,17 @@ var (
|
||||
uniqueHandlerPackageName = map[string]bool{}
|
||||
)
|
||||
|
||||
// ResetUniqueNameSets 清空「唯一变量名」累积状态。
|
||||
// 这些 set 原本假设「一个进程只处理一个 idl」(旧版逐文件生成即如此),
|
||||
// 因此命名从干净的 _v1/_user 起算。当一个进程内循环处理多个 idl 时,必须在每个
|
||||
// idl 开始前重置,否则中间件分组变量名会带上全局序号后缀(如 _v184),导致与逐文件
|
||||
// 生成结果不一致、且依赖处理顺序而不稳定。
|
||||
func ResetUniqueNameSets() {
|
||||
uniquePackageName = map[string]bool{}
|
||||
uniqueMiddlewareName = map[string]bool{}
|
||||
uniqueHandlerPackageName = map[string]bool{}
|
||||
}
|
||||
|
||||
// GetPackageUniqueName can get a non-repeating variable name for package alias
|
||||
func GetPackageUniqueName(name string) (string, error) {
|
||||
name, err := getUniqueName(name, uniquePackageName)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user