genpb.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. package generator
  2. import (
  3. "bytes"
  4. "errors"
  5. "os"
  6. "path/filepath"
  7. "strings"
  8. "github.com/zeromicro/go-zero/core/collection"
  9. conf "github.com/zeromicro/go-zero/tools/goctl/config"
  10. "github.com/zeromicro/go-zero/tools/goctl/rpc/execx"
  11. "github.com/zeromicro/go-zero/tools/goctl/rpc/parser"
  12. )
  13. const googleProtocGenGoErr = `--go_out: protoc-gen-go: plugins are not supported; use 'protoc --go-grpc_out=...' to generate gRPC`
  14. // GenPb generates the pb.go file, which is a layer of packaging for protoc to generate gprc,
  15. // but the commands and flags in protoc are not completely joined in goctl. At present, proto_path(-I) is introduced
  16. func (g *DefaultGenerator) GenPb(ctx DirContext, protoImportPath []string, proto parser.Proto, _ *conf.Config, c *ZRpcContext, goOptions ...string) error {
  17. if c != nil {
  18. return g.genPbDirect(c)
  19. }
  20. // deprecated: use genPbDirect instead.
  21. dir := ctx.GetPb()
  22. cw := new(bytes.Buffer)
  23. directory, base := filepath.Split(proto.Src)
  24. directory = filepath.Clean(directory)
  25. cw.WriteString("protoc ")
  26. protoImportPathSet := collection.NewSet()
  27. isSamePackage := true
  28. for _, ip := range protoImportPath {
  29. pip := " --proto_path=" + ip
  30. if protoImportPathSet.Contains(pip) {
  31. continue
  32. }
  33. abs, err := filepath.Abs(ip)
  34. if err != nil {
  35. return err
  36. }
  37. if abs == directory {
  38. isSamePackage = true
  39. } else {
  40. isSamePackage = false
  41. }
  42. protoImportPathSet.AddStr(pip)
  43. cw.WriteString(pip)
  44. }
  45. currentPath := " --proto_path=" + directory
  46. if !protoImportPathSet.Contains(currentPath) {
  47. cw.WriteString(currentPath)
  48. }
  49. cw.WriteString(" " + proto.Name)
  50. if strings.Contains(proto.GoPackage, "/") {
  51. cw.WriteString(" --go_out=plugins=grpc:" + ctx.GetMain().Filename)
  52. } else {
  53. cw.WriteString(" --go_out=plugins=grpc:" + dir.Filename)
  54. }
  55. // Compatible with version 1.4.0,github.com/golang/protobuf/protoc-gen-go@v1.4.0
  56. // --go_opt usage please see https://developers.google.com/protocol-buffers/docs/reference/go-generated#package
  57. optSet := collection.NewSet()
  58. for _, op := range goOptions {
  59. opt := " --go_opt=" + op
  60. if optSet.Contains(opt) {
  61. continue
  62. }
  63. optSet.AddStr(op)
  64. cw.WriteString(" --go_opt=" + op)
  65. }
  66. var currentFileOpt string
  67. if !isSamePackage || (len(proto.GoPackage) > 0 && proto.GoPackage != proto.Package.Name) {
  68. if filepath.IsAbs(proto.GoPackage) {
  69. currentFileOpt = " --go_opt=M" + base + "=" + proto.GoPackage
  70. } else if strings.Contains(proto.GoPackage, string(filepath.Separator)) {
  71. currentFileOpt = " --go_opt=M" + base + "=./" + proto.GoPackage
  72. } else {
  73. currentFileOpt = " --go_opt=M" + base + "=../" + proto.GoPackage
  74. }
  75. } else {
  76. currentFileOpt = " --go_opt=M" + base + "=."
  77. }
  78. if !optSet.Contains(currentFileOpt) {
  79. cw.WriteString(currentFileOpt)
  80. }
  81. command := cw.String()
  82. g.log.Debug(command)
  83. _, err := execx.Run(command, "")
  84. if err != nil {
  85. if strings.Contains(err.Error(), googleProtocGenGoErr) {
  86. return errors.New(`unsupported plugin protoc-gen-go which installed from the following source:
  87. google.golang.org/protobuf/cmd/protoc-gen-go,
  88. github.com/protocolbuffers/protobuf-go/cmd/protoc-gen-go;
  89. Please replace it by the following command, we recommend to use version before v1.3.5:
  90. go get -u github.com/golang/protobuf/protoc-gen-go`)
  91. }
  92. return err
  93. }
  94. return nil
  95. }
  96. func (g *DefaultGenerator) genPbDirect(c *ZRpcContext) error {
  97. g.log.Debug(c.ProtocCmd)
  98. pwd, err := os.Getwd()
  99. if err != nil {
  100. return err
  101. }
  102. _, err = execx.Run(c.ProtocCmd, pwd)
  103. return err
  104. }