anqiansong 3 lat temu
rodzic
commit
ded22e296e

+ 3 - 0
tools/goctl/rpc/cli/cli.go

@@ -58,6 +58,9 @@ func prepare() error {
 	if _, err := env.LookUpProtoc(); err != nil {
 		return err
 	}
+	if _, err := env.LookUpProtocGenGo(); err != nil {
+		return err
+	}
 	return nil
 }
 

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

@@ -1,6 +1,8 @@
 package generator
 
 import (
+	"os/exec"
+
 	"github.com/tal-tech/go-zero/tools/goctl/util/console"
 )
 
@@ -19,3 +21,21 @@ func NewDefaultGenerator() Generator {
 		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 {
+	_, err := exec.LookPath("go")
+	if err != nil {
+		return err
+	}
+
+	_, err = exec.LookPath("protoc")
+	if err != nil {
+		return err
+	}
+
+	_, err = exec.LookPath("protoc-gen-go")
+
+	return err
+}

+ 5 - 0
tools/goctl/rpc/generator/gen.go

@@ -47,6 +47,11 @@ func (g *RPCGenerator) Generate(src, target string, protoImportPath []string, go
 		return err
 	}
 
+	err = g.g.Prepare()
+	if err != nil {
+		return err
+	}
+
 	projectCtx, err := ctx.Prepare(abs)
 	if err != nil {
 		return err

+ 1 - 17
tools/goctl/rpc/generator/gen_test.go

@@ -1,11 +1,9 @@
 package generator
 
 import (
-	"fmt"
 	"go/build"
 	"os"
 	"path/filepath"
-	"runtime"
 	"strings"
 	"testing"
 
@@ -15,7 +13,6 @@ import (
 	"github.com/tal-tech/go-zero/core/stringx"
 	conf "github.com/tal-tech/go-zero/tools/goctl/config"
 	"github.com/tal-tech/go-zero/tools/goctl/rpc/execx"
-	"github.com/tal-tech/go-zero/tools/goctl/util/env"
 )
 
 var cfg = &conf.Config{
@@ -25,7 +22,7 @@ var cfg = &conf.Config{
 func TestRpcGenerate(t *testing.T) {
 	_ = Clean()
 	dispatcher := NewDefaultGenerator()
-	err := prepare()
+	err := dispatcher.Prepare()
 	if err != nil {
 		logx.Error(err)
 		return
@@ -92,16 +89,3 @@ func TestRpcGenerate(t *testing.T) {
 		}
 	})
 }
-
-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
-	}
-	return nil
-}

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

@@ -7,6 +7,7 @@ import (
 
 // 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

+ 51 - 80
tools/goctl/rpc/generator/genpb.go

@@ -2,36 +2,45 @@ package generator
 
 import (
 	"bytes"
-	"fmt"
-	"io/ioutil"
-	"os"
+	"errors"
 	"path/filepath"
-	"runtime"
 	"strings"
 
 	"github.com/tal-tech/go-zero/core/collection"
 	conf "github.com/tal-tech/go-zero/tools/goctl/config"
 	"github.com/tal-tech/go-zero/tools/goctl/rpc/execx"
 	"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/vars"
 )
 
+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, goOptions ...string) error {
 	dir := ctx.GetPb()
 	cw := new(bytes.Buffer)
-	directory, _ := filepath.Split(proto.Src)
+	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)
 	}
@@ -47,88 +56,50 @@ func (g *DefaultGenerator) GenPb(ctx DirContext, protoImportPath []string, proto
 		cw.WriteString(" --go_out=plugins=grpc:" + dir.Filename)
 	}
 
-	return g.generatePbWithVersion132(cw.String())
-}
-
-// generatePbWithVersion132 generates pb.go by specifying protoc-gen-go@1.3.2 version
-func (g *DefaultGenerator) generatePbWithVersion132(cmd string) error {
-	goctlHome, err := util.GetGoctlHome()
-	if err != nil {
-		return err
-	}
-
-	err = util.MkdirIfNotExist(goctlHome)
-	if err != nil {
-		return err
-	}
+	// 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
+		}
 
