1
0

plugin.go 3.9 KB

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