cmd_up.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. // Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. package cmd
  7. import (
  8. "context"
  9. "fmt"
  10. "runtime"
  11. "github.com/minio/selfupdate"
  12. "github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
  13. "github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
  14. "github.com/gogf/gf/v2/container/gset"
  15. "github.com/gogf/gf/v2/frame/g"
  16. "github.com/gogf/gf/v2/os/gfile"
  17. "github.com/gogf/gf/v2/os/gproc"
  18. "github.com/gogf/gf/v2/text/gstr"
  19. "github.com/gogf/gf/v2/util/gtag"
  20. )
  21. var (
  22. Up = cUp{}
  23. )
  24. type cUp struct {
  25. g.Meta `name:"up" brief:"upgrade GoFrame version/tool to latest one in current project" eg:"{cUpEg}" `
  26. }
  27. const (
  28. gfPackage = `github.com/gogf/gf/`
  29. cUpEg = `
  30. gf up
  31. gf up -a
  32. gf up -c
  33. gf up -cf
  34. `
  35. )
  36. func init() {
  37. gtag.Sets(g.MapStrStr{
  38. `cUpEg`: cUpEg,
  39. })
  40. }
  41. type cUpInput struct {
  42. g.Meta `name:"up" config:"gfcli.up"`
  43. All bool `name:"all" short:"a" brief:"upgrade both version and cli, auto fix codes" orphan:"true"`
  44. Cli bool `name:"cli" short:"c" brief:"also upgrade CLI tool" orphan:"true"`
  45. Fix bool `name:"fix" short:"f" brief:"auto fix codes(it only make sense if cli is to be upgraded)" orphan:"true"`
  46. }
  47. type cUpOutput struct{}
  48. func (c cUp) Index(ctx context.Context, in cUpInput) (out *cUpOutput, err error) {
  49. defer func() {
  50. if err == nil {
  51. mlog.Print()
  52. mlog.Print(`👏congratulations! you've upgraded to the latest version of GoFrame! enjoy it!👏`)
  53. mlog.Print()
  54. }
  55. }()
  56. var doUpgradeVersionOut *doUpgradeVersionOutput
  57. if in.All {
  58. in.Cli = true
  59. in.Fix = true
  60. }
  61. if doUpgradeVersionOut, err = c.doUpgradeVersion(ctx, in); err != nil {
  62. return nil, err
  63. }
  64. if in.Cli {
  65. if err = c.doUpgradeCLI(ctx); err != nil {
  66. return nil, err
  67. }
  68. }
  69. if in.Cli && in.Fix {
  70. if doUpgradeVersionOut != nil && len(doUpgradeVersionOut.Items) > 0 {
  71. upgradedPathSet := gset.NewStrSet()
  72. for _, item := range doUpgradeVersionOut.Items {
  73. if !upgradedPathSet.AddIfNotExist(item.DirPath) {
  74. continue
  75. }
  76. if err = c.doAutoFixing(ctx, item.DirPath, item.Version); err != nil {
  77. return nil, err
  78. }
  79. }
  80. }
  81. }
  82. return
  83. }
  84. type doUpgradeVersionOutput struct {
  85. Items []doUpgradeVersionOutputItem
  86. }
  87. type doUpgradeVersionOutputItem struct {
  88. DirPath string
  89. Version string
  90. }
  91. func (c cUp) doUpgradeVersion(ctx context.Context, in cUpInput) (out *doUpgradeVersionOutput, err error) {
  92. mlog.Print(`start upgrading version...`)
  93. out = &doUpgradeVersionOutput{
  94. Items: make([]doUpgradeVersionOutputItem, 0),
  95. }
  96. type Package struct {
  97. Name string
  98. Version string
  99. }
  100. var (
  101. temp string
  102. dirPath = gfile.Pwd()
  103. goModPath = gfile.Join(dirPath, "go.mod")
  104. )
  105. // It recursively upgrades the go.mod from sub folder to its parent folders.
  106. for {
  107. if gfile.Exists(goModPath) {
  108. var packages []Package
  109. err = gfile.ReadLines(goModPath, func(line string) error {
  110. line = gstr.Trim(line)
  111. line = gstr.TrimLeftStr(line, "require ")
  112. line = gstr.Trim(line)
  113. if gstr.HasPrefix(line, gfPackage) {
  114. array := gstr.SplitAndTrim(line, " ")
  115. packages = append(packages, Package{
  116. Name: array[0],
  117. Version: array[1],
  118. })
  119. }
  120. return nil
  121. })
  122. if err != nil {
  123. return
  124. }
  125. for _, pkg := range packages {
  126. mlog.Printf(`upgrading "%s" from "%s" to "latest"`, pkg.Name, pkg.Version)
  127. // go get -u
  128. command := fmt.Sprintf(`cd %s && go get -u %s@latest`, dirPath, pkg.Name)
  129. if err = gproc.ShellRun(ctx, command); err != nil {
  130. return
  131. }
  132. // go mod tidy
  133. if err = utils.GoModTidy(ctx, dirPath); err != nil {
  134. return nil, err
  135. }
  136. out.Items = append(out.Items, doUpgradeVersionOutputItem{
  137. DirPath: dirPath,
  138. Version: pkg.Version,
  139. })
  140. }
  141. return
  142. }
  143. temp = gfile.Dir(dirPath)
  144. if temp == "" || temp == dirPath {
  145. return
  146. }
  147. dirPath = temp
  148. goModPath = gfile.Join(dirPath, "go.mod")
  149. }
  150. }
  151. // doUpgradeCLI downloads the new version binary with process.
  152. func (c cUp) doUpgradeCLI(ctx context.Context) (err error) {
  153. mlog.Print(`start upgrading cli...`)
  154. var (
  155. downloadUrl = fmt.Sprintf(
  156. `https://github.com/gogf/gf/releases/latest/download/gf_%s_%s`,
  157. runtime.GOOS, runtime.GOARCH,
  158. )
  159. localSaveFilePath = gfile.SelfPath() + "~"
  160. )
  161. if runtime.GOOS == "windows" {
  162. downloadUrl += ".exe"
  163. }
  164. mlog.Printf(`start downloading "%s" to "%s", it may take some time`, downloadUrl, localSaveFilePath)
  165. err = utils.HTTPDownloadFileWithPercent(downloadUrl, localSaveFilePath)
  166. if err != nil {
  167. return err
  168. }
  169. defer func() {
  170. mlog.Printf(`new version cli binary is successfully installed to "%s"`, gfile.SelfPath())
  171. mlog.Printf(`remove temporary buffer file "%s"`, localSaveFilePath)
  172. _ = gfile.Remove(localSaveFilePath)
  173. }()
  174. // It fails if file not exist or its size is less than 1MB.
  175. if !gfile.Exists(localSaveFilePath) || gfile.Size(localSaveFilePath) < 1024*1024 {
  176. mlog.Fatalf(`download "%s" to "%s" failed`, downloadUrl, localSaveFilePath)
  177. }
  178. newFile, err := gfile.Open(localSaveFilePath)
  179. if err != nil {
  180. return err
  181. }
  182. // selfupdate
  183. err = selfupdate.Apply(newFile, selfupdate.Options{})
  184. if err != nil {
  185. return err
  186. }
  187. return
  188. }
  189. func (c cUp) doAutoFixing(ctx context.Context, dirPath string, version string) (err error) {
  190. mlog.Printf(`auto fixing directory path "%s" from version "%s" ...`, dirPath, version)
  191. command := fmt.Sprintf(`gf fix -p %s`, dirPath)
  192. _ = gproc.ShellRun(ctx, command)
  193. return
  194. }