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.
209 lines
4.4 KiB
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
|
|
}
|