plugin.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. package plugin
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "io/ioutil"
  9. "net/http"
  10. "os"
  11. "os/exec"
  12. "path/filepath"
  13. "strings"
  14. "github.com/spf13/cobra"
  15. "github.com/zeromicro/go-zero/tools/goctl/api/parser"
  16. "github.com/zeromicro/go-zero/tools/goctl/api/spec"
  17. "github.com/zeromicro/go-zero/tools/goctl/rpc/execx"
  18. "github.com/zeromicro/go-zero/tools/goctl/util/pathx"
  19. )
  20. const pluginArg = "_plugin"
  21. // Plugin defines an api plugin
  22. type Plugin struct {
  23. Api *spec.ApiSpec
  24. ApiFilePath string
  25. Style string
  26. Dir string
  27. }
  28. var (
  29. // VarStringPlugin describes a plugin.
  30. VarStringPlugin string
  31. // VarStringDir describes a directory.
  32. VarStringDir string
  33. // VarStringAPI describes an API file.
  34. VarStringAPI string
  35. // VarStringStyle describes a style.
  36. VarStringStyle string
  37. )
  38. // PluginCommand is the entry of goctl api plugin
  39. func PluginCommand(_ *cobra.Command, _ []string) error {
  40. ex, err := os.Executable()
  41. if err != nil {
  42. panic(err)
  43. }
  44. plugin := VarStringPlugin
  45. if len(plugin) == 0 {
  46. return errors.New("missing plugin")
  47. }
  48. transferData, err := prepareArgs()
  49. if err != nil {
  50. return err
  51. }
  52. bin, args := getPluginAndArgs(plugin)
  53. bin, download, err := getCommand(bin)
  54. if err != nil {
  55. return err
  56. }
  57. if download {
  58. defer func() {
  59. _ = os.Remove(bin)
  60. }()
  61. }
  62. content, err := execx.Run(bin+" "+args, filepath.Dir(ex), bytes.NewBuffer(transferData))
  63. if err != nil {
  64. return err
  65. }
  66. fmt.Println(content)
  67. return nil
  68. }
  69. func prepareArgs() ([]byte, error) {
  70. apiPath := VarStringAPI
  71. var transferData Plugin
  72. if len(apiPath) > 0 && pathx.FileExists(apiPath) {
  73. api, err := parser.Parse(apiPath)
  74. if err != nil {
  75. return nil, err
  76. }
  77. transferData.Api = api
  78. }
  79. absApiFilePath, err := filepath.Abs(apiPath)
  80. if err != nil {
  81. return nil, err
  82. }
  83. transferData.ApiFilePath = absApiFilePath
  84. dirAbs, err := filepath.Abs(VarStringDir)
  85. if err != nil {
  86. return nil, err
  87. }
  88. transferData.Dir = dirAbs
  89. transferData.Style = VarStringStyle
  90. data, err := json.Marshal(transferData)
  91. if err != nil {
  92. return nil, err
  93. }
  94. return data, nil
  95. }
  96. func getCommand(arg string) (string, bool, error) {
  97. p, err := exec.LookPath(arg)
  98. if err == nil {
  99. abs, err := filepath.Abs(p)
  100. if err != nil {
  101. return "", false, err
  102. }
  103. return abs, false, nil
  104. }
  105. defaultErr := errors.New("invalid plugin value " + arg)
  106. if strings.HasPrefix(arg, "http") {
  107. items := strings.Split(arg, "/")
  108. if len(items) == 0 {
  109. return "", false, defaultErr
  110. }
  111. filename, err := filepath.Abs(pluginArg + items[len(items)-1])
  112. if err != nil {
  113. return "", false, err
  114. }
  115. err = downloadFile(filename, arg)
  116. if err != nil {
  117. return "", false, err
  118. }
  119. os.Chmod(filename, os.ModePerm)
  120. return filename, true, nil
  121. }
  122. return arg, false, nil
  123. }
  124. func downloadFile(filepath, url string) error {
  125. resp, err := http.Get(url)
  126. if err != nil {
  127. return err
  128. }
  129. defer func() {
  130. _ = resp.Body.Close()
  131. }()
  132. out, err := os.Create(filepath)
  133. if err != nil {
  134. return err
  135. }
  136. defer func() {
  137. _ = out.Close()
  138. }()
  139. _, err = io.Copy(out, resp.Body)
  140. return err
  141. }
  142. // NewPlugin returns contextual resources when written in other languages
  143. func NewPlugin() (*Plugin, error) {
  144. var plugin Plugin
  145. content, err := ioutil.ReadAll(os.Stdin)
  146. if err != nil {
  147. return nil, err
  148. }
  149. var info struct {
  150. ApiFilePath string
  151. Style string
  152. Dir string
  153. }
  154. err = json.Unmarshal(content, &info)
  155. if err != nil {
  156. return nil, err
  157. }
  158. plugin.ApiFilePath = info.ApiFilePath
  159. plugin.Style = info.Style
  160. plugin.Dir = info.Dir
  161. api, err := parser.Parse(info.ApiFilePath)
  162. if err != nil {
  163. return nil, err
  164. }
  165. plugin.Api = api
  166. return &plugin, nil
  167. }
  168. func getPluginAndArgs(arg string) (string, string) {
  169. i := strings.Index(arg, "=")
  170. if i <= 0 {
  171. return arg, ""
  172. }
  173. return trimQuote(arg[:i]), trimQuote(arg[i+1:])
  174. }
  175. func trimQuote(in string) string {
  176. in = strings.Trim(in, `"`)
  177. in = strings.Trim(in, `'`)
  178. in = strings.Trim(in, "`")
  179. return in
  180. }