update handler generation (#27)

* add execute files

* add protoc-osx

* add rpc generation

* add rpc generation

* add: rpc template generation

* update usage

* fixed env prepare for project in go path

* optimize gomod cache

* add README.md

* format error

* reactor templatex.go

* remove waste code

* update project.go & README.md

* update project.go & README.md
master
Keson 4 years ago committed by GitHub
parent f411178a4f
commit 0734bbcab3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -56,7 +56,6 @@ user
│   │   └── config.go │   │   └── config.go
│   ├── handler │   ├── handler
│   │   ├── loginhandler.go │   │   ├── loginhandler.go
│   │   └── userhandler.go
│   ├── logic │   ├── logic
│   │   └── loginlogic.go │   │   └── loginlogic.go
│   └── svc │   └── svc
@ -73,25 +72,8 @@ user
``` ```
# 准备工作 # 准备工作
* 安装了go环境 * 安装了go环境
* 安装了protoc并且已经设置环境变量 * 安装了protoc&protoc-gen-go并且已经设置环境变量
* mockgen(可选)
# protoc-gen-go
在使用goctl生成rpc服务代码时我们默认会根据开发人员正在开发的工程依赖的`github.com/golang/protobuf`自动将插件重新`go install`到`${GOPATH}/bin`中,
寻找方法:
### go mod 工程
对于`$ go version`不低于1.5版本的的工程,会优先寻找`$ go env GOMODCACHE`目录,如果没有则去`${GOPATH}`中查找(见下文),而低于1.5版本的则会优先从`${GOPATH}/pkg/mod`目录下查找,否则也从`% GOPATH`中查找(见下文)
### go path工程
对于没有使用go mod的工程则默认当作在`${GOPATH}`中处理暂不支持用户自定义的GOPATH而这种情况下则会默认从`${GOPATH}/src`中查找
> 注意:
* 对于以上两种工程如果没有在对应目录查找到`protoc-gen-go`则会提示相应错误,尽管`protoc-gen-go`可能在其他已经设置环境变量的目录中,这个将在后面版本进行优化。
* 对于go mod工程如果工程没有依赖`github.com/golang/protobuf`则需要提前引入。
### 好处
* 保证grpc代码生成规范的一致性
# 用法 # 用法
```shell script ```shell script

@ -9,7 +9,7 @@ import (
func Rpc(c *cli.Context) error { func Rpc(c *cli.Context) error {
rpcCtx := ctx.MustCreateRpcContextFromCli(c) rpcCtx := ctx.MustCreateRpcContextFromCli(c)
generator := gogen.NewDefaultRpcGenerator(rpcCtx) generator := gen.NewDefaultRpcGenerator(rpcCtx)
rpcCtx.Must(generator.Generate()) rpcCtx.Must(generator.Generate())
return nil return nil
} }
@ -17,7 +17,7 @@ func Rpc(c *cli.Context) error {
func RpcTemplate(c *cli.Context) error { func RpcTemplate(c *cli.Context) error {
out := c.String("out") out := c.String("out")
idea := c.Bool("idea") idea := c.Bool("idea")
generator := gogen.NewRpcTemplate(out, idea) generator := gen.NewRpcTemplate(out, idea)
generator.MustGenerate() generator.MustGenerate()
return nil return nil
} }

@ -33,7 +33,6 @@ type (
ProtoSource string ProtoSource string
TargetDir string TargetDir string
SharedDir string SharedDir string
GoPath string
console.Console console.Console
} }
) )
@ -83,7 +82,6 @@ func MustCreateRpcContext(protoSrc, targetDir, sharedDir, serviceName string, id
ProtoSource: filepath.Base(srcFp), ProtoSource: filepath.Base(srcFp),
TargetDir: targetDirFp, TargetDir: targetDirFp,
SharedDir: sharedFp, SharedDir: sharedFp,
GoPath: info.GoPath,
Console: log, Console: log,
} }
} }

