package project import ( "errors" "fmt" "io/ioutil" "os" "os/exec" "path/filepath" "regexp" "strings" "github.com/tal-tech/go-zero/tools/goctl/rpc/execx" ) const ( constGo = "go" constProtoC = "protoc" constGoMod = "go env GOMOD" constGoPath = "go env GOPATH" constProtoCGenGo = "protoc-gen-go" ) type ( Project struct { Path string // Project path name Name string // Project name Package string // The service related package // true-> project in go path or project init with go mod,or else->false IsInGoEnv bool GoMod GoMod } GoMod struct { Module string // The gomod module name Path string // The gomod related path } ) func Prepare(projectDir string, checkGrpcEnv bool) (*Project, error) { _, err := exec.LookPath(constGo) if err != nil { return nil, fmt.Errorf("please install go first,reference documents:「https://golang.org/doc/install」") } if checkGrpcEnv { _, err = exec.LookPath(constProtoC) if err != nil { return nil, fmt.Errorf("please install protoc first,reference documents:「https://github.com/golang/protobuf」") } _, err = exec.LookPath(constProtoCGenGo) if err != nil { return nil, fmt.Errorf("please install plugin protoc-gen-go first,reference documents:「https://github.com/golang/protobuf」") } } var ( goMod, module string goPath string name, path string pkg string ) ret, err := execx.Run(constGoMod, projectDir) if err != nil { return nil, err } goMod = strings.TrimSpace(ret) if goMod == os.DevNull { goMod = "" } ret, err = execx.Run(constGoPath, "") if err != nil { return nil, err } goPath = strings.TrimSpace(ret) src := filepath.Join(goPath, "src") var isInGoEnv = true if len(goMod) > 0 { 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 } } else { pwd, err := filepath.Abs(projectDir) if err != nil { return nil, err } if !strings.HasPrefix(pwd, src) { name = filepath.Clean(filepath.Base(pwd)) path = projectDir pkg = name isInGoEnv = false } else { r := strings.TrimPrefix(pwd, src+string(filepath.Separator)) name = filepath.Dir(r) if name == "." { name = r } path = filepath.Join(src, name) pkg = r } module = name } return &Project{ Name: name, Path: path, Package: strings.ReplaceAll(pkg, `\`, "/"), IsInGoEnv: isInGoEnv, GoMod: GoMod{ Module: module, Path: goMod, }, }, 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 "", errors.New("module not matched") }