version.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // Package version provides the version command.
  2. package version
  3. import (
  4. "context"
  5. "errors"
  6. "fmt"
  7. "io"
  8. "net/http"
  9. "strings"
  10. "time"
  11. "github.com/coreos/go-semver/semver"
  12. "github.com/rclone/rclone/cmd"
  13. "github.com/rclone/rclone/fs"
  14. "github.com/rclone/rclone/fs/config/flags"
  15. "github.com/rclone/rclone/fs/fshttp"
  16. "github.com/spf13/cobra"
  17. )
  18. var (
  19. check = false
  20. )
  21. func init() {
  22. cmd.Root.AddCommand(commandDefinition)
  23. cmdFlags := commandDefinition.Flags()
  24. flags.BoolVarP(cmdFlags, &check, "check", "", false, "Check for new version", "")
  25. }
  26. var commandDefinition = &cobra.Command{
  27. Use: "version",
  28. Short: `Show the version number.`,
  29. Long: `
  30. Show the rclone version number, the go version, the build target
  31. OS and architecture, the runtime OS and kernel version and bitness,
  32. build tags and the type of executable (static or dynamic).
  33. For example:
  34. $ rclone version
  35. rclone v1.55.0
  36. - os/version: ubuntu 18.04 (64 bit)
  37. - os/kernel: 4.15.0-136-generic (x86_64)
  38. - os/type: linux
  39. - os/arch: amd64
  40. - go/version: go1.16
  41. - go/linking: static
  42. - go/tags: none
  43. Note: before rclone version 1.55 the os/type and os/arch lines were merged,
  44. and the "go/version" line was tagged as "go version".
  45. If you supply the --check flag, then it will do an online check to
  46. compare your version with the latest release and the latest beta.
  47. $ rclone version --check
  48. yours: 1.42.0.6
  49. latest: 1.42 (released 2018-06-16)
  50. beta: 1.42.0.5 (released 2018-06-17)
  51. Or
  52. $ rclone version --check
  53. yours: 1.41
  54. latest: 1.42 (released 2018-06-16)
  55. upgrade: https://downloads.rclone.org/v1.42
  56. beta: 1.42.0.5 (released 2018-06-17)
  57. upgrade: https://beta.rclone.org/v1.42-005-g56e1e820
  58. `,
  59. Annotations: map[string]string{
  60. "versionIntroduced": "v1.33",
  61. },
  62. Run: func(command *cobra.Command, args []string) {
  63. ctx := context.Background()
  64. cmd.CheckArgs(0, 0, command, args)
  65. if check {
  66. CheckVersion(ctx)
  67. } else {
  68. cmd.ShowVersion()
  69. }
  70. },
  71. }
  72. // strip a leading v off the string
  73. func stripV(s string) string {
  74. if len(s) > 0 && s[0] == 'v' {
  75. return s[1:]
  76. }
  77. return s
  78. }
  79. // GetVersion gets the version available for download
  80. func GetVersion(ctx context.Context, url string) (v *semver.Version, vs string, date time.Time, err error) {
  81. resp, err := fshttp.NewClient(ctx).Get(url)
  82. if err != nil {
  83. return v, vs, date, err
  84. }
  85. defer fs.CheckClose(resp.Body, &err)
  86. if resp.StatusCode != http.StatusOK {
  87. return v, vs, date, errors.New(resp.Status)
  88. }
  89. bodyBytes, err := io.ReadAll(resp.Body)
  90. if err != nil {
  91. return v, vs, date, err
  92. }
  93. vs = strings.TrimSpace(string(bodyBytes))
  94. vs = strings.TrimPrefix(vs, "rclone ")
  95. vs = strings.TrimRight(vs, "β")
  96. date, err = http.ParseTime(resp.Header.Get("Last-Modified"))
  97. if err != nil {
  98. return v, vs, date, err
  99. }
  100. v, err = semver.NewVersion(stripV(vs))
  101. return v, vs, date, err
  102. }
  103. // CheckVersion checks the installed version against available downloads
  104. func CheckVersion(ctx context.Context) {
  105. vCurrent, err := semver.NewVersion(stripV(fs.Version))
  106. if err != nil {
  107. fs.Errorf(nil, "Failed to parse version: %v", err)
  108. }
  109. const timeFormat = "2006-01-02"
  110. printVersion := func(what, url string) {
  111. v, vs, t, err := GetVersion(ctx, url+"version.txt")
  112. if err != nil {
  113. fs.Errorf(nil, "Failed to get rclone %s version: %v", what, err)
  114. return
  115. }
  116. fmt.Printf("%-8s%-40v %20s\n",
  117. what+":",
  118. v,
  119. "(released "+t.Format(timeFormat)+")",
  120. )
  121. if v.Compare(*vCurrent) > 0 {
  122. fmt.Printf(" upgrade: %s\n", url+vs)
  123. }
  124. }
  125. fmt.Printf("yours: %-13s\n", vCurrent)
  126. printVersion(
  127. "latest",
  128. "https://downloads.rclone.org/",
  129. )
  130. printVersion(
  131. "beta",
  132. "https://beta.rclone.org/",
  133. )
  134. if strings.HasSuffix(fs.Version, "-DEV") {
  135. fmt.Println("Your version is compiled from git so comparisons may be wrong.")
  136. }
  137. }