project.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. package ctx
  2. import (
  3. "errors"
  4. "fmt"
  5. "io/ioutil"
  6. "os"
  7. "os/exec"
  8. "path/filepath"
  9. "regexp"
  10. "runtime"
  11. "strings"
  12. "github.com/tal-tech/go-zero/tools/goctl/rpc/execx"
  13. "github.com/tal-tech/go-zero/tools/goctl/util"
  14. "github.com/tal-tech/go-zero/tools/goctl/util/console"
  15. )
  16. var errProtobufNotFound = errors.New("github.com/golang/protobuf is not found,please ensure you has already [go get github.com/golang/protobuf]")
  17. const (
  18. constGo = "go"
  19. constProtoC = "protoc"
  20. constGoModOn = "go env GO111MODULE"
  21. constGoMod = "go env GOMOD"
  22. constGoModCache = "go env GOMODCACHE"
  23. constGoPath = "go env GOPATH"
  24. constProtoCGenGo = "protoc-gen-go"
  25. )
  26. type (
  27. Project struct {
  28. Path string
  29. Name string
  30. GoPath string
  31. Protobuf Protobuf
  32. GoMod GoMod
  33. }
  34. GoMod struct {
  35. ModOn bool
  36. GoModCache string
  37. GoMod string
  38. Module string
  39. }
  40. Protobuf struct {
  41. Path string
  42. }
  43. )
  44. func prepare(log console.Console) (*Project, error) {
  45. log.Info("checking go env...")
  46. _, err := exec.LookPath(constGo)
  47. if err != nil {
  48. return nil, err
  49. }
  50. _, err = exec.LookPath(constProtoC)
  51. if err != nil {
  52. return nil, err
  53. }
  54. var (
  55. goModOn bool
  56. goMod, goModCache, module string
  57. goPath string
  58. name, path string
  59. protobufModule string
  60. )
  61. ret, err := execx.Run(constGoModOn)
  62. if err != nil {
  63. return nil, err
  64. }
  65. goModOn = strings.TrimSpace(ret) == "on"
  66. ret, err = execx.Run(constGoMod)
  67. if err != nil {
  68. return nil, err
  69. }
  70. goMod = strings.TrimSpace(ret)
  71. ret, err = execx.Run(constGoModCache)
  72. if err != nil {
  73. return nil, err
  74. }
  75. goModCache = strings.TrimSpace(ret)
  76. ret, err = execx.Run(constGoPath)
  77. if err != nil {
  78. return nil, err
  79. }
  80. goPath = strings.TrimSpace(ret)
  81. src := filepath.Join(goPath, "src")
  82. if len(goMod) > 0 {
  83. if goModCache == "" {
  84. goModCache = filepath.Join(goPath, "pkg", "mod")
  85. }
  86. path = filepath.Dir(goMod)
  87. name = filepath.Base(path)
  88. data, err := ioutil.ReadFile(goMod)
  89. if err != nil {
  90. return nil, err
  91. }
  92. module, err = matchModule(data)
  93. if err != nil {
  94. return nil, err
  95. }
  96. } else {
  97. if goModCache == "" {
  98. goModCache = src
  99. }
  100. pwd, err := os.Getwd()
  101. if err != nil {
  102. return nil, err
  103. }
  104. if !strings.HasPrefix(pwd, src) {
  105. return nil, fmt.Errorf("%s: project is not in go mod and go path", pwd)
  106. }
  107. r := strings.TrimPrefix(pwd, src+string(filepath.Separator))
  108. name = filepath.Dir(r)
  109. if name == "." {
  110. name = r
  111. }
  112. path = filepath.Join(src, name)
  113. module = name
  114. }
  115. protobuf := filepath.Join(goModCache, protobufModule)
  116. if !util.FileExists(protobuf) {
  117. return nil, fmt.Errorf("expected protobuf module in path: %s,please ensure you has already [go get github.com/golang/protobuf]", protobuf)
  118. }
  119. var protoCGenGoFilename string
  120. os := runtime.GOOS
  121. switch os {
  122. case "darwin":
  123. protoCGenGoFilename = filepath.Join(goPath, "bin", "protoc-gen-go")
  124. case "windows":
  125. protoCGenGoFilename = filepath.Join(goPath, "bin", "protoc-gen-go.exe")
  126. default:
  127. return nil, fmt.Errorf("unexpeted os: %s", os)
  128. }
  129. if !util.FileExists(protoCGenGoFilename) {
  130. sh := "go install " + filepath.Join(protobuf, constProtoCGenGo)
  131. log.Warning(sh)
  132. stdout, err := execx.Run(sh)
  133. if err != nil {
  134. return nil, err
  135. }
  136. log.Info(stdout)
  137. }
  138. if !util.FileExists(protoCGenGoFilename) {
  139. return nil, fmt.Errorf("protoc-gen-go is not found")
  140. }
  141. return &Project{
  142. Name: name,
  143. Path: path,
  144. GoPath: goPath,
  145. Protobuf: Protobuf{
  146. Path: protobuf,
  147. },
  148. GoMod: GoMod{
  149. ModOn: goModOn,
  150. GoModCache: goModCache,
  151. GoMod: goMod,
  152. Module: module,
  153. },
  154. }, nil
  155. }
  156. func matchModule(data []byte) (string, error) {
  157. text := string(data)
  158. re := regexp.MustCompile(`(?m)^\s*module\s+[a-z0-9/\-.]+$`)
  159. matches := re.FindAllString(text, -1)
  160. if len(matches) == 1 {
  161. target := matches[0]
  162. index := strings.Index(target, "module")
  163. return strings.TrimSpace(target[index+6:]), nil
  164. }
  165. return "", nil
  166. }