From d72f8001767d121c20d910e95f0edf0ef9ee9661 Mon Sep 17 00:00:00 2001 From: luoxin Date: Thu, 20 Jun 2024 17:40:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=A2=E6=88=B7=E7=AB=AF=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E7=94=9F=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .goreleaser.yaml | 12 +-- README.md | 2 + cli/gen/gen_impl.go | 6 ++ cli/gen/upmod.go | 5 + cli/sync.go | 8 ++ codegen/generate_impl.go | 152 ++++++++++++++++++++++++++++++ codegen/path.go | 4 + codegen/pbparse.go | 2 +- codegen/resource.go | 10 ++ codegen/template/client.call.gtpl | 7 ++ codegen/template/client.gtpl | 1 + codegen/template/goreleaser.gtpl | 2 +- codegen/template/orm.gtpl | 3 +- codegen/template/rpc_path.gtpl | 4 + example.codegen.cfg.yaml | 6 ++ state/config.go | 8 +- state/i18n.go | 2 +- 17 files changed, 219 insertions(+), 15 deletions(-) create mode 100644 codegen/template/client.call.gtpl create mode 100644 codegen/template/client.gtpl diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 7406bb8..ed9f62e 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -1,16 +1,12 @@ project_name: codegen - +version: 2 env: - GO111MODULE=on - - GOSUMDB=off - CGO_ENABLED=0 -before: - hooks: - - go mod tidy -#gomod: -# proxy: true -# mod: mod +gomod: + proxy: true + mod: mod builds: - id: cli diff --git a/README.md b/README.md index b8b8f06..a992ce0 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ 帮助文档:https://lazygophers.pages.dev/ +模板仓库:https://github.com/lazygophers/template + ## 生成样例 首先,需要创建一个文件夹存放 `proto` 文件,假设文件夹名为 `proto`,并且在 `proto` 文件夹下存在一个 `hello.proto` 文件,内容如下 diff --git a/cli/gen/gen_impl.go b/cli/gen/gen_impl.go index eabe7b2..ce94fe5 100644 --- a/cli/gen/gen_impl.go +++ b/cli/gen/gen_impl.go @@ -31,6 +31,12 @@ var runGenImpl = func(cmd *cobra.Command, args []string) (err error) { return err } + err = codegen.GenerateClient(pb) + if err != nil { + log.Errorf("err:%v", err) + return err + } + return nil } diff --git a/cli/gen/upmod.go b/cli/gen/upmod.go index a54cb29..aef1159 100644 --- a/cli/gen/upmod.go +++ b/cli/gen/upmod.go @@ -2,6 +2,7 @@ package gen import ( "errors" + "github.com/lazygophers/codegen/cli/utils" "github.com/lazygophers/codegen/codegen" "github.com/lazygophers/codegen/state" "github.com/lazygophers/log" @@ -66,6 +67,10 @@ var upModCmd = &cobra.Command{ state.LazyConfig.Apply() } + if cmd.Flag("goproxy").Value.String() != "" { + state.LazyConfig.GoMod.Goproxy = utils.GetString("goproxy", cmd) + } + err = codegen.UpdateGoMod(filepath.Join(projectDir, "go.mod")) if err != nil { log.Errorf("err:%v", err) diff --git a/cli/sync.go b/cli/sync.go index 04ec658..3b06d09 100644 --- a/cli/sync.go +++ b/cli/sync.go @@ -186,6 +186,14 @@ var syncCmd = &cobra.Command{ // 存储到当前目录下的文件(按照文件名 hash) fileName := filepath.Join(runtime.UserConfigDir(), app.Organization, "codegen", cryptox.Md5(c.Sync.Remote), "codegen.cfg.yaml") + if !osx.IsDir(filepath.Dir(fileName)) { + err = os.MkdirAll(filepath.Dir(fileName), 0777) + if err != nil { + log.Errorf("err:%v", err) + return err + } + } + file, err := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666) if err != nil { log.Errorf("err:%v", err) diff --git a/codegen/generate_impl.go b/codegen/generate_impl.go index 3c19d22..fd65907 100644 --- a/codegen/generate_impl.go +++ b/codegen/generate_impl.go @@ -440,3 +440,155 @@ func GenerateImplRpcRoute(pb *PbPackage) (err error) { return nil } + +func generateImplClient(pb *PbPackage, rpc *PbRPC) (err error) { + pterm.Info.Printfln("try generate impl client %s", rpc.Name) + + args := map[string]any{ + "PB": pb, + "RpcName": rpc.Name, + "RequestType": rpc.rpc.RequestType, + "ResponseType": rpc.rpc.ReturnsType, + "RPC": pbRpc2Route(rpc), + } + + if rpc.genOption.Model != "" { + log.Infof("model:%s", rpc.genOption.Model) + + args["Model"] = rpc.genOption.Model + + msg := pb.GetMessage(rpc.genOption.Model) + if msg != nil { + pkField := msg.PrimaryField() + if pkField != nil { + args["PrimaryKey"] = pkField.Name + args["PrimaryKeyType"] = pkField.Type() + } + } + } + + tpl, err := GetTemplate(TemplateTypeImplClientCall, rpc.genOption.Action) + if err != nil { + log.Errorf("err:%v", err) + return err + } + + file, err := os.OpenFile(GetPath(PathTypeImplClient, pb), os.O_CREATE|os.O_WRONLY|os.O_APPEND, fs.FileMode(0666)) + if err != nil { + log.Errorf("err:%v", err) + return err + } + defer file.Close() + + _, err = file.WriteString("\n") + if err != nil { + log.Errorf("err:%v", err) + return err + } + + err = tpl.Execute(file, args) + if err != nil { + log.Errorf("err:%v", err) + return err + } + + _, err = file.WriteString("\n") + if err != nil { + log.Errorf("err:%v", err) + return err + } + + pterm.Success.Printfln("generate %s success", rpc.Name) + + return nil +} + +func initImplClient(pb *PbPackage) error { + if osx.IsFile(GetPath(PathTypeImplClient, pb)) { + return nil + } + + tpl, err := GetTemplate(TemplateTypeImplClient) + if err != nil { + log.Errorf("err:%v", err) + return err + } + + file, err := os.OpenFile(GetPath(PathTypeImplClient, pb), os.O_CREATE|os.O_WRONLY|os.O_TRUNC, fs.FileMode(0666)) + if err != nil { + log.Errorf("err:%v", err) + return err + } + defer file.Close() + + err = tpl.Execute(file, map[string]any{ + "PB": pb, + }) + if err != nil { + log.Errorf("err:%v", err) + return err + } + + return nil +} + +func GenerateClient(pb *PbPackage) (err error) { + pterm.Info.Printfln("Generating impl client...") + + err = initImplDirectory(pb) + if err != nil { + log.Errorf("err:%v", err) + return err + } + + goPackage, err := ParseGoDir(filepath.Dir(GetPath(PathTypeImplClient, pb))) + if err != nil { + log.Errorf("err:%v", err) + return err + } + + if len(goPackage) == 0 { + goPackage = make(map[string]*GoPackage) + } + + if goPackage[pb.GoPackageName()] == nil { + goPackage[pb.GoPackageName()] = &GoPackage{} + } + + if len(goPackage[pb.GoPackageName()].FuncMap) == 0 { + goPackage[pb.GoPackageName()].FuncMap = make(map[string]*GoFuncNode) + } + + matchFunc := func(rpc *PbRPC) bool { + for _, goFuncNode := range goPackage[pb.GoPackageName()].FuncMap { + goFunc := goFuncNode.goFunc + + if goFunc.RecvType != "" { + continue + } + + if goFunc.Name == rpc.Name { + pterm.Warning.Printfln("%s is exist, skip generate", rpc.Name) + return true + } + } + + return false + } + + for _, rpc := range pb.RPCs() { + //path := filepath.Join(GetPath(PathTypeImpl, pb), rpc.genOption.GenTo+".go") + + if matchFunc(rpc) { + continue + } + + err = generateImplClient(pb, rpc) + if err != nil { + log.Errorf("err:%v", err) + return err + } + } + + return nil +} diff --git a/codegen/path.go b/codegen/path.go index 1b23696..73a8c7c 100644 --- a/codegen/path.go +++ b/codegen/path.go @@ -26,6 +26,7 @@ const ( PathTypeImpl PathTypeImplPath PathTypeImplRoute + PathTypeImplClient PathTypeCmd PathTypeCmdMain @@ -94,6 +95,9 @@ func GetPath(t PathType, pb *PbPackage) string { case PathTypeImplRoute: return filepath.Join(GetPath(PathTypeCmd, pb), "route.gen.go") + case PathTypeImplClient: + return filepath.Join(pb.ProjectRoot(), "client.go") + case PathTypeCmd: return filepath.Join(pb.ProjectRoot(), "cmd") diff --git a/codegen/pbparse.go b/codegen/pbparse.go index 2fff7ae..732a27b 100644 --- a/codegen/pbparse.go +++ b/codegen/pbparse.go @@ -267,7 +267,7 @@ func NewPbRPC(rpc *proto.RPC) *PbRPC { options: make(map[string]map[string]string, len(rpc.Options)), genOption: &PbRpcGenOptions{ Method: "POST", - Path: rpc.Name, + Path: "/" + rpc.Name, }, } p.walk() diff --git a/codegen/resource.go b/codegen/resource.go index 5a5fb8e..a3e1f1c 100644 --- a/codegen/resource.go +++ b/codegen/resource.go @@ -47,6 +47,8 @@ const ( TemplateTypeImplAction TemplateTypeImplPath TemplateTypeImplRoute + TemplateTypeImplClient + TemplateTypeImplClientCall TemplateTypeGoreleaser TemplateTypeMakefile @@ -151,6 +153,14 @@ func GetTemplate(t TemplateType, args ...string) (tpl *template.Template, err er systemPath = state.Config.Template.Impl.Route embedPath = "template/rpc_route.gtpl" + case TemplateTypeImplClient: + systemPath = state.Config.Template.Impl.Client + embedPath = "template/client.gtpl" + + case TemplateTypeImplClientCall: + systemPath = state.Config.Template.Impl.ClientCall + embedPath = "template/client.call.gtpl" + case TemplateTypeCmd: systemPath = state.Config.Template.Main embedPath = "template/cmd.gtpl" diff --git a/codegen/template/client.call.gtpl b/codegen/template/client.call.gtpl new file mode 100644 index 0000000..ec1a72c --- /dev/null +++ b/codegen/template/client.call.gtpl @@ -0,0 +1,7 @@ +func {{ .RPC.RpcName }}(ctx *lrpc.Ctx, req *{{ .RequestType }}) (*{{ .ResponseType }}, error) { + var rsp {{ .ResponseType }} + return &rsp, lrpc.Call(ctx, &core.ServiceDiscoveryClient{ + ServiceName: ServerName, + ServicePath: RpcPath{{ .RPC.RpcName }}, + }, req, &rsp) +} diff --git a/codegen/template/client.gtpl b/codegen/template/client.gtpl new file mode 100644 index 0000000..df7d138 --- /dev/null +++ b/codegen/template/client.gtpl @@ -0,0 +1 @@ +package lmq diff --git a/codegen/template/goreleaser.gtpl b/codegen/template/goreleaser.gtpl index 7740523..d4231bb 100644 --- a/codegen/template/goreleaser.gtpl +++ b/codegen/template/goreleaser.gtpl @@ -25,7 +25,7 @@ builds: - -X github.com/lazygophers/utils/app.Version={{ Self ".Version" }} - -X github.com/lazygophers/utils/app.Tag={{ Self ".Tag" }} - -X github.com/lazygophers/utils/app.BuildDate={{ Self ".Date" }} - - -X github.com/lazygophers/utils/app.GoVersion={{ .EnvSelf ".GOVERSION" }} + - -X github.com/lazygophers/utils/app.GoVersion={{ .EnvSelf ".Env.GOVERSION" }} - -X github.com/lazygophers/utils/app.GoOS={{ Self ".Os" }} - -X github.com/lazygophers/utils/app.Goarch={{ Self ".Arch" }} - -X github.com/lazygophers/utils/app.Goarm={{ Self ".Arm" }} diff --git a/codegen/template/orm.gtpl b/codegen/template/orm.gtpl index 9bb2ebd..95a9fc2 100644 --- a/codegen/template/orm.gtpl +++ b/codegen/template/orm.gtpl @@ -1,9 +1,10 @@ package {{ .PB.GoPackageName }} +{{ if gt (len .Models) 0 }} import ( "database/sql/driver" "github.com/lazygophers/utils" -) +){{ end }} {{ range $key, $value := .Models }}func (m *{{ $value }}) Scan(value interface{}) error { return utils.Scan(m, value) diff --git a/codegen/template/rpc_path.gtpl b/codegen/template/rpc_path.gtpl index bf07315..4976578 100644 --- a/codegen/template/rpc_path.gtpl +++ b/codegen/template/rpc_path.gtpl @@ -1,5 +1,9 @@ package {{ .PB.GoPackageName }} +const ( + ServerName = "{{ .PB.GoPackageName }}" +) + const ({{ range $key, $value := .RPCS }} RpcPath{{ $value.RpcName }} = "{{ $value.Path }}"{{ end }} ) diff --git a/example.codegen.cfg.yaml b/example.codegen.cfg.yaml index d005f88..c641fcc 100644 --- a/example.codegen.cfg.yaml +++ b/example.codegen.cfg.yaml @@ -108,6 +108,12 @@ template: # 路由相关的配置 route: " 的模板文件路径" + # 客户模板文件 + client: " 的模板文件" + + # 调用函数的模板 + client_call: "调用函数的模板文件" + # rpc 相关的 action: # key → action value → 模版文件路径 diff --git a/state/config.go b/state/config.go index 9e112b7..3fb4998 100644 --- a/state/config.go +++ b/state/config.go @@ -137,9 +137,11 @@ type CfgProto struct { type CfgImpl struct { Action map[string]string `json:"action,omitempty" yaml:"action,omitempty" toml:"action,omitempty"` - Impl string `json:"impl,omitempty" yaml:"impl,omitempty" toml:"impl,omitempty"` - Path string `json:"path,omitempty" yaml:"path,omitempty" toml:"path,omitempty"` - Route string `json:"route,omitempty" yaml:"route,omitempty" toml:"route,omitempty"` + Impl string `json:"impl,omitempty" yaml:"impl,omitempty" toml:"impl,omitempty"` + Path string `json:"path,omitempty" yaml:"path,omitempty" toml:"path,omitempty"` + Route string `json:"route,omitempty" yaml:"route,omitempty" toml:"route,omitempty"` + Client string `json:"client,omitempty" yaml:"client,omitempty" toml:"client,omitempty"` + ClientCall string `json:"client_call,omitempty" yaml:"client_call,omitempty" toml:"client_call,omitempty"` } type CfgTemplateState struct { diff --git a/state/i18n.go b/state/i18n.go index 687a741..4d64516 100644 --- a/state/i18n.go +++ b/state/i18n.go @@ -59,5 +59,5 @@ func Localize(key string, args ...interface{}) string { } func LocalizeWithLanguage(lang string, key string, args ...interface{}) string { - return I18n.LocalizeWithLanguage(lang, key, args...) + return I18n.LocalizeWithLang(lang, key, args...) }