소스 검색

fix #1014 (#1018)

* fix #1014

* remove unused code

* * optimize generate pb.go on Windows
* format code
* optimize console.go

* version rollback

Co-authored-by: anqiansong <anqiansong@bytedance.com>
anqiansong 3 년 전
부모
커밋
f0ed2370a3

+ 2 - 4
tools/goctl/rpc/cli/cli.go

@@ -6,10 +6,11 @@ import (
 	"path/filepath"
 	"runtime"
 
+	"github.com/urfave/cli"
+
 	"github.com/tal-tech/go-zero/tools/goctl/rpc/generator"
 	"github.com/tal-tech/go-zero/tools/goctl/util"
 	"github.com/tal-tech/go-zero/tools/goctl/util/env"
-	"github.com/urfave/cli"
 )
 
 // RPC is to generate rpc service code from a proto file by specifying a proto file using flag src,
@@ -57,9 +58,6 @@ func prepare() error {
 	if _, err := env.LookUpProtoc(); err != nil {
 		return err
 	}
-	if _, err := env.LookUpProtocGenGo(); err != nil {
-		return err
-	}
 	return nil
 }
 

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

@@ -1,8 +1,6 @@
 package generator
 
 import (
-	"os/exec"
-
 	"github.com/tal-tech/go-zero/tools/goctl/util/console"
 )
 
@@ -21,21 +19,3 @@ 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
-}

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

@@ -47,11 +47,6 @@ 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

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

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

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

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

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

@@ -2,45 +2,36 @@ package generator
 
 import (
 	"bytes"
-	"errors"
+	"fmt"
+	"io/ioutil"
+	"os"
 	"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, base := filepath.Split(proto.Src)
+	directory, _ := 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)
 	}
@@ -56,50 +47,88 @@ func (g *DefaultGenerator) GenPb(ctx DirContext, protoImportPath []string, proto
 		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
-		}
+	return g.generatePbWithVersion132(cw.String())
+}
 
-		optSet.AddStr(op)
-		cw.WriteString(" --go_opt=" + op)
+// 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
 	}
 
-	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 + "=."
+	err = util.MkdirIfNotExist(goctlHome)
+	if err != nil {
+		return err
 	}
 
-	if !optSet.Contains(currentFileOpt) {
-		cw.WriteString(currentFileOpt)
+	goctlHomeBin := filepath.Join(goctlHome, "bin")
+	err = util.MkdirIfNotExist(goctlHomeBin)
+	if err != nil {
+		return err
 	}
 
-	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;
+	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"
 
-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`)
+	if util.FileExists(protocGenGo) {
+		g.log.Success("protoc-gen-go exists ...")
+		goGetCmd = ""
+	} else {
+		g.log.Error("missing protoc-gen-go: downloading ...")
+	}
+
+	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
 		}
 
-		return err
+		g.log.Debug("%s", cmd)
+		cmd = batFile
+	default:
+		return fmt.Errorf("unsupported os: %s", goos)
+	}
+
+	_, 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)
+}
+
+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
+		}
 	}
-	return nil
+
+	return batFile, nil
 }

+ 22 - 4
tools/goctl/util/console/console.go

@@ -3,8 +3,11 @@ package console
 import (
 	"fmt"
 	"os"
+	"runtime"
 
 	"github.com/logrusorgru/aurora"
+
+	"github.com/tal-tech/go-zero/tools/goctl/vars"
 )
 
 type (
@@ -46,22 +49,22 @@ func (c *colorConsole) Info(format string, a ...interface{}) {
 
 func (c *colorConsole) Debug(format string, a ...interface{}) {
 	msg := fmt.Sprintf(format, a...)
-	fmt.Println(aurora.Blue(msg))
+	println(aurora.Blue(msg))
 }
 
 func (c *colorConsole) Success(format string, a ...interface{}) {
 	msg := fmt.Sprintf(format, a...)
-	fmt.Println(aurora.Green(msg))
+	println(aurora.Green(msg))
 }
 
 func (c *colorConsole) Warning(format string, a ...interface{}) {
 	msg := fmt.Sprintf(format, a...)
-	fmt.Println(aurora.Yellow(msg))
+	println(aurora.Yellow(msg))
 }
 
 func (c *colorConsole) Error(format string, a ...interface{}) {
 	msg := fmt.Sprintf(format, a...)
-	fmt.Println(aurora.Red(msg))
+	println(aurora.Red(msg))
 }
 
 func (c *colorConsole) Fatalln(format string, a ...interface{}) {
@@ -123,3 +126,18 @@ func (i *ideaConsole) Must(err error) {
 		i.Fatalln("%+v", err)
 	}
 }
+
+func println(msg interface{}) {
+	value, ok := msg.(aurora.Value)
+	if !ok {
+		fmt.Println(msg)
+	}
+
+	goos := runtime.GOOS
+	if goos == vars.OsWindows {
+		fmt.Println(value.Value())
+		return
+	}
+
+	fmt.Println(msg)
+}

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

@@ -5,6 +5,7 @@ import (
 	"os"
 	"path"
 	"path/filepath"
+	"runtime"
 	"strings"
 
 	"github.com/tal-tech/go-zero/tools/goctl/vars"
@@ -115,6 +116,12 @@ 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