goctl.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. package main
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "net/http"
  6. "net/url"
  7. "os"
  8. "os/user"
  9. "path"
  10. "path/filepath"
  11. "time"
  12. "zero/core/conf"
  13. "zero/core/hash"
  14. "zero/core/lang"
  15. "zero/core/logx"
  16. "zero/core/mapreduce"
  17. "zero/core/stringx"
  18. "zero/tools/goctl/api/apigen"
  19. "zero/tools/goctl/api/dartgen"
  20. "zero/tools/goctl/api/docgen"
  21. "zero/tools/goctl/api/format"
  22. "zero/tools/goctl/api/gogen"
  23. "zero/tools/goctl/api/javagen"
  24. "zero/tools/goctl/api/tsgen"
  25. "zero/tools/goctl/api/validate"
  26. "zero/tools/goctl/configgen"
  27. "zero/tools/goctl/docker"
  28. "zero/tools/goctl/feature"
  29. "zero/tools/goctl/model/mongomodel"
  30. "zero/tools/goctl/util"
  31. "github.com/logrusorgru/aurora"
  32. "github.com/urfave/cli"
  33. )
  34. const (
  35. autoUpdate = "GOCTL_AUTO_UPDATE"
  36. configFile = ".goctl"
  37. configTemplate = `url = http://47.97.184.41:7777/`
  38. toolName = "goctl"
  39. )
  40. var (
  41. BuildTime = "not set"
  42. commands = []cli.Command{
  43. {
  44. Name: "api",
  45. Usage: "generate api related files",
  46. Flags: []cli.Flag{
  47. cli.StringFlag{
  48. Name: "o",
  49. Usage: "the output api file",
  50. },
  51. },
  52. Action: apigen.ApiCommand,
  53. Subcommands: []cli.Command{
  54. {
  55. Name: "format",
  56. Usage: "format api files",
  57. Flags: []cli.Flag{
  58. cli.StringFlag{
  59. Name: "dir",
  60. Usage: "the format target dir",
  61. },
  62. cli.BoolFlag{
  63. Name: "p",
  64. Usage: "print result to console",
  65. },
  66. cli.BoolFlag{
  67. Name: "iu",
  68. Usage: "ignore update",
  69. Required: false,
  70. },
  71. },
  72. Action: format.GoFormatApi,
  73. },
  74. {
  75. Name: "validate",
  76. Usage: "validate api file",
  77. Flags: []cli.Flag{
  78. cli.StringFlag{
  79. Name: "api",
  80. Usage: "validate target api file",
  81. },
  82. },
  83. Action: validate.GoValidateApi,
  84. },
  85. {
  86. Name: "doc",
  87. Usage: "generate doc files",
  88. Flags: []cli.Flag{
  89. cli.StringFlag{
  90. Name: "dir",
  91. Usage: "the target dir",
  92. },
  93. },
  94. Action: docgen.DocCommand,
  95. },
  96. {
  97. Name: "go",
  98. Usage: "generate go files for provided api in yaml file",
  99. Flags: []cli.Flag{
  100. cli.StringFlag{
  101. Name: "dir",
  102. Usage: "the target dir",
  103. },
  104. cli.StringFlag{
  105. Name: "api",
  106. Usage: "the api file",
  107. },
  108. },
  109. Action: gogen.GoCommand,
  110. },
  111. {
  112. Name: "java",
  113. Usage: "generate java files for provided api in api file",
  114. Flags: []cli.Flag{
  115. cli.StringFlag{
  116. Name: "dir",
  117. Usage: "the target dir",
  118. },
  119. cli.StringFlag{
  120. Name: "api",
  121. Usage: "the api file",
  122. },
  123. },
  124. Action: javagen.JavaCommand,
  125. },
  126. {
  127. Name: "ts",
  128. Usage: "generate ts files for provided api in api file",
  129. Flags: []cli.Flag{
  130. cli.StringFlag{
  131. Name: "dir",
  132. Usage: "the target dir",
  133. },
  134. cli.StringFlag{
  135. Name: "api",
  136. Usage: "the api file",
  137. },
  138. cli.StringFlag{
  139. Name: "webapi",
  140. Usage: "the web api file path",
  141. Required: false,
  142. },
  143. cli.StringFlag{
  144. Name: "caller",
  145. Usage: "the web api caller",
  146. Required: false,
  147. },
  148. cli.BoolFlag{
  149. Name: "unwrap",
  150. Usage: "unwrap the webapi caller for import",
  151. Required: false,
  152. },
  153. },
  154. Action: tsgen.TsCommand,
  155. },
  156. {
  157. Name: "dart",
  158. Usage: "generate dart files for provided api in api file",
  159. Flags: []cli.Flag{
  160. cli.StringFlag{
  161. Name: "dir",
  162. Usage: "the target dir",
  163. },
  164. cli.StringFlag{
  165. Name: "api",
  166. Usage: "the api file",
  167. },
  168. },
  169. Action: dartgen.DartCommand,
  170. },
  171. },
  172. },
  173. {
  174. Name: "docker",
  175. Usage: "generate Dockerfile and Makefile",
  176. Flags: []cli.Flag{
  177. cli.StringFlag{
  178. Name: "go",
  179. Usage: "the file that contains main function",
  180. },
  181. cli.StringFlag{
  182. Name: "namespace, n",
  183. Usage: "which namespace of kubernetes to deploy the service",
  184. },
  185. },
  186. Action: docker.DockerCommand,
  187. },
  188. {
  189. Name: "model",
  190. Usage: "generate sql model",
  191. Flags: []cli.Flag{
  192. cli.StringFlag{
  193. Name: "config, c",
  194. Usage: "the file that contains main function",
  195. },
  196. cli.StringFlag{
  197. Name: "dir, d",
  198. Usage: "the target dir",
  199. },
  200. },
  201. Subcommands: []cli.Command{
  202. {
  203. Name: "mongo",
  204. Usage: "generate mongoModel files for provided somemongo.go in go file",
  205. Flags: []cli.Flag{
  206. cli.StringFlag{
  207. Name: "src, s",
  208. Usage: "the src file",
  209. },
  210. cli.StringFlag{
  211. Name: "cache",
  212. Usage: "need cache code([yes/no] default value is no)",
  213. },
  214. },
  215. Action: mongomodel.ModelCommond,
  216. },
  217. },
  218. },
  219. {
  220. Name: "config",
  221. Usage: "generate config json",
  222. Flags: []cli.Flag{
  223. cli.StringFlag{
  224. Name: "path, p",
  225. Usage: "the target config go file",
  226. },
  227. },
  228. Action: configgen.GenConfigCommand,
  229. },
  230. {
  231. Name: "feature",
  232. Usage: "the features of the latest version",
  233. Action: feature.Feature,
  234. },
  235. }
  236. )
  237. func genConfigFile(file string) error {
  238. return ioutil.WriteFile(file, []byte(configTemplate), 0600)
  239. }
  240. func getAbsFile() (string, error) {
  241. exe, err := os.Executable()
  242. if err != nil {
  243. return "", err
  244. }
  245. dir, err := filepath.Abs(filepath.Dir(exe))
  246. if err != nil {
  247. return "", err
  248. }
  249. return path.Join(dir, filepath.Base(os.Args[0])), nil
  250. }
  251. func getFilePerm(file string) (os.FileMode, error) {
  252. info, err := os.Stat(file)
  253. if err != nil {
  254. return 0, err
  255. }
  256. return info.Mode(), nil
  257. }
  258. func update() {
  259. usr, err := user.Current()
  260. if err != nil {
  261. fmt.Println(err)
  262. return
  263. }
  264. absConfigFile := path.Join(usr.HomeDir, configFile)
  265. if !util.FileExists(absConfigFile) {
  266. if err := genConfigFile(absConfigFile); err != nil {
  267. fmt.Println(err)
  268. return
  269. }
  270. }
  271. props, err := conf.LoadProperties(absConfigFile)
  272. if err != nil {
  273. fmt.Println(err)
  274. return
  275. }
  276. u, err := url.Parse(props.GetString("url"))
  277. if err != nil {
  278. fmt.Println(err)
  279. return
  280. }
  281. u.Path = path.Join(u.Path, toolName)
  282. req, err := http.NewRequest(http.MethodGet, u.String(), nil)
  283. if err != nil {
  284. fmt.Println(err)
  285. return
  286. }
  287. file, err := getAbsFile()
  288. if err != nil {
  289. fmt.Println(err)
  290. return
  291. }
  292. content, err := ioutil.ReadFile(file)
  293. if err != nil {
  294. fmt.Println(err)
  295. return
  296. }
  297. req.Header.Set("Content-Md5", hash.Md5Hex(content))
  298. resp, err := http.DefaultClient.Do(req)
  299. if err != nil {
  300. fmt.Println(err)
  301. return
  302. }
  303. defer resp.Body.Close()
  304. mode, err := getFilePerm(file)
  305. if err != nil {
  306. fmt.Println(err)
  307. return
  308. }
  309. content, err = ioutil.ReadAll(resp.Body)
  310. if err != nil {
  311. fmt.Println(err)
  312. return
  313. }
  314. switch resp.StatusCode {
  315. case http.StatusOK:
  316. if err := ioutil.WriteFile(file, content, mode); err != nil {
  317. fmt.Println(err)
  318. }
  319. }
  320. }
  321. func main() {
  322. logx.Disable()
  323. done := make(chan lang.PlaceholderType)
  324. mapreduce.FinishVoid(func() {
  325. if os.Getenv(autoUpdate) != "off" && !stringx.Contains(os.Args, "-iu") {
  326. update()
  327. }
  328. close(done)
  329. }, func() {
  330. app := cli.NewApp()
  331. app.Usage = "a cli tool to generate code"
  332. app.Version = BuildTime
  333. app.Commands = commands
  334. // cli already print error messages
  335. if err := app.Run(os.Args); err != nil {
  336. fmt.Println("error:", err)
  337. }
  338. }, func() {
  339. select {
  340. case <-done:
  341. case <-time.After(time.Second):
  342. fmt.Println(aurora.Yellow("Updating goctl, please wait..."))
  343. }
  344. })
  345. }