feat: Remove command `goctl rpc proto` (#1665)

* Fix goctl completion expression

* Fix code generation error if the pkg of pb/grpc is same to zrpc call client pkg

* Remove deprecated comment on action goctl rpc new

* Remove zrpc code generation on action goctl rpc proto

* Remove zrpc code generation on action goctl rpc proto

* Remove Generator interface

Co-authored-by: anqiansong <anqiansong@bytedance.com>
master
anqiansong 3 years ago committed by GitHub
parent 448029aa4b
commit 227104d7d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -48,17 +48,15 @@ func Completion(c *cli.Context) error {
flag := magic flag := magic
err = ioutil.WriteFile(zshF, zsh, os.ModePerm) err = ioutil.WriteFile(zshF, zsh, os.ModePerm)
if err != nil { if err == nil {
return err flag |= flagZsh
} }
flag |= flagZsh
err = ioutil.WriteFile(bashF, bash, os.ModePerm) err = ioutil.WriteFile(bashF, bash, os.ModePerm)
if err != nil { if err == nil {
return err flag |= flagBash
} }
flag |= flagBash
buffer.WriteString(aurora.BrightGreen("generation auto completion success!\n").String()) buffer.WriteString(aurora.BrightGreen("generation auto completion success!\n").String())
buffer.WriteString(aurora.BrightGreen("executes the following script to setting shell:\n").String()) buffer.WriteString(aurora.BrightGreen("executes the following script to setting shell:\n").String())
switch flag { switch flag {

@ -492,9 +492,8 @@ var commands = []cli.Command{
Usage: "generate rpc code", Usage: "generate rpc code",
Subcommands: []cli.Command{ Subcommands: []cli.Command{
{ {
Name: "new", Name: "new",
Usage: `generate rpc demo service`, Usage: `generate rpc demo service`,
Description: aurora.Yellow(`deprecated: zrpc code generation use "goctl rpc protoc" instead, for the details see "goctl rpc protoc --help"`).String(),
Flags: []cli.Flag{ Flags: []cli.Flag{
cli.StringFlag{ cli.StringFlag{
Name: "style", Name: "style",
@ -603,53 +602,6 @@ var commands = []cli.Command{
}, },
}, },
}, },
{
Name: "proto",
Usage: `generate rpc from proto`,
Description: aurora.Yellow(`deprecated: zrpc code generation use "goctl rpc protoc" instead, for the details see "goctl rpc protoc --help"`).String(),
Flags: []cli.Flag{
cli.StringFlag{
Name: "src, s",
Usage: "the file path of the proto source file",
},
cli.StringSliceFlag{
Name: "proto_path, I",
Usage: `native command of protoc, specify the directory in which to search for imports. [optional]`,
},
cli.StringSliceFlag{
Name: "go_opt",
Usage: `native command of protoc-gen-go, specify the mapping from proto to go, eg --go_opt=proto_import=go_package_import. [optional]`,
},
cli.StringFlag{
Name: "dir, d",
Usage: `the target path of the code`,
},
cli.StringFlag{
Name: "style",
Usage: "the file naming format, see [https://github.com/zeromicro/go-zero/tree/master/tools/goctl/config/readme.md]",
},
cli.BoolFlag{
Name: "idea",
Usage: "whether the command execution environment is from idea plugin. [optional]",
},
cli.StringFlag{
Name: "home",
Usage: "the goctl home path of the template, --home and --remote cannot be set at the same time, " +
"if they are, --remote has higher priority",
},
cli.StringFlag{
Name: "remote",
Usage: "the remote git repo of the template, --home and --remote cannot be set at the same time, " +
"if they are, --remote has higher priority\n\tThe git repo directory must be consistent with the " +
"https://github.com/zeromicro/go-zero-template directory structure",
},
cli.StringFlag{
Name: "branch",
Usage: "the branch of the remote repo, it does work with --remote",
},
},
Action: rpc.RPC,
},
}, },
}, },
{ {

@ -4,84 +4,16 @@ import (
"errors" "errors"
"fmt" "fmt"
"path/filepath" "path/filepath"
"runtime"
"github.com/urfave/cli" "github.com/urfave/cli"
"github.com/zeromicro/go-zero/tools/goctl/rpc/generator" "github.com/zeromicro/go-zero/tools/goctl/rpc/generator"
"github.com/zeromicro/go-zero/tools/goctl/util" "github.com/zeromicro/go-zero/tools/goctl/util"
"github.com/zeromicro/go-zero/tools/goctl/util/console"
"github.com/zeromicro/go-zero/tools/goctl/util/env"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx" "github.com/zeromicro/go-zero/tools/goctl/util/pathx"
) )
// Deprecated: use ZRPC instead.
// RPC is to generate rpc service code from a proto file by specifying a proto file using flag src,
// you can specify a target folder for code generation, when the proto file has import, you can specify
// the import search directory through the proto_path command, for specific usage, please refer to protoc -h
func RPC(c *cli.Context) error {
console.Warning("deprecated: use %q instead, for the details see %q",
"goctl rpc protoc", "goctl rpc protoc --help")
if err := prepare(); err != nil {
return err
}
src := c.String("src")
out := c.String("dir")
style := c.String("style")
protoImportPath := c.StringSlice("proto_path")
goOptions := c.StringSlice("go_opt")
home := c.String("home")
remote := c.String("remote")
branch := c.String("branch")
if len(remote) > 0 {
repo, _ := util.CloneIntoGitHome(remote, branch)
if len(repo) > 0 {
home = repo
}
}
if len(home) > 0 {
pathx.RegisterGoctlHome(home)
}
if len(src) == 0 {
return errors.New("missing -src")
}
if len(out) == 0 {
return errors.New("missing -dir")
}
g, err := generator.NewDefaultRPCGenerator(style)
if err != nil {
return err
}
return g.Generate(src, out, protoImportPath, goOptions...)
}
func prepare() error {
if !env.CanExec() {
return fmt.Errorf("%s: can not start new processes using os.StartProcess or exec.Command", runtime.GOOS)
}
if _, err := env.LookUpGo(); err != nil {
return err
}
if _, err := env.LookUpProtoc(); err != nil {
return err
}
if _, err := env.LookUpProtocGenGo(); err != nil {
return err
}
return nil
}
// RPCNew is to generate rpc greet service, this greet service can speed // RPCNew is to generate rpc greet service, this greet service can speed
// up your understanding of the zrpc service structure // up your understanding of the zrpc service structure
func RPCNew(c *cli.Context) error { func RPCNew(c *cli.Context) error {
console.Warning("deprecated: it will be removed in the feature, zrpc code generation please use %q instead",
"goctl rpc protoc")
rpcname := c.Args().First() rpcname := c.Args().First()
ext := filepath.Ext(rpcname) ext := filepath.Ext(rpcname)
if len(ext) > 0 { if len(ext) > 0 {
@ -113,12 +45,15 @@ func RPCNew(c *cli.Context) error {
return err return err
} }
g, err := generator.NewDefaultRPCGenerator(style) var ctx generator.ZRpcContext
if err != nil { ctx.Src = src
return err ctx.GoOutput = filepath.Dir(src)
} ctx.GrpcOutput = filepath.Dir(src)
ctx.IsGooglePlugin = true
return g.Generate(src, filepath.Dir(src), nil) ctx.Output = filepath.Dir(src)
ctx.ProtocCmd = fmt.Sprintf("protoc -I=%s %s --go_out=%s --go-grpc_out=%s", filepath.Dir(src), filepath.Base(src), filepath.Dir(src), filepath.Dir(src))
g := generator.NewGenerator(style)
return g.Generate(&ctx)
} }
// RPCTemplate is the entry for generate rpc template // RPCTemplate is the entry for generate rpc template

@ -107,12 +107,8 @@ func ZRPC(c *cli.Context) error {
ctx.IsGooglePlugin = isGooglePlugin ctx.IsGooglePlugin = isGooglePlugin
ctx.Output = zrpcOut ctx.Output = zrpcOut
ctx.ProtocCmd = strings.Join(protocArgs, " ") ctx.ProtocCmd = strings.Join(protocArgs, " ")
g, err := generator.NewDefaultRPCGenerator(style, generator.WithZRpcContext(&ctx)) g := generator.NewGenerator(style)
if err != nil { return g.Generate(&ctx)
return err
}
return g.Generate(source, zrpcOut, nil)
} }
func removeGoctlFlag(args []string) []string { func removeGoctlFlag(args []string) []string {

@ -1,6 +1,7 @@
syntax = "proto3"; syntax = "proto3";
package common; package common;
option go_package="./common";
message User { message User {
string name = 1; string name = 1;

@ -1,28 +0,0 @@
package generator
import (
"github.com/zeromicro/go-zero/tools/goctl/env"
"github.com/zeromicro/go-zero/tools/goctl/util/console"
)
// DefaultGenerator defines the environment needs of rpc service generation
type DefaultGenerator struct {
log console.Console
}
// just test interface implement
var _ Generator = (*DefaultGenerator)(nil)
// NewDefaultGenerator returns an instance of DefaultGenerator
func NewDefaultGenerator() Generator {
log := console.NewColorConsole()
return &DefaultGenerator{
log: log,
}
}
// Prepare provides environment detection generated by rpc service,
// including go environment, protoc, whether protoc-gen-go is installed or not
func (g *DefaultGenerator) Prepare() error {
return env.Prepare(true, true)
}

@ -3,22 +3,12 @@ package generator
import ( import (
"path/filepath" "path/filepath"
conf "github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/zeromicro/go-zero/tools/goctl/rpc/parser" "github.com/zeromicro/go-zero/tools/goctl/rpc/parser"
"github.com/zeromicro/go-zero/tools/goctl/util/console" "github.com/zeromicro/go-zero/tools/goctl/util/console"
"github.com/zeromicro/go-zero/tools/goctl/util/ctx" "github.com/zeromicro/go-zero/tools/goctl/util/ctx"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx" "github.com/zeromicro/go-zero/tools/goctl/util/pathx"
) )
// RPCGenerator defines a generator and configure
type RPCGenerator struct {
g Generator
cfg *conf.Config
ctx *ZRpcContext
}
type RPCGeneratorOption func(g *RPCGenerator)
type ZRpcContext struct { type ZRpcContext struct {
Src string Src string
ProtocCmd string ProtocCmd string
@ -30,38 +20,11 @@ type ZRpcContext struct {
Output string Output string
} }
// NewDefaultRPCGenerator wraps Generator with configure
func NewDefaultRPCGenerator(style string, options ...RPCGeneratorOption) (*RPCGenerator, error) {
cfg, err := conf.NewConfig(style)
if err != nil {
return nil, err
}
return NewRPCGenerator(NewDefaultGenerator(), cfg, options...), nil
}
// NewRPCGenerator creates an instance for RPCGenerator
func NewRPCGenerator(g Generator, cfg *conf.Config, options ...RPCGeneratorOption) *RPCGenerator {
out := &RPCGenerator{
g: g,
cfg: cfg,
}
for _, opt := range options {
opt(out)
}
return out
}
func WithZRpcContext(c *ZRpcContext) RPCGeneratorOption {
return func(g *RPCGenerator) {
g.ctx = c
}
}
// Generate generates an rpc service, through the proto file, // Generate generates an rpc service, through the proto file,
// code storage directory, and proto import parameters to control // code storage directory, and proto import parameters to control
// the source file and target location of the rpc service that needs to be generated // the source file and target location of the rpc service that needs to be generated
func (g *RPCGenerator) Generate(src, target string, protoImportPath []string, goOptions ...string) error { func (g *Generator) Generate(zctx *ZRpcContext) error {
abs, err := filepath.Abs(target) abs, err := filepath.Abs(zctx.Output)
if err != nil { if err != nil {
return err return err
} }
@ -71,7 +34,7 @@ func (g *RPCGenerator) Generate(src, target string, protoImportPath []string, go
return err return err
} }
err = g.g.Prepare() err = g.Prepare()
if err != nil { if err != nil {
return err return err
} }
@ -82,52 +45,52 @@ func (g *RPCGenerator) Generate(src, target string, protoImportPath []string, go
} }
p := parser.NewDefaultProtoParser() p := parser.NewDefaultProtoParser()
proto, err := p.Parse(src) proto, err := p.Parse(zctx.Src)
if err != nil { if err != nil {
return err return err
} }
dirCtx, err := mkdir(projectCtx, proto, g.cfg, g.ctx) dirCtx, err := mkdir(projectCtx, proto, g.cfg, zctx)
if err != nil { if err != nil {
return err return err
} }
err = g.g.GenEtc(dirCtx, proto, g.cfg) err = g.GenEtc(dirCtx, proto, g.cfg)
if err != nil { if err != nil {
return err return err
} }
err = g.g.GenPb(dirCtx, protoImportPath, proto, g.cfg, g.ctx, goOptions...) err = g.GenPb(dirCtx, zctx)
if err != nil { if err != nil {
return err return err
} }
err = g.g.GenConfig(dirCtx, proto, g.cfg) err = g.GenConfig(dirCtx, proto, g.cfg)
if err != nil { if err != nil {
return err return err
} }
err = g.g.GenSvc(dirCtx, proto, g.cfg) err = g.GenSvc(dirCtx, proto, g.cfg)
if err != nil { if err != nil {
return err return err
} }
err = g.g.GenLogic(dirCtx, proto, g.cfg) err = g.GenLogic(dirCtx, proto, g.cfg)
if err != nil { if err != nil {
return err return err
} }
err = g.g.GenServer(dirCtx, proto, g.cfg) err = g.GenServer(dirCtx, proto, g.cfg)
if err != nil { if err != nil {
return err return err
} }
err = g.g.GenMain(dirCtx, proto, g.cfg) err = g.GenMain(dirCtx, proto, g.cfg)
if err != nil { if err != nil {
return err return err
} }
err = g.g.GenCall(dirCtx, proto, g.cfg) err = g.GenCall(dirCtx, proto, g.cfg)
console.NewColorConsole().MarkDone() console.NewColorConsole().MarkDone()

@ -1,6 +1,7 @@
package generator package generator
import ( import (
"fmt"
"go/build" "go/build"
"os" "os"
"path/filepath" "path/filepath"
@ -10,26 +11,19 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
"github.com/zeromicro/go-zero/core/stringx" "github.com/zeromicro/go-zero/core/stringx"
conf "github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/zeromicro/go-zero/tools/goctl/rpc/execx" "github.com/zeromicro/go-zero/tools/goctl/rpc/execx"
"github.com/zeromicro/go-zero/tools/goctl/util/pathx" "github.com/zeromicro/go-zero/tools/goctl/util/pathx"
) )
var cfg = &conf.Config{
NamingFormat: "gozero",
}
func TestRpcGenerate(t *testing.T) { func TestRpcGenerate(t *testing.T) {
_ = Clean() _ = Clean()
dispatcher := NewDefaultGenerator() g := NewGenerator("gozero")
err := dispatcher.Prepare() err := g.Prepare()
if err != nil { if err != nil {
logx.Error(err) logx.Error(err)
return return
} }
projectName := stringx.Rand() projectName := stringx.Rand()
g := NewRPCGenerator(dispatcher, cfg)
src := filepath.Join(build.Default.GOPATH, "src") src := filepath.Join(build.Default.GOPATH, "src")
_, err = os.Stat(src) _, err = os.Stat(src)
if err != nil { if err != nil {
@ -46,7 +40,15 @@ func TestRpcGenerate(t *testing.T) {
// case go path // case go path
t.Run("GOPATH", func(t *testing.T) { t.Run("GOPATH", func(t *testing.T) {
err = g.Generate("./test.proto", projectDir, []string{common}, "Mbase/common.proto=./base") ctx := &ZRpcContext{
Src: "./test.proto",
ProtocCmd: fmt.Sprintf("protoc -I=%s test.proto --go_out=%s --go_opt=Mbase/common.proto=./base --go-grpc_out=%s", common, projectDir, projectDir),
IsGooglePlugin: true,
GoOutput: projectDir,
GrpcOutput: projectDir,
Output: projectDir,
}
err = g.Generate(ctx)
assert.Nil(t, err) assert.Nil(t, err)
_, err = execx.Run("go test "+projectName, projectDir) _, err = execx.Run("go test "+projectName, projectDir)
if err != nil { if err != nil {
@ -67,7 +69,15 @@ func TestRpcGenerate(t *testing.T) {
} }
projectDir = filepath.Join(workDir, projectName) projectDir = filepath.Join(workDir, projectName)
err = g.Generate("./test.proto", projectDir, []string{common}, "Mbase/common.proto=./base") ctx := &ZRpcContext{
Src: "./test.proto",
ProtocCmd: fmt.Sprintf("protoc -I=%s test.proto --go_out=%s --go_opt=Mbase/common.proto=./base --go-grpc_out=%s", common, projectDir, projectDir),
IsGooglePlugin: true,
GoOutput: projectDir,
GrpcOutput: projectDir,
Output: projectDir,
}
err = g.Generate(ctx)
assert.Nil(t, err) assert.Nil(t, err)
_, err = execx.Run("go test "+projectName, projectDir) _, err = execx.Run("go test "+projectName, projectDir)
if err != nil { if err != nil {
@ -79,7 +89,15 @@ func TestRpcGenerate(t *testing.T) {
// case not in go mod and go path // case not in go mod and go path
t.Run("OTHER", func(t *testing.T) { t.Run("OTHER", func(t *testing.T) {
err = g.Generate("./test.proto", projectDir, []string{common, src}, "Mbase/common.proto=./base") ctx := &ZRpcContext{
Src: "./test.proto",
ProtocCmd: fmt.Sprintf("protoc -I=%s test.proto --go_out=%s --go_opt=Mbase/common.proto=./base --go-grpc_out=%s", common, projectDir, projectDir),
IsGooglePlugin: true,
GoOutput: projectDir,
GrpcOutput: projectDir,
Output: projectDir,
}
err = g.Generate(ctx)
assert.Nil(t, err) assert.Nil(t, err)
_, err = execx.Run("go test "+projectName, projectDir) _, err = execx.Run("go test "+projectName, projectDir)
if err != nil { if err != nil {

@ -58,7 +58,7 @@ func New{{.serviceName}}(cli zrpc.Client) {{.serviceName}} {
callFunctionTemplate = ` callFunctionTemplate = `
{{if .hasComment}}{{.comment}}{{end}} {{if .hasComment}}{{.comment}}{{end}}
func (m *default{{.serviceName}}) {{.method}}(ctx context.Context{{if .hasReq}}, in *{{.pbRequest}}{{end}}, opts ...grpc.CallOption) ({{if .notStream}}*{{.pbResponse}}, {{else}}{{.streamBody}},{{end}} error) { func (m *default{{.serviceName}}) {{.method}}(ctx context.Context{{if .hasReq}}, in *{{.pbRequest}}{{end}}, opts ...grpc.CallOption) ({{if .notStream}}*{{.pbResponse}}, {{else}}{{.streamBody}},{{end}} error) {
client := {{.package}}.New{{.rpcServiceName}}Client(m.cli.Conn()) client := {{if .isCallPkgSameToGrpcPkg}}{{else}}{{.package}}.{{end}}New{{.rpcServiceName}}Client(m.cli.Conn())
return client.{{.method}}(ctx{{if .hasReq}}, in{{end}}, opts...) return client.{{.method}}(ctx{{if .hasReq}}, in{{end}}, opts...)
} }
` `
@ -66,10 +66,17 @@ func (m *default{{.serviceName}}) {{.method}}(ctx context.Context{{if .hasReq}},
// GenCall generates the rpc client code, which is the entry point for the rpc service call. // GenCall generates the rpc client code, which is the entry point for the rpc service call.
// It is a layer of encapsulation for the rpc client and shields the details in the pb. // It is a layer of encapsulation for the rpc client and shields the details in the pb.
func (g *DefaultGenerator) GenCall(ctx DirContext, proto parser.Proto, cfg *conf.Config) error { func (g *Generator) GenCall(ctx DirContext, proto parser.Proto, cfg *conf.Config) error {
dir := ctx.GetCall() dir := ctx.GetCall()
service := proto.Service service := proto.Service
head := util.GetHead(proto.Name) head := util.GetHead(proto.Name)
fmt.Printf(`
call: %s
pb: %s
grpc: %s
`, ctx.GetCall().Filename, ctx.GetPb().Filename, ctx.GetProtoGo().Filename)
isCallPkgSameToPbPkg := ctx.GetCall().Filename == ctx.GetPb().Filename
isCallPkgSameToGrpcPkg := ctx.GetCall().Filename == ctx.GetProtoGo().Filename
callFilename, err := format.FileNamingFormat(cfg.NamingFormat, service.Name) callFilename, err := format.FileNamingFormat(cfg.NamingFormat, service.Name)
if err != nil { if err != nil {
@ -77,12 +84,12 @@ func (g *DefaultGenerator) GenCall(ctx DirContext, proto parser.Proto, cfg *conf
} }
filename := filepath.Join(dir.Filename, fmt.Sprintf("%s.go", callFilename)) filename := filepath.Join(dir.Filename, fmt.Sprintf("%s.go", callFilename))
functions, err := g.genFunction(proto.PbPackage, service) functions, err := g.genFunction(proto.PbPackage, service, isCallPkgSameToGrpcPkg)
if err != nil { if err != nil {
return err return err
} }
iFunctions, err := g.getInterfaceFuncs(proto.PbPackage, service) iFunctions, err := g.getInterfaceFuncs(proto.PbPackage, service, isCallPkgSameToGrpcPkg)
if err != nil { if err != nil {
return err return err
} }
@ -93,11 +100,19 @@ func (g *DefaultGenerator) GenCall(ctx DirContext, proto parser.Proto, cfg *conf
} }
alias := collection.NewSet() alias := collection.NewSet()
for _, item := range proto.Message { if !isCallPkgSameToPbPkg {
msgName := getMessageName(*item.Message) for _, item := range proto.Message {
alias.AddStr(fmt.Sprintf("%s = %s", parser.CamelCase(msgName), fmt.Sprintf("%s.%s", proto.PbPackage, parser.CamelCase(msgName)))) msgName := getMessageName(*item.Message)
alias.AddStr(fmt.Sprintf("%s = %s", parser.CamelCase(msgName), fmt.Sprintf("%s.%s", proto.PbPackage, parser.CamelCase(msgName))))
}
} }
pbPackage := fmt.Sprintf(`"%s"`, ctx.GetPb().Package)
protoGoPackage := fmt.Sprintf(`"%s"`, ctx.GetProtoGo().Package)
if isCallPkgSameToGrpcPkg {
pbPackage = ""
protoGoPackage = ""
}
aliasKeys := alias.KeysStr() aliasKeys := alias.KeysStr()
sort.Strings(aliasKeys) sort.Strings(aliasKeys)
err = util.With("shared").GoFmt(true).Parse(text).SaveTo(map[string]interface{}{ err = util.With("shared").GoFmt(true).Parse(text).SaveTo(map[string]interface{}{
@ -105,8 +120,8 @@ func (g *DefaultGenerator) GenCall(ctx DirContext, proto parser.Proto, cfg *conf
"alias": strings.Join(aliasKeys, pathx.NL), "alias": strings.Join(aliasKeys, pathx.NL),
"head": head, "head": head,
"filePackage": dir.Base, "filePackage": dir.Base,
"pbPackage": fmt.Sprintf(`"%s"`, ctx.GetPb().Package), "pbPackage": pbPackage,
"protoGoPackage": fmt.Sprintf(`"%s"`, ctx.GetProtoGo().Package), "protoGoPackage": protoGoPackage,
"serviceName": stringx.From(service.Name).ToCamel(), "serviceName": stringx.From(service.Name).ToCamel(),
"functions": strings.Join(functions, pathx.NL), "functions": strings.Join(functions, pathx.NL),
"interface": strings.Join(iFunctions, pathx.NL), "interface": strings.Join(iFunctions, pathx.NL),
@ -136,7 +151,7 @@ func getMessageName(msg proto.Message) string {
return strings.Join(list, "_") return strings.Join(list, "_")
} }
func (g *DefaultGenerator) genFunction(goPackage string, service parser.Service) ([]string, error) { func (g *Generator) genFunction(goPackage string, service parser.Service, isCallPkgSameToGrpcPkg bool) ([]string, error) {
functions := make([]string, 0) functions := make([]string, 0)
for _, rpc := range service.RPC { for _, rpc := range service.RPC {
@ -147,18 +162,22 @@ func (g *DefaultGenerator) genFunction(goPackage string, service parser.Service)
comment := parser.GetComment(rpc.Doc()) comment := parser.GetComment(rpc.Doc())
streamServer := fmt.Sprintf("%s.%s_%s%s", goPackage, parser.CamelCase(service.Name), parser.CamelCase(rpc.Name), "Client") streamServer := fmt.Sprintf("%s.%s_%s%s", goPackage, parser.CamelCase(service.Name), parser.CamelCase(rpc.Name), "Client")
if isCallPkgSameToGrpcPkg {
streamServer = fmt.Sprintf("%s_%s%s", parser.CamelCase(service.Name), parser.CamelCase(rpc.Name), "Client")
}
buffer, err := util.With("sharedFn").Parse(text).Execute(map[string]interface{}{ buffer, err := util.With("sharedFn").Parse(text).Execute(map[string]interface{}{
"serviceName": stringx.From(service.Name).ToCamel(), "serviceName": stringx.From(service.Name).ToCamel(),
"rpcServiceName": parser.CamelCase(service.Name), "rpcServiceName": parser.CamelCase(service.Name),
"method": parser.CamelCase(rpc.Name), "method": parser.CamelCase(rpc.Name),
"package": goPackage, "package": goPackage,
"pbRequest": parser.CamelCase(rpc.RequestType), "pbRequest": parser.CamelCase(rpc.RequestType),
"pbResponse": parser.CamelCase(rpc.ReturnsType), "pbResponse": parser.CamelCase(rpc.ReturnsType),
"hasComment": len(comment) > 0, "hasComment": len(comment) > 0,
"comment": comment, "comment": comment,
"hasReq": !rpc.StreamsRequest, "hasReq": !rpc.StreamsRequest,
"notStream": !rpc.StreamsRequest && !rpc.StreamsReturns, "notStream": !rpc.StreamsRequest && !rpc.StreamsReturns,
"streamBody": streamServer, "streamBody": streamServer,
"isCallPkgSameToGrpcPkg": isCallPkgSameToGrpcPkg,
}) })
if err != nil { if err != nil {
return nil, err return nil, err
@ -170,7 +189,7 @@ func (g *DefaultGenerator) genFunction(goPackage string, service parser.Service)
return functions, nil return functions, nil
} }
func (g *DefaultGenerator) getInterfaceFuncs(goPackage string, service parser.Service) ([]string, error) { func (g *Generator) getInterfaceFuncs(goPackage string, service parser.Service, isCallPkgSameToGrpcPkg bool) ([]string, error) {
functions := make([]string, 0) functions := make([]string, 0)
for _, rpc := range service.RPC { for _, rpc := range service.RPC {
@ -181,6 +200,9 @@ func (g *DefaultGenerator) getInterfaceFuncs(goPackage string, service parser.Se
comment := parser.GetComment(rpc.Doc()) comment := parser.GetComment(rpc.Doc())
streamServer := fmt.Sprintf("%s.%s_%s%s", goPackage, parser.CamelCase(service.Name), parser.CamelCase(rpc.Name), "Client") streamServer := fmt.Sprintf("%s.%s_%s%s", goPackage, parser.CamelCase(service.Name), parser.CamelCase(rpc.Name), "Client")
if isCallPkgSameToGrpcPkg {
streamServer = fmt.Sprintf("%s_%s%s", parser.CamelCase(service.Name), parser.CamelCase(rpc.Name), "Client")
}
buffer, err := util.With("interfaceFn").Parse(text).Execute( buffer, err := util.With("interfaceFn").Parse(text).Execute(
map[string]interface{}{ map[string]interface{}{
"hasComment": len(comment) > 0, "hasComment": len(comment) > 0,

@ -24,7 +24,7 @@ type Config struct {
// which contains the zrpc.RpcServerConf configuration item by default. // which contains the zrpc.RpcServerConf configuration item by default.
// You can specify the naming style of the target file name through config.Config. For details, // You can specify the naming style of the target file name through config.Config. For details,
// see https://github.com/zeromicro/go-zero/tree/master/tools/goctl/config/config.go // see https://github.com/zeromicro/go-zero/tree/master/tools/goctl/config/config.go
func (g *DefaultGenerator) GenConfig(ctx DirContext, _ parser.Proto, cfg *conf.Config) error { func (g *Generator) GenConfig(ctx DirContext, _ parser.Proto, cfg *conf.Config) error {
dir := ctx.GetConfig() dir := ctx.GetConfig()
configFilename, err := format.FileNamingFormat(cfg.NamingFormat, "config") configFilename, err := format.FileNamingFormat(cfg.NamingFormat, "config")
if err != nil { if err != nil {

@ -1,19 +1,34 @@
package generator package generator
import ( import (
"log"
conf "github.com/zeromicro/go-zero/tools/goctl/config" conf "github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/zeromicro/go-zero/tools/goctl/rpc/parser" "github.com/zeromicro/go-zero/tools/goctl/env"
"github.com/zeromicro/go-zero/tools/goctl/util/console"
) )
// Generator defines a generator interface to describe how to generate rpc service // Generator defines the environment needs of rpc service generation
type Generator interface { type Generator struct {
Prepare() error log console.Console
GenMain(ctx DirContext, proto parser.Proto, cfg *conf.Config) error cfg *conf.Config
GenCall(ctx DirContext, proto parser.Proto, cfg *conf.Config) error }
GenEtc(ctx DirContext, proto parser.Proto, cfg *conf.Config) error
GenConfig(ctx DirContext, proto parser.Proto, cfg *conf.Config) error // NewGenerator returns an instance of Generator
GenLogic(ctx DirContext, proto parser.Proto, cfg *conf.Config) error func NewGenerator(style string) *Generator {
GenServer(ctx DirContext, proto parser.Proto, cfg *conf.Config) error cfg, err := conf.NewConfig(style)
GenSvc(ctx DirContext, proto parser.Proto, cfg *conf.Config) error if err != nil {
GenPb(ctx DirContext, protoImportPath []string, proto parser.Proto, cfg *conf.Config, c *ZRpcContext, goOptions ...string) error log.Fatalln(err)
}
log := console.NewColorConsole()
return &Generator{
log: log,
cfg: cfg,
}
}
// Prepare provides environment detection generated by rpc service,
// including go environment, protoc, whether protoc-gen-go is installed or not
func (g *Generator) Prepare() error {
return env.Prepare(true, true)
} }

@ -23,7 +23,7 @@ Etcd:
// GenEtc generates the yaml configuration file of the rpc service, // GenEtc generates the yaml configuration file of the rpc service,
// including host, port monitoring configuration items and etcd configuration // including host, port monitoring configuration items and etcd configuration
func (g *DefaultGenerator) GenEtc(ctx DirContext, _ parser.Proto, cfg *conf.Config) error { func (g *Generator) GenEtc(ctx DirContext, _ parser.Proto, cfg *conf.Config) error {
dir := ctx.GetEtc() dir := ctx.GetEtc()
etcFilename, err := format.FileNamingFormat(cfg.NamingFormat, ctx.GetServiceName().Source()) etcFilename, err := format.FileNamingFormat(cfg.NamingFormat, ctx.GetServiceName().Source())
if err != nil { if err != nil {

@ -50,7 +50,7 @@ func (l *{{.logicName}}) {{.method}} ({{if .hasReq}}in {{.request}}{{if .stream}
) )
// GenLogic generates the logic file of the rpc service, which corresponds to the RPC definition items in proto. // GenLogic generates the logic file of the rpc service, which corresponds to the RPC definition items in proto.
func (g *DefaultGenerator) GenLogic(ctx DirContext, proto parser.Proto, cfg *conf.Config) error { func (g *Generator) GenLogic(ctx DirContext, proto parser.Proto, cfg *conf.Config) error {
dir := ctx.GetLogic() dir := ctx.GetLogic()
service := proto.Service.Service.Name service := proto.Service.Service.Name
for _, rpc := range proto.Service.RPC { for _, rpc := range proto.Service.RPC {
@ -84,7 +84,7 @@ func (g *DefaultGenerator) GenLogic(ctx DirContext, proto parser.Proto, cfg *con
return nil return nil
} }
func (g *DefaultGenerator) genLogicFunction(serviceName, goPackage string, rpc *parser.RPC) (string, error) { func (g *Generator) genLogicFunction(serviceName, goPackage string, rpc *parser.RPC) (string, error) {
functions := make([]string, 0) functions := make([]string, 0)
text, err := pathx.LoadTemplate(category, logicFuncTemplateFileFile, logicFunctionTemplate) text, err := pathx.LoadTemplate(category, logicFuncTemplateFileFile, logicFunctionTemplate)
if err != nil { if err != nil {

@ -53,7 +53,7 @@ func main() {
` `
// GenMain generates the main file of the rpc service, which is an rpc service program call entry // GenMain generates the main file of the rpc service, which is an rpc service program call entry
func (g *DefaultGenerator) GenMain(ctx DirContext, proto parser.Proto, cfg *conf.Config) error { func (g *Generator) GenMain(ctx DirContext, proto parser.Proto, cfg *conf.Config) error {
mainFilename, err := format.FileNamingFormat(cfg.NamingFormat, ctx.GetServiceName().Source()) mainFilename, err := format.FileNamingFormat(cfg.NamingFormat, ctx.GetServiceName().Source())
if err != nil { if err != nil {
return err return err

@ -1,118 +1,24 @@
package generator package generator
import ( import (
"bytes"
"errors"
"fmt" "fmt"
"io/fs" "io/fs"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"github.com/zeromicro/go-zero/core/collection"
conf "github.com/zeromicro/go-zero/tools/goctl/config"
"github.com/zeromicro/go-zero/tools/goctl/rpc/execx" "github.com/zeromicro/go-zero/tools/goctl/rpc/execx"
"github.com/zeromicro/go-zero/tools/goctl/rpc/parser"
) )
const googleProtocGenGoErr = `--go_out: protoc-gen-go: plugins are not supported; use 'protoc --go-grpc_out=...' to generate gRPC` const googleProtocGenGoErr = `--go_out: protoc-gen-go: plugins are not supported; use 'protoc --go-grpc_out=...' to generate gRPC`
// GenPb generates the pb.go file, which is a layer of packaging for protoc to generate gprc, // GenPb generates the pb.go file, which is a layer of packaging for protoc to generate gprc,
// but the commands and flags in protoc are not completely joined in goctl. At present, proto_path(-I) is introduced // but the commands and flags in protoc are not completely joined in goctl. At present, proto_path(-I) is introduced
func (g *DefaultGenerator) GenPb(ctx DirContext, protoImportPath []string, proto parser.Proto, _ *conf.Config, c *ZRpcContext, goOptions ...string) error { func (g *Generator) GenPb(ctx DirContext, c *ZRpcContext) error {
if c != nil { return g.genPbDirect(ctx, c)
return g.genPbDirect(ctx, c)
}
// deprecated: use genPbDirect instead.
dir := ctx.GetPb()
cw := new(bytes.Buffer)
directory, base := filepath.Split(proto.Src)
directory = filepath.Clean(directory)
cw.WriteString("protoc ")
protoImportPathSet := collection.NewSet()
isSamePackage := true
for _, ip := range protoImportPath {
pip := " --proto_path=" + ip
if protoImportPathSet.Contains(pip) {
continue
}
abs, err := filepath.Abs(ip)
if err != nil {
return err
}
if abs == directory {
isSamePackage = true
} else {
isSamePackage = false
}
protoImportPathSet.AddStr(pip)
cw.WriteString(pip)
}
currentPath := " --proto_path=" + directory
if !protoImportPathSet.Contains(currentPath) {
cw.WriteString(currentPath)
}
cw.WriteString(" " + proto.Name)
if strings.Contains(proto.GoPackage, "/") {
cw.WriteString(" --go_out=plugins=grpc:" + ctx.GetMain().Filename)
} else {
cw.WriteString(" --go_out=plugins=grpc:" + dir.Filename)
}
// Compatible with version 1.4.0github.com/golang/protobuf/protoc-gen-go@v1.4.0
// --go_opt usage please see https://developers.google.com/protocol-buffers/docs/reference/go-generated#package
optSet := collection.NewSet()
for _, op := range goOptions {
opt := " --go_opt=" + op
if optSet.Contains(opt) {
continue
}
optSet.AddStr(op)
cw.WriteString(" --go_opt=" + op)
}
var currentFileOpt string
if !isSamePackage || (len(proto.GoPackage) > 0 && proto.GoPackage != proto.Package.Name) {
if filepath.IsAbs(proto.GoPackage) {
currentFileOpt = " --go_opt=M" + base + "=" + proto.GoPackage
} else if strings.Contains(proto.GoPackage, string(filepath.Separator)) {
currentFileOpt = " --go_opt=M" + base + "=./" + proto.GoPackage
} else {
currentFileOpt = " --go_opt=M" + base + "=../" + proto.GoPackage
}
} else {
currentFileOpt = " --go_opt=M" + base + "=."
}
if !optSet.Contains(currentFileOpt) {
cw.WriteString(currentFileOpt)
}
command := cw.String()
g.log.Debug(command)
_, err := execx.Run(command, "")
if err != nil {
if strings.Contains(err.Error(), googleProtocGenGoErr) {
return errors.New(`unsupported plugin protoc-gen-go which installed from the following source:
google.golang.org/protobuf/cmd/protoc-gen-go,
github.com/protocolbuffers/protobuf-go/cmd/protoc-gen-go;
Please replace it by the following command, we recommend to use version before v1.3.5:
go get -u github.com/golang/protobuf/protoc-gen-go`)
}
return err
}
return nil
} }
func (g *DefaultGenerator) genPbDirect(ctx DirContext, c *ZRpcContext) error { func (g *Generator) genPbDirect(ctx DirContext, c *ZRpcContext) error {
g.log.Debug("[command]: %s", c.ProtocCmd) g.log.Debug("[command]: %s", c.ProtocCmd)
pwd, err := os.Getwd() pwd, err := os.Getwd()
if err != nil { if err != nil {
@ -126,7 +32,7 @@ func (g *DefaultGenerator) genPbDirect(ctx DirContext, c *ZRpcContext) error {
return g.setPbDir(ctx, c) return g.setPbDir(ctx, c)
} }
func (g *DefaultGenerator) setPbDir(ctx DirContext, c *ZRpcContext) error { func (g *Generator) setPbDir(ctx DirContext, c *ZRpcContext) error {
pbDir, err := findPbFile(c.GoOutput, false) pbDir, err := findPbFile(c.GoOutput, false)
if err != nil { if err != nil {
return err return err

@ -48,7 +48,7 @@ func (s *{{.server}}Server) {{.method}} ({{if .notStream}}ctx context.Context,{{
) )
// GenServer generates rpc server file, which is an implementation of rpc server // GenServer generates rpc server file, which is an implementation of rpc server
func (g *DefaultGenerator) GenServer(ctx DirContext, proto parser.Proto, cfg *conf.Config) error { func (g *Generator) GenServer(ctx DirContext, proto parser.Proto, cfg *conf.Config) error {
dir := ctx.GetServer() dir := ctx.GetServer()
logicImport := fmt.Sprintf(`"%v"`, ctx.GetLogic().Package) logicImport := fmt.Sprintf(`"%v"`, ctx.GetLogic().Package)
svcImport := fmt.Sprintf(`"%v"`, ctx.GetSvc().Package) svcImport := fmt.Sprintf(`"%v"`, ctx.GetSvc().Package)
@ -94,7 +94,7 @@ func (g *DefaultGenerator) GenServer(ctx DirContext, proto parser.Proto, cfg *co
return err return err
} }
func (g *DefaultGenerator) genFunctions(goPackage string, service parser.Service) ([]string, error) { func (g *Generator) genFunctions(goPackage string, service parser.Service) ([]string, error) {
var functionList []string var functionList []string
for _, rpc := range service.RPC { for _, rpc := range service.RPC {
text, err := pathx.LoadTemplate(category, serverFuncTemplateFile, functionTemplate) text, err := pathx.LoadTemplate(category, serverFuncTemplateFile, functionTemplate)

@ -28,7 +28,7 @@ func NewServiceContext(c config.Config) *ServiceContext {
// GenSvc generates the servicecontext.go file, which is the resource dependency of a service, // GenSvc generates the servicecontext.go file, which is the resource dependency of a service,
// such as rpc dependency, model dependency, etc. // such as rpc dependency, model dependency, etc.
func (g *DefaultGenerator) GenSvc(ctx DirContext, _ parser.Proto, cfg *conf.Config) error { func (g *Generator) GenSvc(ctx DirContext, _ parser.Proto, cfg *conf.Config) error {
dir := ctx.GetSvc() dir := ctx.GetSvc()
svcFilename, err := format.FileNamingFormat(cfg.NamingFormat, "service_context") svcFilename, err := format.FileNamingFormat(cfg.NamingFormat, "service_context")
if err != nil { if err != nil {

@ -12,6 +12,7 @@ import (
const rpcTemplateText = `syntax = "proto3"; const rpcTemplateText = `syntax = "proto3";
package {{.package}}; package {{.package}};
option go_package="./{{.package}}";
message Request { message Request {
string ping = 1; string ping = 1;

Loading…
Cancel
Save