Răsfoiți Sursa

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>
anqiansong 3 ani în urmă
părinte
comite
227104d7d7

+ 4 - 6
tools/goctl/completion/completion.go

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

+ 2 - 50
tools/goctl/goctl.go

@@ -492,9 +492,8 @@ var commands = []cli.Command{
 		Usage: "generate rpc code",
 		Subcommands: []cli.Command{
 			{
-				Name:        "new",
-				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(),
+				Name:  "new",
+				Usage: `generate rpc demo service`,
 				Flags: []cli.Flag{
 					cli.StringFlag{
 						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,
-			},
 		},
 	},
 	{

+ 9 - 74
tools/goctl/rpc/cli/cli.go

@@ -4,84 +4,16 @@ import (
 	"errors"
 	"fmt"
 	"path/filepath"
-	"runtime"
 
 	"github.com/urfave/cli"
 	"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/console"
-	"github.com/zeromicro/go-zero/tools/goctl/util/env"
 	"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
 // up your understanding of the zrpc service structure
 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()
 	ext := filepath.Ext(rpcname)
 	if len(ext) > 0 {
@@ -113,12 +45,15 @@ func RPCNew(c *cli.Context) error {
 		return err
 	}
 
-	g, err := generator.NewDefaultRPCGenerator(style)
-	if err != nil {
-		return err
-	}
-
-	return g.Generate(src, filepath.Dir(src), nil)
+	var ctx generator.ZRpcContext
+	ctx.Src = src
+	ctx.GoOutput = filepath.Dir(src)
+	ctx.GrpcOutput = filepath.Dir(src)
+	ctx.IsGooglePlugin = true
+	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

+ 2 - 6
tools/goctl/rpc/cli/zrpc.go

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

+ 1 - 0
tools/goctl/rpc/generator/base/common.proto

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

+ 0 - 28
tools/goctl/rpc/generator/defaultgenerator.go

@@ -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)
-}

+ 13 - 50
tools/goctl/rpc/generator/gen.go

@@ -3,22 +3,12 @@ package generator
 import (
 	"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/util/console"
 	"github.com/zeromicro/go-zero/tools/goctl/util/ctx"
 	"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 {
 	Src             string
 	ProtocCmd       string
@@ -30,38 +20,11 @@ type ZRpcContext struct {
 	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,
 // code storage directory, and proto import parameters to control
 // 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 {
-	abs, err := filepath.Abs(target)
+func (g *Generator) Generate(zctx *ZRpcContext) error {
+	abs, err := filepath.Abs(zctx.Output)
 	if err != nil {
 		return err
 	}
@@ -71,7 +34,7 @@ func (g *RPCGenerator) Generate(src, target string, protoImportPath []string, go
 		return err
 	}
 
-	err = g.g.Prepare()
+	err = g.Prepare()
 	if err != nil {
 		return err
 	}
@@ -82,52 +45,52 @@ func (g *RPCGenerator) Generate(src, target string, protoImportPath []string, go
 	}
 
 	p := parser.NewDefaultProtoParser()
-	proto, err := p.Parse(src)
+	proto, err := p.Parse(zctx.Src)
 	if err != nil {
 		return err
 	}
 
-	dirCtx, err := mkdir(projectCtx, proto, g.cfg, g.ctx)
+	dirCtx, err := mkdir(projectCtx, proto, g.cfg, zctx)
 	if err != nil {
 		return err
 	}
 
-	err = g.g.GenEtc(dirCtx, proto, g.cfg)
+	err = g.GenEtc(dirCtx, proto, g.cfg)
 	if err != nil {
 		return err
 	}
 
-	err = g.g.GenPb(dirCtx, protoImportPath, proto, g.cfg, g.ctx, goOptions...)
+	err = g.GenPb(dirCtx, zctx)
 	if err != nil {
 		return err
 	}
 
-	err = g.g.GenConfig(dirCtx, proto, g.cfg)
+	err = g.GenConfig(dirCtx, proto, g.cfg)
 	if err != nil {
 		return err
 	}
 
-	err = g.g.GenSvc(dirCtx, proto, g.cfg)
+	err = g.GenSvc(dirCtx, proto, g.cfg)
 	if err != nil {
 		return err
 	}
 
-	err = g.g.GenLogic(dirCtx, proto, g.cfg)
+	err = g.GenLogic(dirCtx, proto, g.cfg)
 	if err != nil {
 		return err
 	}
 
-	err = g.g.GenServer(dirCtx, proto, g.cfg)
+	err = g.GenServer(dirCtx, proto, g.cfg)
 	if err != nil {
 		return err
 	}
 
-	err = g.g.GenMain(dirCtx, proto, g.cfg)
+	err = g.GenMain(dirCtx, proto, g.cfg)
 	if err != nil {
 		return err
 	}
 
-	err = g.g.GenCall(dirCtx, proto, g.cfg)
+	err = g.GenCall(dirCtx, proto, g.cfg)
 
 	console.NewColorConsole().MarkDone()
 

+ 30 - 12
tools/goctl/rpc/generator/gen_test.go

@@ -1,6 +1,7 @@
 package generator
 
 import (
+	"fmt"
 	"go/build"
 	"os"
 	"path/filepath"
@@ -10,26 +11,19 @@ import (
 	"github.com/stretchr/testify/assert"
 	"github.com/zeromicro/go-zero/core/logx"
 	"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/util/pathx"
 )
 
-var cfg = &conf.Config{
-	NamingFormat: "gozero",
-}
-
 func TestRpcGenerate(t *testing.T) {
 	_ = Clean()
-	dispatcher := NewDefaultGenerator()
-	err := dispatcher.Prepare()
+	g := NewGenerator("gozero")
+	err := g.Prepare()
 	if err != nil {
 		logx.Error(err)
 		return
 	}
 	projectName := stringx.Rand()
-	g := NewRPCGenerator(dispatcher, cfg)
-
 	src := filepath.Join(build.Default.GOPATH, "src")
 	_, err = os.Stat(src)
 	if err != nil {
@@ -46,7 +40,15 @@ func TestRpcGenerate(t *testing.T) {
 
 	// case go path
 	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)
 		_, err = execx.Run("go test "+projectName, projectDir)
 		if err != nil {
@@ -67,7 +69,15 @@ func TestRpcGenerate(t *testing.T) {
 		}
 
 		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)
 		_, err = execx.Run("go test "+projectName, projectDir)
 		if err != nil {
@@ -79,7 +89,15 @@ func TestRpcGenerate(t *testing.T) {
 
 	// case not in go mod and go path
 	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)
 		_, err = execx.Run("go test "+projectName, projectDir)
 		if err != nil {

+ 44 - 22
tools/goctl/rpc/generator/gencall.go

@@ -58,7 +58,7 @@ func New{{.serviceName}}(cli zrpc.Client) {{.serviceName}} {
 	callFunctionTemplate = `
 {{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) {
-	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...)
 }
 `
@@ -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.
 // 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()
 	service := proto.Service
 	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)
 	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))
-	functions, err := g.genFunction(proto.PbPackage, service)
+	functions, err := g.genFunction(proto.PbPackage, service, isCallPkgSameToGrpcPkg)
 	if err != nil {
 		return err
 	}
 
-	iFunctions, err := g.getInterfaceFuncs(proto.PbPackage, service)
+	iFunctions, err := g.getInterfaceFuncs(proto.PbPackage, service, isCallPkgSameToGrpcPkg)
 	if err != nil {
 		return err
 	}
@@ -93,11 +100,19 @@ func (g *DefaultGenerator) GenCall(ctx DirContext, proto parser.Proto, cfg *conf
 	}
 
 	alias := collection.NewSet()
-	for _, item := range proto.Message {
-		msgName := getMessageName(*item.Message)
-		alias.AddStr(fmt.Sprintf("%s = %s", parser.CamelCase(msgName), fmt.Sprintf("%s.%s", proto.PbPackage, parser.CamelCase(msgName))))
+	if !isCallPkgSameToPbPkg {
+		for _, item := range proto.Message {
+			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()
 	sort.Strings(aliasKeys)
 	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),
 		"head":           head,
 		"filePackage":    dir.Base,
-		"pbPackage":      fmt.Sprintf(`"%s"`, ctx.GetPb().Package),
-		"protoGoPackage": fmt.Sprintf(`"%s"`, ctx.GetProtoGo().Package),
+		"pbPackage":      pbPackage,
+		"protoGoPackage": protoGoPackage,
 		"serviceName":    stringx.From(service.Name).ToCamel(),
 		"functions":      strings.Join(functions, pathx.NL),
 		"interface":      strings.Join(iFunctions, pathx.NL),
@@ -136,7 +151,7 @@ func getMessageName(msg proto.Message) string {
 	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)
 
 	for _, rpc := range service.RPC {
@@ -147,18 +162,22 @@ func (g *DefaultGenerator) genFunction(goPackage string, service parser.Service)
 
 		comment := parser.GetComment(rpc.Doc())
 		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{}{
-			"serviceName":    stringx.From(service.Name).ToCamel(),
-			"rpcServiceName": parser.CamelCase(service.Name),
-			"method":         parser.CamelCase(rpc.Name),
-			"package":        goPackage,
-			"pbRequest":      parser.CamelCase(rpc.RequestType),
-			"pbResponse":     parser.CamelCase(rpc.ReturnsType),
-			"hasComment":     len(comment) > 0,
-			"comment":        comment,
-			"hasReq":         !rpc.StreamsRequest,
-			"notStream":      !rpc.StreamsRequest && !rpc.StreamsReturns,
-			"streamBody":     streamServer,
+			"serviceName":            stringx.From(service.Name).ToCamel(),
+			"rpcServiceName":         parser.CamelCase(service.Name),
+			"method":                 parser.CamelCase(rpc.Name),
+			"package":                goPackage,
+			"pbRequest":              parser.CamelCase(rpc.RequestType),
+			"pbResponse":             parser.CamelCase(rpc.ReturnsType),
+			"hasComment":             len(comment) > 0,
+			"comment":                comment,
+			"hasReq":                 !rpc.StreamsRequest,
+			"notStream":              !rpc.StreamsRequest && !rpc.StreamsReturns,
+			"streamBody":             streamServer,
+			"isCallPkgSameToGrpcPkg": isCallPkgSameToGrpcPkg,
 		})
 		if err != nil {
 			return nil, err
@@ -170,7 +189,7 @@ func (g *DefaultGenerator) genFunction(goPackage string, service parser.Service)
 	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)
 
 	for _, rpc := range service.RPC {
@@ -181,6 +200,9 @@ func (g *DefaultGenerator) getInterfaceFuncs(goPackage string, service parser.Se
 
 		comment := parser.GetComment(rpc.Doc())
 		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(
 			map[string]interface{}{
 				"hasComment": len(comment) > 0,

+ 1 - 1
tools/goctl/rpc/generator/genconfig.go

@@ -24,7 +24,7 @@ type Config struct {
 // 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,
 // 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()
 	configFilename, err := format.FileNamingFormat(cfg.NamingFormat, "config")
 	if err != nil {

+ 27 - 12
tools/goctl/rpc/generator/generator.go

@@ -1,19 +1,34 @@
 package generator
 
 import (
+	"log"
+
 	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
-type Generator interface {
-	Prepare() error
-	GenMain(ctx DirContext, proto parser.Proto, cfg *conf.Config) error
-	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
-	GenLogic(ctx DirContext, proto parser.Proto, cfg *conf.Config) error
-	GenServer(ctx DirContext, proto parser.Proto, cfg *conf.Config) error
-	GenSvc(ctx DirContext, proto parser.Proto, cfg *conf.Config) error
-	GenPb(ctx DirContext, protoImportPath []string, proto parser.Proto, cfg *conf.Config, c *ZRpcContext, goOptions ...string) error
+// Generator defines the environment needs of rpc service generation
+type Generator struct {
+	log console.Console
+	cfg *conf.Config
+}
+
+// NewGenerator returns an instance of Generator
+func NewGenerator(style string) *Generator {
+	cfg, err := conf.NewConfig(style)
+	if err != nil {
+		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)
 }

+ 1 - 1
tools/goctl/rpc/generator/genetc.go

@@ -23,7 +23,7 @@ Etcd:
 
 // GenEtc generates the yaml configuration file of the rpc service,
 // 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()
 	etcFilename, err := format.FileNamingFormat(cfg.NamingFormat, ctx.GetServiceName().Source())
 	if err != nil {

+ 2 - 2
tools/goctl/rpc/generator/genlogic.go

@@ -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.
-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()
 	service := proto.Service.Service.Name
 	for _, rpc := range proto.Service.RPC {
@@ -84,7 +84,7 @@ func (g *DefaultGenerator) GenLogic(ctx DirContext, proto parser.Proto, cfg *con
 	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)
 	text, err := pathx.LoadTemplate(category, logicFuncTemplateFileFile, logicFunctionTemplate)
 	if err != nil {

+ 1 - 1
tools/goctl/rpc/generator/genmain.go

@@ -53,7 +53,7 @@ func main() {
 `
 
 // 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())
 	if err != nil {
 		return err

+ 4 - 98
tools/goctl/rpc/generator/genpb.go

@@ -1,118 +1,24 @@
 package generator
 
 import (
-	"bytes"
-	"errors"
 	"fmt"
 	"io/fs"
 	"os"
 	"path/filepath"
 	"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/parser"
 )
 
 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,
 // 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 {
-	if c != nil {
-		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.0,github.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 *Generator) GenPb(ctx DirContext, c *ZRpcContext) error {
+	return g.genPbDirect(ctx, c)
 }
 
-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)
 	pwd, err := os.Getwd()
 	if err != nil {
@@ -126,7 +32,7 @@ func (g *DefaultGenerator) genPbDirect(ctx DirContext, c *ZRpcContext) error {
 	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)
 	if err != nil {
 		return err

+ 2 - 2
tools/goctl/rpc/generator/genserver.go

@@ -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
-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()
 	logicImport := fmt.Sprintf(`"%v"`, ctx.GetLogic().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
 }
 
-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
 	for _, rpc := range service.RPC {
 		text, err := pathx.LoadTemplate(category, serverFuncTemplateFile, functionTemplate)

+ 1 - 1
tools/goctl/rpc/generator/gensvc.go

@@ -28,7 +28,7 @@ func NewServiceContext(c config.Config) *ServiceContext {
 
 // GenSvc generates the servicecontext.go file, which is the resource dependency of a service,
 // 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()
 	svcFilename, err := format.FileNamingFormat(cfg.NamingFormat, "service_context")
 	if err != nil {

+ 1 - 0
tools/goctl/rpc/generator/prototmpl.go

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