From 71257cea7f82b29cb0f30033f485bdae0c9c9e00 Mon Sep 17 00:00:00 2001 From: fgy Date: Fri, 2 Sep 2022 19:29:19 +0800 Subject: [PATCH] feat: generate a separate handler file for each method --- cmd/hz/internal/app/app.go | 3 + cmd/hz/internal/config/argument.go | 1 + cmd/hz/internal/generator/handler.go | 74 +++++++++++++++++------- cmd/hz/internal/generator/package.go | 23 +++++--- cmd/hz/internal/generator/package_tpl.go | 4 +- cmd/hz/internal/generator/router.go | 49 ++++++++++++++-- cmd/hz/internal/protobuf/api/api.pb.go | 55 +++++++++--------- cmd/hz/internal/protobuf/api/api.proto | 1 + cmd/hz/internal/protobuf/ast.go | 9 +++ cmd/hz/internal/protobuf/plugin.go | 5 +- cmd/hz/internal/thrift/ast.go | 12 ++++ cmd/hz/internal/thrift/plugin.go | 9 ++- cmd/hz/internal/thrift/tags.go | 5 ++ cmd/hz/internal/util/data.go | 14 ++++- 14 files changed, 195 insertions(+), 69 deletions(-) diff --git a/cmd/hz/internal/app/app.go b/cmd/hz/internal/app/app.go index 588fa09..05789ed 100644 --- a/cmd/hz/internal/app/app.go +++ b/cmd/hz/internal/app/app.go @@ -123,6 +123,7 @@ func Init() *cli.App { snakeNameFlag := cli.BoolFlag{Name: "snake_tag", Usage: "Use snake_case style naming for tags. (Only works for 'form', 'query', 'json')", Destination: &globalArgs.SnakeName} customLayout := cli.StringFlag{Name: "customize_layout", Usage: "Specify the layout template. ({{Template Profile}}:{{Rendering Data}})", Destination: &globalArgs.CustomizeLayout} customPackage := cli.StringFlag{Name: "customize_package", Usage: "Specify the package template. ({{Template Profile}}:)", Destination: &globalArgs.CustomizePackage} + handlerByMethod := cli.BoolFlag{Name: "handler_by_method", Usage: "Generate a separate handler file for each method.", Destination: &globalArgs.HandlerByMethod} // app app := cli.NewApp() @@ -164,6 +165,7 @@ func Init() *cli.App { &excludeFilesFlag, &customLayout, &customPackage, + &handlerByMethod, &protoPluginsFlag, &thriftPluginsFlag, }, @@ -191,6 +193,7 @@ func Init() *cli.App { &snakeNameFlag, &excludeFilesFlag, &customPackage, + &handlerByMethod, &protoPluginsFlag, &thriftPluginsFlag, }, diff --git a/cmd/hz/internal/config/argument.go b/cmd/hz/internal/config/argument.go index fc4e532..9191181 100644 --- a/cmd/hz/internal/config/argument.go +++ b/cmd/hz/internal/config/argument.go @@ -61,6 +61,7 @@ type Argument struct { SnakeName bool Excludes []string NoRecurse bool + HandlerByMethod bool CustomizeLayout string CustomizePackage string diff --git a/cmd/hz/internal/generator/handler.go b/cmd/hz/internal/generator/handler.go index 1b8883b..3445cd5 100644 --- a/cmd/hz/internal/generator/handler.go +++ b/cmd/hz/internal/generator/handler.go @@ -36,6 +36,7 @@ type HttpMethod struct { ReturnTypeName string Path string Serializer string + OutputDir string // Annotations map[string]string Models map[string]*model.Model } @@ -54,29 +55,37 @@ type Client struct { func (pkgGen *HttpPackageGenerator) genHandler(pkg *HttpPackage, handlerDir, handlerPackage string, root *RouterNode) error { for _, s := range pkg.Services { - handler := Handler{ - FilePath: filepath.Join(handlerDir, util.ToSnakeCase(s.Name)+".go"), - PackageName: util.SplitPackage(handlerPackage, ""), - Methods: s.Methods, - } - - handler.Imports = make(map[string]*model.Model, len(s.Methods)) - for _, m := range s.Methods { - for key, mm := range m.Models { - if v, ok := handler.Imports[mm.PackageName]; ok && v.Package != mm.Package { - handler.Imports[key] = mm - continue + var handler Handler + if pkgGen.HandlerByMethod { // generate handler by method + for _, m := range s.Methods { + handler = Handler{ + FilePath: filepath.Join(handlerDir, m.OutputDir, util.ToSnakeCase(m.Name)+".go"), + PackageName: util.SplitPackage(handlerPackage, ""), + Methods: []*HttpMethod{m}, + } + + if err := pkgGen.processHandler(&handler, root, handlerDir, m.OutputDir, true); err != nil { + return fmt.Errorf("generate handler %s failed, err: %v", handler.FilePath, err.Error()) + } + + if err := pkgGen.updateHandler(handler, handlerTplName, handler.FilePath, false); err != nil { + return fmt.Errorf("generate handler %s failed, err: %v", handler.FilePath, err.Error()) } - handler.Imports[mm.PackageName] = mm } - err := root.Update(m, handler.PackageName) - if err != nil { - return err + } else { // generate handler service + handler = Handler{ + FilePath: filepath.Join(handlerDir, util.ToSnakeCase(s.Name)+".go"), + PackageName: util.SplitPackage(handlerPackage, ""), + Methods: s.Methods, + } + + if err := pkgGen.processHandler(&handler, root, "", "", false); err != nil { + return fmt.Errorf("generate handler %s failed, err: %v", handler.FilePath, err.Error()) + } + + if err := pkgGen.updateHandler(handler, handlerTplName, handler.FilePath, false); err != nil { + return fmt.Errorf("generate handler %s failed, err: %v", handler.FilePath, err.Error()) } - } - handler.Format() - if err := pkgGen.updateHandler(handler, handlerTplName, handler.FilePath, false); err != nil { - return fmt.Errorf("generate handler %s failed, err: %v", handler.FilePath, err.Error()) } if len(pkgGen.ClientDir) != 0 { @@ -96,6 +105,31 @@ func (pkgGen *HttpPackageGenerator) genHandler(pkg *HttpPackage, handlerDir, han return nil } +func (pkgGen *HttpPackageGenerator) processHandler(handler *Handler, root *RouterNode, handlerDir, projectOutDir string, handlerByMethod bool) error { + singleHandlerPackage := "" + if handlerByMethod { + singleHandlerPackage = util.SubPackage(pkgGen.ProjPackage, filepath.Join(handlerDir, projectOutDir)) + } + handler.Imports = make(map[string]*model.Model, len(handler.Methods)) + for _, m := range handler.Methods { + // Iterate over the request and return parameters of the method to get import path. + for key, mm := range m.Models { + if v, ok := handler.Imports[mm.PackageName]; ok && v.Package != mm.Package { + handler.Imports[key] = mm + continue + } + handler.Imports[mm.PackageName] = mm + } + err := root.Update(m, handler.PackageName, singleHandlerPackage) + if err != nil { + return err + } + } + + handler.Format() + return nil +} + func (pkgGen *HttpPackageGenerator) updateHandler(handler interface{}, handlerTpl, filePath string, noRepeat bool) error { isExist, err := util.PathExist(filePath) if err != nil { diff --git a/cmd/hz/internal/generator/package.go b/cmd/hz/internal/generator/package.go index da340a9..13249b5 100644 --- a/cmd/hz/internal/generator/package.go +++ b/cmd/hz/internal/generator/package.go @@ -44,15 +44,16 @@ type Service struct { } type HttpPackageGenerator struct { - ConfigPath string - Backend meta.Backend - Options []Option - ProjPackage string - HandlerDir string - RouterDir string - ModelDir string - ClientDir string - NeedModel bool + ConfigPath string + Backend meta.Backend + Options []Option + ProjPackage string + HandlerDir string + RouterDir string + ModelDir string + ClientDir string + NeedModel bool + HandlerByMethod bool loadedBackend Backend curModel *model.Model @@ -135,7 +136,11 @@ func (pkgGen *HttpPackageGenerator) Generate(pkg *HttpPackage) error { } } + // this is for handler_by_service, the handler_dir is {$HANDLER_DIR}/{$PKG} handlerDir := util.SubDir(pkgGen.HandlerDir, pkg.Package) + if pkgGen.HandlerByMethod { + handlerDir = pkgGen.HandlerDir + } handlerPackage := util.SubPackage(pkgGen.ProjPackage, handlerDir) routerDir := util.SubDir(pkgGen.RouterDir, pkg.Package) routerPackage := util.SubPackage(pkgGen.ProjPackage, routerDir) diff --git a/cmd/hz/internal/generator/package_tpl.go b/cmd/hz/internal/generator/package_tpl.go index 3e259e3..5a2324e 100644 --- a/cmd/hz/internal/generator/package_tpl.go +++ b/cmd/hz/internal/generator/package_tpl.go @@ -97,7 +97,9 @@ package {{$.PackageName}} import ( "github.com/cloudwego/hertz/pkg/app/server" - {{range $k, $v := .HandlerPackages}}{{$k}} "{{$v}}"{{end}} + {{- range $k, $v := .HandlerPackages}} + {{$k}} "{{$v}}" + {{- end}} ) /* diff --git a/cmd/hz/internal/generator/router.go b/cmd/hz/internal/generator/router.go index 3081b1e..39b8a85 100644 --- a/cmd/hz/internal/generator/router.go +++ b/cmd/hz/internal/generator/router.go @@ -42,8 +42,10 @@ type RouterNode struct { Path string Children childrenRouterInfo - Handler string // {{HandlerPackage}}.{{HandlerName}} - HttpMethod string + Handler string // {{HandlerPackage}}.{{HandlerName}} + HandlerPackage string + HandlerPackageAlias string + HttpMethod string } type RegisterDependency struct { @@ -64,7 +66,7 @@ func (routerNode *RouterNode) Sort() { sort.Sort(routerNode.Children) } -func (routerNode *RouterNode) Update(method *HttpMethod, handlerType string) error { +func (routerNode *RouterNode) Update(method *HttpMethod, handlerType, handlerPkg string) error { if method.Path == "" { return fmt.Errorf("empty path for method '%s'", method.Name) } @@ -77,7 +79,7 @@ func (routerNode *RouterNode) Update(method *HttpMethod, handlerType string) err return fmt.Errorf("path '%s' has been registered", method.Path) } name := util.ToVarName(paths[:last]) - parent.Insert(name, method, handlerType, paths[last:]) + parent.Insert(name, method, handlerType, paths[last:], handlerPkg) parent.Sort() return nil } @@ -136,14 +138,36 @@ func (routerNode *RouterNode) DFS(i int, hook func(layer int, node *RouterNode) return nil } -func (routerNode *RouterNode) Insert(name string, method *HttpMethod, handlerType string, paths []string) { +var handlerPkgMap map[string]string + +func (routerNode *RouterNode) Insert(name string, method *HttpMethod, handlerType string, paths []string, handlerPkg string) { cur := routerNode for i, p := range paths { c := &RouterNode{ Path: "/" + p, } if i == len(paths)-1 { - c.Handler = handlerType + "." + method.Name + // generate handler by method + if len(handlerPkg) != 0 { + // get a unique package alias for every handler + pkgAlias := filepath.Base(handlerPkg) + pkgAlias = util.ToVarName([]string{pkgAlias}) + val, exist := handlerPkgMap[handlerPkg] + if !exist { + pkgAlias, _ = util.GetHandlerPackageUniqueName(pkgAlias) + if len(handlerPkgMap) == 0 { + handlerPkgMap = make(map[string]string, 10) + } + handlerPkgMap[handlerPkg] = pkgAlias + } else { + pkgAlias = val + } + c.HandlerPackageAlias = pkgAlias + c.Handler = pkgAlias + "." + method.Name + c.HandlerPackage = handlerPkg + } else { // generate handler by service + c.Handler = handlerType + "." + method.Name + } c.HttpMethod = getHttpMethod(method.HTTPMethod) } if cur.Children == nil { @@ -272,6 +296,19 @@ func (pkgGen *HttpPackageGenerator) genRouter(pkg *HttpPackage, root *RouterNode }, Router: root, } + + if pkgGen.HandlerByMethod { + handlerMap := make(map[string]string, 1) + hook := func(layer int, node *RouterNode) error { + if len(node.HandlerPackage) != 0 { + handlerMap[node.HandlerPackageAlias] = node.HandlerPackage + } + return nil + } + root.DFS(0, hook) + router.HandlerPackages = handlerMap + } + if err := pkgGen.TemplateGenerator.Generate(router, routerTplName, router.FilePath, false); err != nil { return fmt.Errorf("generate router %s failed, err: %v", router.FilePath, err.Error()) } diff --git a/cmd/hz/internal/protobuf/api/api.pb.go b/cmd/hz/internal/protobuf/api/api.pb.go index aa5e8d9..7fa96fe 100644 --- a/cmd/hz/internal/protobuf/api/api.pb.go +++ b/cmd/hz/internal/protobuf/api/api.pb.go @@ -1,17 +1,3 @@ -// Copyright 2022 CloudWeGo Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.0 @@ -243,6 +229,14 @@ var file_api_proto_extTypes = []protoimpl.ExtensionInfo{ Tag: "bytes,50308,opt,name=baseurl", Filename: "api.proto", }, + { + ExtendedType: (*descriptorpb.MethodOptions)(nil), + ExtensionType: (*string)(nil), + Field: 50309, + Name: "api.handler_path", + Tag: "bytes,50309,opt,name=handler_path", + Filename: "api.proto", + }, { ExtendedType: (*descriptorpb.EnumValueOptions)(nil), ExtensionType: (*int32)(nil), @@ -311,12 +305,14 @@ var ( E_Param = &file_api_proto_extTypes[24] // Whether client requests take public parameters // optional string baseurl = 50308; E_Baseurl = &file_api_proto_extTypes[25] // Baseurl used in ttnet routing + // optional string handler_path = 50309; + E_HandlerPath = &file_api_proto_extTypes[26] // handler_path specifies the path to generate the method ) // Extension fields to descriptorpb.EnumValueOptions. var ( // optional int32 http_code = 50401; - E_HttpCode = &file_api_proto_extTypes[26] + E_HttpCode = &file_api_proto_extTypes[27] ) var File_api_proto protoreflect.FileDescriptor @@ -416,12 +412,16 @@ var file_api_proto_rawDesc = []byte{ 0x61, 0x6d, 0x3a, 0x3a, 0x0a, 0x07, 0x62, 0x61, 0x73, 0x65, 0x75, 0x72, 0x6c, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x84, 0x89, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x62, 0x61, 0x73, 0x65, 0x75, 0x72, 0x6c, 0x3a, 0x40, - 0x0a, 0x09, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x21, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, - 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xe1, - 0x89, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x68, 0x74, 0x74, 0x70, 0x43, 0x6f, 0x64, 0x65, - 0x42, 0x06, 0x5a, 0x04, 0x2f, 0x61, 0x70, 0x69, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x62, 0x61, 0x73, 0x65, 0x75, 0x72, 0x6c, 0x3a, 0x43, + 0x0a, 0x0c, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1e, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x85, + 0x89, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x50, + 0x61, 0x74, 0x68, 0x3a, 0x40, 0x0a, 0x09, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, + 0x12, 0x21, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x18, 0xe1, 0x89, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x68, 0x74, 0x74, + 0x70, 0x43, 0x6f, 0x64, 0x65, 0x42, 0x06, 0x5a, 0x04, 0x2f, 0x61, 0x70, 0x69, } var file_api_proto_goTypes = []interface{}{ @@ -456,11 +456,12 @@ var file_api_proto_depIdxs = []int32{ 1, // 23: api.serializer:extendee -> google.protobuf.MethodOptions 1, // 24: api.param:extendee -> google.protobuf.MethodOptions 1, // 25: api.baseurl:extendee -> google.protobuf.MethodOptions - 2, // 26: api.http_code:extendee -> google.protobuf.EnumValueOptions - 27, // [27:27] is the sub-list for method output_type - 27, // [27:27] is the sub-list for method input_type - 27, // [27:27] is the sub-list for extension type_name - 0, // [0:27] is the sub-list for extension extendee + 1, // 26: api.handler_path:extendee -> google.protobuf.MethodOptions + 2, // 27: api.http_code:extendee -> google.protobuf.EnumValueOptions + 28, // [28:28] is the sub-list for method output_type + 28, // [28:28] is the sub-list for method input_type + 28, // [28:28] is the sub-list for extension type_name + 0, // [0:28] is the sub-list for extension extendee 0, // [0:0] is the sub-list for field type_name } @@ -476,7 +477,7 @@ func file_api_proto_init() { RawDescriptor: file_api_proto_rawDesc, NumEnums: 0, NumMessages: 0, - NumExtensions: 27, + NumExtensions: 28, NumServices: 0, }, GoTypes: file_api_proto_goTypes, diff --git a/cmd/hz/internal/protobuf/api/api.proto b/cmd/hz/internal/protobuf/api/api.proto index 405a80b..54a2db2 100644 --- a/cmd/hz/internal/protobuf/api/api.proto +++ b/cmd/hz/internal/protobuf/api/api.proto @@ -36,6 +36,7 @@ extend google.protobuf.MethodOptions { optional string serializer = 50306; // Serialization method optional string param = 50307; // Whether client requests take public parameters optional string baseurl = 50308; // Baseurl used in ttnet routing + optional string handler_path = 50309; // handler_path specifies the path to generate the method } extend google.protobuf.EnumValueOptions { diff --git a/cmd/hz/internal/protobuf/ast.go b/cmd/hz/internal/protobuf/ast.go index 7492eaa..9ca67c6 100644 --- a/cmd/hz/internal/protobuf/ast.go +++ b/cmd/hz/internal/protobuf/ast.go @@ -23,6 +23,7 @@ import ( "github.com/cloudwego/hertz/cmd/hz/internal/generator" "github.com/cloudwego/hertz/cmd/hz/internal/generator/model" + "github.com/cloudwego/hertz/cmd/hz/internal/protobuf/api" "github.com/cloudwego/hertz/cmd/hz/internal/util" "github.com/cloudwego/hertz/cmd/hz/internal/util/logs" "github.com/jhump/protoreflect/desc" @@ -121,6 +122,13 @@ func astToService(ast *descriptorpb.FileDescriptorProto, resolver *Resolver) ([] } path := vpath.(string) + var handlerOutDir string + genPath := checkFirstOption(api.E_HandlerPath, m.GetOptions()) + handlerOutDir, ok := genPath.(string) + if !ok || len(handlerOutDir) == 0 { + handlerOutDir = "" + } + reqName := m.GetInputType() sb, err := resolver.ResolveIdentifier(reqName) reqName = util.BaseName(sb.Scope.GetOptions().GetGoPackage(), "") + "." + sb.Name @@ -145,6 +153,7 @@ func astToService(ast *descriptorpb.FileDescriptorProto, resolver *Resolver) ([] HTTPMethod: hmethod, Path: path, Serializer: serializer, + OutputDir: handlerOutDir, } goOptMapAlias := make(map[string]string, 1) diff --git a/cmd/hz/internal/protobuf/plugin.go b/cmd/hz/internal/protobuf/plugin.go index 71b6d76..b341164 100644 --- a/cmd/hz/internal/protobuf/plugin.go +++ b/cmd/hz/internal/protobuf/plugin.go @@ -582,8 +582,9 @@ func (plugin *Plugin) genHttpPackage(ast *descriptorpb.FileDescriptorProto, deps TemplateGenerator: generator.TemplateGenerator{ OutputDir: args.OutDir, }, - ProjPackage: pkg, - Options: options, + ProjPackage: pkg, + Options: options, + HandlerByMethod: args.HandlerByMethod, } if args.ModelBackend != "" { diff --git a/cmd/hz/internal/thrift/ast.go b/cmd/hz/internal/thrift/ast.go index 75535df..fb8632c 100644 --- a/cmd/hz/internal/thrift/ast.go +++ b/cmd/hz/internal/thrift/ast.go @@ -70,6 +70,17 @@ func astToService(ast *parser.Thrift, resolver *Resolver) ([]*generator.Service, if len(rs) > 1 { return nil, fmt.Errorf("too many 'api.XXX' annotations: %s", rs) } + + var handlerOutDir string + genPaths := getAnnotation(m.Annotations, ApiGenPath) + if len(genPaths) == 0 { + handlerOutDir = "" + } else if len(genPaths) > 1 { + return nil, fmt.Errorf("too many 'api.handler_path' for %s", m.Name) + } else { + handlerOutDir = genPaths[0] + } + hmethod, path := util.GetFirstKV(rs) if len(path) != 1 || path[0] == "" { return nil, fmt.Errorf("invalid api.%s for %s.%s: %s", hmethod, s.Name, m.Name, path) @@ -103,6 +114,7 @@ func astToService(ast *parser.Thrift, resolver *Resolver) ([]*generator.Service, ReturnTypeName: respName, Path: path[0], Serializer: sr, + OutputDir: handlerOutDir, // Annotations: m.Annotations, } refs := resolver.ExportReferred(false, true) diff --git a/cmd/hz/internal/thrift/plugin.go b/cmd/hz/internal/thrift/plugin.go index b36f9f7..f4f599f 100644 --- a/cmd/hz/internal/thrift/plugin.go +++ b/cmd/hz/internal/thrift/plugin.go @@ -90,6 +90,10 @@ func (plugin *Plugin) Run() int { options := CheckTagOption(plugin.args) pkgInfo, err := plugin.getPackageInfo() + if err != nil { + logs.Errorf("get http package info failed: %s", err.Error()) + return meta.PluginError + } cf, _ := util.GetColonPair(args.CustomizePackage) pkg, err := args.GetGoPackage() @@ -126,8 +130,9 @@ func (plugin *Plugin) Run() int { TemplateGenerator: generator.TemplateGenerator{ OutputDir: args.OutDir, }, - ProjPackage: pkg, - Options: options, + ProjPackage: pkg, + Options: options, + HandlerByMethod: args.HandlerByMethod, } if args.ModelBackend != "" { sg.Backend = meta.Backend(args.ModelBackend) diff --git a/cmd/hz/internal/thrift/tags.go b/cmd/hz/internal/thrift/tags.go index 0e4635a..2e03c61 100644 --- a/cmd/hz/internal/thrift/tags.go +++ b/cmd/hz/internal/thrift/tags.go @@ -56,6 +56,7 @@ const ( ApiAny = "api.any" ApiPath = "api.path" ApiSerializer = "api.serializer" + ApiGenPath = "api.handler_path" ) var ( @@ -70,6 +71,10 @@ var ( ApiAny: "ANY", } + HttpMethodOptionAnnotations = map[string]string{ + ApiGenPath: "handler_path", + } + BindingTags = map[string]string{ AnnotationPath: "path", AnnotationQuery: "query", diff --git a/cmd/hz/internal/util/data.go b/cmd/hz/internal/util/data.go index 6f6f768..3622a5b 100644 --- a/cmd/hz/internal/util/data.go +++ b/cmd/hz/internal/util/data.go @@ -366,8 +366,9 @@ func SubDir(root, subPkg string) string { } var ( - uniquePackageName = map[string]bool{} - uniqueMiddlewareName = map[string]bool{} + uniquePackageName = map[string]bool{} + uniqueMiddlewareName = map[string]bool{} + uniqueHandlerPackageName = map[string]bool{} ) // GetPackageUniqueName can get a non-repeating variable name for package alias @@ -390,6 +391,15 @@ func GetMiddlewareUniqueName(name string) (string, error) { return name, nil } +func GetHandlerPackageUniqueName(name string) (string, error) { + name, err := getUniqueName(name, uniqueHandlerPackageName) + if err != nil { + return "", fmt.Errorf("can not generate unique handler package name: '%s', err: %v", name, err) + } + + return name, nil +} + // getUniqueName can get a non-repeating variable name func getUniqueName(name string, uniqueNameSet map[string]bool) (string, error) { uniqueName := name