project.go 3.8 KB

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