@ -7,41 +7,29 @@ import (
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"regexp" "regexp"
"runtime"
"strings" "strings"
"github.com/tal-tech/go-zero/tools/goctl/rpc/execx" "github.com/tal-tech/go-zero/tools/goctl/rpc/execx"
"github.com/tal-tech/go-zero/tools/goctl/util"
"github.com/tal-tech/go-zero/tools/goctl/util/console" "github.com/tal-tech/go-zero/tools/goctl/util/console"
) )
const ( const (
constGo = "go" constGo = "go"
constProtoC = "protoc" constProtoC = "protoc"
constGoModOn = "go env GO111MODULE"
constGoMod = "go env GOMOD" constGoMod = "go env GOMOD"
constGoModCache = "go env GOMODCACHE"
constGoPath = "go env GOPATH" constGoPath = "go env GOPATH"
constProtoCGenGo = "protoc-gen-go" constProtoCGenGo = "protoc-gen-go"
) )
type ( type (
Project struct { Project struct {
Path string Path string
Name string Name string
GoPath string GoMod GoMod
Protobuf Protobuf
GoMod GoMod
} }
GoMod struct { GoMod struct {
ModOn bool Module string
GoModCache string
GoMod string
Module string
}
Protobuf struct {
Path string
} }
) )
@ -56,32 +44,23 @@ func prepare(log console.Console) (*Project, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
_, err = exec.LookPath(constProtoCGenGo)
var (
goModOn bool
goMod, goModCache, module string
goPath string
name, path string
protobufModule string
)
ret, err := execx.Run(constGoModOn)
if err != nil { if err != nil {
return nil, err return nil, err
} }
goModOn = strings.TrimSpace(ret) == "on" var (
ret, err = execx.Run(constGoMod) goMod, module string
if err != nil { goPath string
return nil, err name, path string
} )
goMod = strings.TrimSpace(ret) ret, err := execx.Run(constGoMod)
ret, err = execx.Run(constGoModCache)
if err != nil { if err != nil {
return nil, err return nil, err
} }
goMod = strings.TrimSpace(ret)
goModCache = strings.TrimSpace(ret)
ret, err = execx.Run(constGoPath) ret, err = execx.Run(constGoPath)
if err != nil { if err != nil {
return nil, err return nil, err
@ -90,9 +69,6 @@ func prepare(log console.Console) (*Project, error) {
goPath = strings.TrimSpace(ret) goPath = strings.TrimSpace(ret)
src := filepath.Join(goPath, "src") src := filepath.Join(goPath, "src")
if len(goMod) > 0 { if len(goMod) > 0 {
if goModCache == "" {
goModCache = filepath.Join(goPath, "pkg", "mod")
}
path = filepath.Dir(goMod) path = filepath.Dir(goMod)
name = filepath.Base(path) name = filepath.Base(path)
data, err := ioutil.ReadFile(goMod) data, err := ioutil.ReadFile(goMod)
@ -105,9 +81,6 @@ func prepare(log console.Console) (*Project, error) {
return nil, err return nil, err
} }
} else { } else {
if goModCache == "" {
goModCache = src
}
pwd, err := os.Getwd() pwd, err := os.Getwd()
if err != nil { if err != nil {
return nil, err return nil, err
@ -125,47 +98,11 @@ func prepare(log console.Console) (*Project, error) {
module = name module = name
} }
protobuf := filepath.Join(goModCache, protobufModule)
if !util.FileExists(protobuf) {
return nil, fmt.Errorf("expected protobuf module in path: %s,please ensure you has already [go get github.com/golang/protobuf]", protobuf)
}
var protoCGenGoFilename string
os := runtime.GOOS
switch os {
case "darwin":
protoCGenGoFilename = filepath.Join(goPath, "bin", "protoc-gen-go")
case "windows":
protoCGenGoFilename = filepath.Join(goPath, "bin", "protoc-gen-go.exe")
default:
return nil, fmt.Errorf("unexpeted os: %s", os)
}
if !util.FileExists(protoCGenGoFilename) {
sh := "go install " + filepath.Join(protobuf, constProtoCGenGo)
log.Warning(sh)
stdout, err := execx.Run(sh)
if err != nil {
return nil, err
}
log.Info(stdout)
}
if !util.FileExists(protoCGenGoFilename) {
return nil, fmt.Errorf("protoc-gen-go is not found")
}
return &Project{ return &Project{
Name: name, Name: name,
Path: path, Path: path,
GoPath: goPath,
Protobuf: Protobuf{
Path: protobuf,
},
GoMod: GoMod{ GoMod: GoMod{
ModOn: goModOn, Module: module,
GoModCache: goModCache,
GoMod: goMod,
Module: module,
}, },
}, nil }, nil
} }

@ -1,4 +1,4 @@
package gogen package gen
import ( import (
"github.com/tal-tech/go-zero/tools/goctl/rpc/ctx" "github.com/tal-tech/go-zero/tools/goctl/rpc/ctx"

@ -1,4 +1,4 @@
package gogen package gen
import ( import (
"io/ioutil" "io/ioutil"

@ -1,4 +1,4 @@
package gogen package gen
import ( import (
"path/filepath" "path/filepath"

@ -1,4 +1,4 @@
package gogen package gen
import ( import (
"fmt" "fmt"

@ -1,10 +1,11 @@
package gogen package gen
import ( import (
"fmt" "fmt"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
"github.com/tal-tech/go-zero/tools/goctl/util" "github.com/tal-tech/go-zero/tools/goctl/util"
) )
@ -27,22 +28,9 @@ func New{{.server}}Server(svcCtx *svc.ServiceContext) *{{.server}}Server {
} }
} }
{{if .hasComment}}{{.comment}}{{end}} {{.funcs}}
func (s *{{.server}}Server) {{.method}} (ctx context.Context, in *{{.package}}.{{.request}}) (*{{.package}}.{{.response}}, error) {
l := logic.New{{.logicName}}(ctx,s.svcCtx)
return l.{{.method}}(in)
}
` `
functionTemplate = `{{.head}} functionTemplate = `
package handler
import (
"context"
{{.imports}}
)
{{if .hasComment}}{{.comment}}{{end}} {{if .hasComment}}{{.comment}}{{end}}
func (s *{{.server}}Server) {{.method}} (ctx context.Context, in *{{.package}}.{{.request}}) (*{{.package}}.{{.response}}, error) { func (s *{{.server}}Server) {{.method}} (ctx context.Context, in *{{.package}}.{{.request}}) (*{{.package}}.{{.response}}, error) {
l := logic.New{{.logicName}}(ctx,s.svcCtx) l := logic.New{{.logicName}}(ctx,s.svcCtx)
@ -52,17 +40,10 @@ func (s *{{.server}}Server) {{.method}} (ctx context.Context, in *{{.package}}.{
typeFmt = `%sServer struct { typeFmt = `%sServer struct {
svcCtx *svc.ServiceContext svcCtx *svc.ServiceContext
}` }`
newFuncFmt = `func New%sServer(svcCtx *svc.ServiceContext) *%sServer {
return &%sServer{
svcCtx: svcCtx,
}
}`
) )
func (g *defaultRpcGenerator) genHandler() error { func (g *defaultRpcGenerator) genHandler() error {
handlerPath := g.dirM[dirHandler] handlerPath := g.dirM[dirHandler]
filename := fmt.Sprintf("%vhandler.go", g.Ctx.ServiceName.Lower())
handlerFile := filepath.Join(handlerPath, filename)
file := g.ast file := g.ast
pkg := file.Package pkg := file.Package
pbImport := fmt.Sprintf(`%v "%v"`, pkg, g.mustGetPackage(dirPb)) pbImport := fmt.Sprintf(`%v "%v"`, pkg, g.mustGetPackage(dirPb))
@ -73,54 +54,47 @@ func (g *defaultRpcGenerator) genHandler() error {
logicImport, logicImport,
svcImport, svcImport,
} }
types := make([]string, 0)
newFuncs := make([]string, 0)
head := util.GetHead(g.Ctx.ProtoSource) head := util.GetHead(g.Ctx.ProtoSource)
for _, service := range file.Service { for _, service := range file.Service {
types = append(types, fmt.Sprintf(typeFmt, service.Name.Title())) filename := fmt.Sprintf("%vhandler.go", service.Name.Lower())
newFuncs = append(newFuncs, fmt.Sprintf(newFuncFmt, service.Name.Title(), handlerFile := filepath.Join(handlerPath, filename)
service.Name.Title(), service.Name.Title())) funcList, err := g.genFunctions(service)
if err != nil {
return err
}
err = util.With("server").GoFmt(true).Parse(handlerTemplate).SaveTo(map[string]interface{}{
"head": head,
"types": fmt.Sprintf(typeFmt, service.Name.Title()),
"server": service.Name.Title(),
"imports": strings.Join(imports, "\n\t"),
"funcs": strings.Join(funcList, "\n"),
}, handlerFile, true)
if err != nil {
return err
}
} }
return nil
return util.With("server").GoFmt(true).Parse(handlerTemplate).SaveTo(map[string]interface{}{
"head": head,
"types": strings.Join(types, "\n"),
"newFuncs": strings.Join(newFuncs, "\n"),
"imports": strings.Join(imports, "\n\t"),
}, handlerFile, true)
} }
func (g *defaultRpcGenerator) genFunctions() error { func (g *defaultRpcGenerator) genFunctions(service *parser.RpcService) ([]string, error) {
handlerPath := g.dirM[dirHandler]
file := g.ast file := g.ast
pkg := file.Package pkg := file.Package
var functionList []string
head := util.GetHead(g.Ctx.ProtoSource) for _, method := range service.Funcs {
handlerImports := make([]string, 0) buffer, err := util.With("func").Parse(functionTemplate).Execute(map[string]interface{}{
pbImport := fmt.Sprintf(`%v "%v"`, pkg, g.mustGetPackage(dirPb)) "server": service.Name.Title(),
handlerImports = append(handlerImports, pbImport, fmt.Sprintf(`"%v"`, g.mustGetPackage(dirLogic))) "logicName": fmt.Sprintf("%sLogic", method.Name.Title()),
for _, service := range file.Service { "method": method.Name.Title(),
for _, method := range service.Funcs { "package": pkg,
handlerName := fmt.Sprintf("%shandler.go", method.Name.Lower()) "request": method.InType,
filename := filepath.Join(handlerPath, handlerName) "response": method.OutType,
// override "hasComment": len(method.Document),
err := util.With("func").GoFmt(true).Parse(functionTemplate).SaveTo(map[string]interface{}{ "comment": strings.Join(method.Document, "\n"),
"head": head, })
"server": service.Name.Title(), if err != nil {
"imports": strings.Join(handlerImports, "\n"), return nil, err
"logicName": fmt.Sprintf("%sLogic", method.Name.Title()),
"method": method.Name.Title(),
"package": pkg,
"request": method.InType,
"response": method.OutType,
"hasComment": len(method.Document),
"comment": strings.Join(method.Document, "\n"),
}, filename, true)
if err != nil {
return err
}
} }
functionList = append(functionList, buffer.String())
} }
return functionList, nil
return nil
} }

@ -1,4 +1,4 @@
package gogen package gen
import ( import (
"fmt" "fmt"

@ -1,4 +1,4 @@
package gogen package gen
import ( import (
"fmt" "fmt"

@ -1,4 +1,4 @@
package gogen package gen
import ( import (
"errors" "errors"
@ -8,6 +8,7 @@ import (
"strings" "strings"
"github.com/dsymonds/gotoc/parser" "github.com/dsymonds/gotoc/parser"
"github.com/tal-tech/go-zero/core/lang" "github.com/tal-tech/go-zero/core/lang"
"github.com/tal-tech/go-zero/tools/goctl/rpc/execx" "github.com/tal-tech/go-zero/tools/goctl/rpc/execx"
astParser "github.com/tal-tech/go-zero/tools/goctl/rpc/parser" astParser "github.com/tal-tech/go-zero/tools/goctl/rpc/parser"
@ -72,8 +73,7 @@ func (g *defaultRpcGenerator) genPb() error {
func (g *defaultRpcGenerator) protocGenGo(target string) error { func (g *defaultRpcGenerator) protocGenGo(target string) error {
src := filepath.Dir(g.Ctx.ProtoFileSrc) src := filepath.Dir(g.Ctx.ProtoFileSrc)
sh := fmt.Sprintf(`export PATH=%s:$PATH sh := fmt.Sprintf(`protoc -I=%s --go_out=plugins=grpc:%s %s`, src, target, g.Ctx.ProtoFileSrc)
protoc -I=%s --go_out=plugins=grpc:%s %s`, filepath.Join(g.Ctx.GoPath, "bin"), src, target, g.Ctx.ProtoFileSrc)
stdout, err := execx.Run(sh) stdout, err := execx.Run(sh)
if err != nil { if err != nil {
return err return err

@ -1,4 +1,4 @@
package gogen package gen
import ( import (
"fmt" "fmt"

@ -1,4 +1,4 @@
package gogen package gen
import ( import (
"fmt" "fmt"

@ -1,4 +1,4 @@
package gogen package gen
import ( import (
"github.com/tal-tech/go-zero/tools/goctl/util" "github.com/tal-tech/go-zero/tools/goctl/util"

Loading…
Cancel
Save