-	goctlHomeBin := filepath.Join(goctlHome, "bin")
-	err = util.MkdirIfNotExist(goctlHomeBin)
-	if err != nil {
-		return err
+		optSet.AddStr(op)
+		cw.WriteString(" --go_opt=" + op)
 	}
 
-	protocGenGo := filepath.Join(goctlHome, "bin", "protoc-gen-go")
-	g.log.Debug("checking protoc-gen-go state ...")
-	goGetCmd := "\ngo install github.com/golang/protobuf/protoc-gen-go@v1.3.2"
-
-	if util.FileExists(protocGenGo) {
-		g.log.Success("protoc-gen-go exists ...")
-		goGetCmd = ""
+	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 {
-		g.log.Error("missing protoc-gen-go: downloading ...")
+		currentFileOpt = " --go_opt=M" + base + "=."
 	}
 
-	goos := runtime.GOOS
-	switch goos {
-	case vars.OsLinux, vars.OsMac:
-		cmd = getUnixLikeCmd(goctlHome, goctlHomeBin, goGetCmd, cmd)
-		g.log.Debug("%s", cmd)
-	case vars.OsWindows:
-		cmd = getWindowsCmd(goctlHome, goctlHomeBin, goGetCmd, cmd)
-		// Do not support to execute commands in context, the solution is created
-		// a batch file to execute it on Windows.
-		batFile, err := createBatchFile(goctlHome, cmd)
-		if err != nil {
-			return err
-		}
-
-		g.log.Debug("%s", cmd)
-		cmd = batFile
-	default:
-		return fmt.Errorf("unsupported os: %s", goos)
+	if !optSet.Contains(currentFileOpt) {
+		cw.WriteString(currentFileOpt)
 	}
 
-	_, err = execx.Run(cmd, "")
-	return err
-}
-
-func getUnixLikeCmd(goctlHome, goctlHomeBin, goGetCmd, cmd string) string {
-	return fmt.Sprintf(`export GOPATH=%s 
-export GOBIN=%s 
-export PATH=$PATH:$GOPATH:$GOBIN
-export GO111MODULE=on
-export GOPROXY=https://goproxy.cn %s
-%s`, goctlHome, goctlHomeBin, goGetCmd, cmd)
-}
-
-func getWindowsCmd(goctlHome, goctlHomeBin, goGetCmd, cmd string) string {
-	return fmt.Sprintf(`set GOPATH=%s
-set GOBIN=%s
-set path=%s
-set GO111MODULE=on
-set GOPROXY=https://goproxy.cn %s
-%s`, goctlHome, goctlHomeBin, "%path%;"+goctlHome+";"+goctlHomeBin, goGetCmd, cmd)
-}
+	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;
 
-func createBatchFile(goctlHome, cmd string) (string, error) {
-	batFile := filepath.Join(goctlHome, ".generate.bat")
-	if !util.FileExists(batFile) {
-		err := ioutil.WriteFile(batFile, []byte(cmd), os.ModePerm)
-		if err != nil {
-			return "", err
+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 batFile, nil
+		return err
+	}
+	return nil
 }

+ 0 - 7
tools/goctl/util/path.go

@@ -5,7 +5,6 @@ import (
 	"os"
 	"path"
 	"path/filepath"
-	"runtime"
 	"strings"
 
 	"github.com/tal-tech/go-zero/tools/goctl/vars"
@@ -116,12 +115,6 @@ func FindProjectPath(loc string) (string, bool) {
 
 // ReadLink returns the destination of the named symbolic link recursively.
 func ReadLink(name string) (string, error) {
-	goos := runtime.GOOS
-	switch goos {
-	case vars.OsWindows:
-		return name, nil
-	}
-
 	name, err := filepath.Abs(name)
 	if err != nil {
 		return "", err