You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
go-zero/tools/goctl/rpc/ctx/project.go

209 lines
4.4 KiB
Go

package ctx
import (
"errors"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"regexp"
"runtime"
"strings"
"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"
)
var (
errProtobufNotFound = errors.New("github.com/golang/protobuf is not found,please ensure you has already [go get github.com/golang/protobuf]")
)
const (
constGo = "go"
constProtoC = "protoc"
constGoModOn = "go env GO111MODULE"
constGoMod = "go env GOMOD"
constGoModCache = "go env GOMODCACHE"
constGoPath = "go env GOPATH"
constProtoCGenGo = "protoc-gen-go"
)
type (
Project struct {
Path string
Name string
GoPath string
Protobuf Protobuf
GoMod GoMod
}
GoMod struct {
ModOn bool
GoModCache string
GoMod string
Module string
}
Protobuf struct {
Path string
}
)
func prepare(log console.Console) (*Project, error) {
log.Info("check go env ...")
_, err := exec.LookPath(constGo)
if err != nil {
return nil, err
}
_, err = exec.LookPath(constProtoC)
if err != nil {
return nil, err
}
var (
goModOn bool
goMod, goModCache, module string
goPath string
name, path string
protobufModule string
)
ret, err := execx.Run(constGoModOn)
if err != nil {
return nil, err
}
goModOn = strings.TrimSpace(ret) == "on"
ret, err = execx.Run(constGoMod)
if err != nil {
return nil, err
}
goMod = strings.TrimSpace(ret)
ret, err = execx.Run(constGoModCache)
if err != nil {
return nil, err
}
goModCache = strings.TrimSpace(ret)
ret, err = execx.Run(constGoPath)
if err != nil {
return nil, err
}
goPath = strings.TrimSpace(ret)
src := filepath.Join(goPath, "src")
if len(goMod) > 0 {
if goModCache == "" {
goModCache = filepath.Join(goPath, "pkg", "mod")
}
path = filepath.Dir(goMod)
name = filepath.Base(path)
data, err := ioutil.ReadFile(goMod)
if err != nil {
return nil, err
}
module, err = matchModule(data)
if err != nil {
return nil, err
}
protobufModule, err = matchProtoBuf(data)
if err != nil {
return nil, err
}
} else {
if goModCache == "" {
goModCache = src
}
pwd, err := os.Getwd()
if err != nil {
return nil, err
}
if !strings.HasPrefix(pwd, src) {
return nil, fmt.Errorf("%s: project is not in go mod and go path", pwd)
}
r := strings.TrimPrefix(pwd, src+string(filepath.Separator))
name = filepath.Dir(r)
if name == "." {
name = r
}
path = filepath.Join(src, 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{
Name: name,
Path: path,
GoPath: goPath,
Protobuf: Protobuf{
Path: protobuf,
},
GoMod: GoMod{
ModOn: goModOn,
GoModCache: goModCache,
GoMod: goMod,
Module: module,
},
}, nil
}
// github.com/golang/protobuf@{version}
func matchProtoBuf(data []byte) (string, error) {
text := string(data)
re := regexp.MustCompile(`(?m)(github.com/golang/protobuf)\s+(v[0-9.]+)`)
matches := re.FindAllStringSubmatch(text, -1)
if len(matches) == 0 {
return "", errProtobufNotFound
}
groups := matches[0]
if len(groups) < 3 {
return "", errProtobufNotFound
}
return fmt.Sprintf("%s@%s", groups[1], groups[2]), nil
}
func matchModule(data []byte) (string, error) {
text := string(data)
re := regexp.MustCompile(`(?m)^\s*module\s+[a-z0-9/\-.]+$`)
matches := re.FindAllString(text, -1)
if len(matches) == 1 {
target := matches[0]
index := strings.Index(target, "module")
return strings.TrimSpace(target[index+6:]), nil
}
return "", nil
}