diff --git a/cmd/version/version.go b/cmd/version/version.go index a98f459de..04f157e7f 100644 --- a/cmd/version/version.go +++ b/cmd/version/version.go @@ -7,11 +7,11 @@ import ( "strings" "time" + "github.com/coreos/go-semver/semver" "github.com/pkg/errors" "github.com/rclone/rclone/cmd" "github.com/rclone/rclone/fs" "github.com/rclone/rclone/fs/config/flags" - "github.com/rclone/rclone/fs/version" "github.com/spf13/cobra" ) @@ -66,8 +66,16 @@ Or }, } +// strip a leading v off the string +func stripV(s string) string { + if len(s) > 0 && s[0] == 'v' { + return s[1:] + } + return s +} + // getVersion gets the version by checking the download repository passed in -func getVersion(url string) (v version.Version, vs string, date time.Time, err error) { +func getVersion(url string) (v *semver.Version, vs string, date time.Time, err error) { resp, err := http.Get(url) if err != nil { return v, vs, date, err @@ -89,16 +97,16 @@ func getVersion(url string) (v version.Version, vs string, date time.Time, err e if err != nil { return v, vs, date, err } - v, err = version.New(vs) + v, err = semver.NewVersion(stripV(vs)) return v, vs, date, err } // check the current version against available versions func checkVersion() { // Get Current version - vCurrent, err := version.New(fs.Version) + vCurrent, err := semver.NewVersion(stripV(fs.Version)) if err != nil { - fs.Errorf(nil, "Failed to get parse version: %v", err) + fs.Errorf(nil, "Failed to parse version: %v", err) } const timeFormat = "2006-01-02" @@ -108,12 +116,12 @@ func checkVersion() { fs.Errorf(nil, "Failed to get rclone %s version: %v", what, err) return } - fmt.Printf("%-8s%-13v %20s\n", + fmt.Printf("%-8s%-40v %20s\n", what+":", v, "(released "+t.Format(timeFormat)+")", ) - if v.Cmp(vCurrent) > 0 { + if v.Compare(*vCurrent) > 0 { fmt.Printf(" upgrade: %s\n", url+vs) } } @@ -126,7 +134,7 @@ func checkVersion() { "beta", "https://beta.rclone.org/", ) - if vCurrent.IsGit() { + if strings.HasSuffix(fs.Version, "-DEV") { fmt.Println("Your version is compiled from git so comparisons may be wrong.") } } diff --git a/fs/rc/internal.go b/fs/rc/internal.go index 2c27cda88..24a13b865 100644 --- a/fs/rc/internal.go +++ b/fs/rc/internal.go @@ -8,13 +8,14 @@ import ( "os" "os/exec" "runtime" + "strings" "time" + "github.com/coreos/go-semver/semver" "github.com/pkg/errors" "github.com/rclone/rclone/fs" "github.com/rclone/rclone/fs/config/obscure" - "github.com/rclone/rclone/fs/version" "github.com/rclone/rclone/lib/atexit" ) @@ -171,10 +172,10 @@ func init() { Help: ` This shows the current version of go and the go runtime -- version - rclone version, eg "v1.44" -- decomposed - version number as [major, minor, patch, subpatch] - - note patch and subpatch will be 999 for a git compiled version +- version - rclone version, eg "v1.53.0" +- decomposed - version number as [major, minor, patch] - isGit - boolean - true if this was compiled from the git version +- isBeta - boolean - true if this is a beta version - os - OS in use as according to Go - arch - cpu architecture in use according to Go - goVersion - version of Go runtime in use @@ -185,14 +186,15 @@ This shows the current version of go and the go runtime // Return version info func rcVersion(ctx context.Context, in Params) (out Params, err error) { - decomposed, err := version.New(fs.Version) + version, err := semver.NewVersion(fs.Version[1:]) if err != nil { return nil, err } out = Params{ "version": fs.Version, - "decomposed": decomposed, - "isGit": decomposed.IsGit(), + "decomposed": version.Slice(), + "isGit": strings.HasSuffix(fs.Version, "-DEV"), + "isBeta": version.PreRelease != "", "os": runtime.GOOS, "arch": runtime.GOARCH, "goVersion": runtime.Version(), diff --git a/fs/rc/internal_test.go b/fs/rc/internal_test.go index c9e46a537..3eac2be57 100644 --- a/fs/rc/internal_test.go +++ b/fs/rc/internal_test.go @@ -14,7 +14,6 @@ import ( "github.com/rclone/rclone/fs" "github.com/rclone/rclone/fs/config/obscure" - "github.com/rclone/rclone/fs/version" ) func TestMain(m *testing.M) { @@ -106,7 +105,7 @@ func TestCoreVersion(t *testing.T) { assert.Equal(t, runtime.GOARCH, out["arch"]) assert.Equal(t, runtime.Version(), out["goVersion"]) _ = out["isGit"].(bool) - v := out["decomposed"].(version.Version) + v := out["decomposed"].([]int64) assert.True(t, len(v) >= 2) } diff --git a/fs/version.go b/fs/version.go index 5f1f636b4..0110ac8d3 100644 --- a/fs/version.go +++ b/fs/version.go @@ -1,4 +1,4 @@ package fs // Version of rclone -var Version = "v1.52.3-DEV" +var Version = "v1.53.0-DEV" diff --git a/fs/version/version.go b/fs/version/version.go deleted file mode 100644 index a2accfe0b..000000000 --- a/fs/version/version.go +++ /dev/null @@ -1,86 +0,0 @@ -package version - -import ( - "fmt" - "regexp" - "strconv" - "strings" - - "github.com/pkg/errors" - "github.com/rclone/rclone/fs" -) - -// Version represents a parsed rclone version number -type Version []int - -var parseVersion = regexp.MustCompile(`^(?:rclone )?v(\d+)\.(\d+)(?:\.(\d+))?(?:-(\d+)(?:-(g[\wβ-]+))?)?$`) - -// New parses a version number from a string -// -// This will be returned with up to 4 elements for major, minor, -// patch, subpatch release. -// -// If the version number represents a compiled from git version -// number, then it will be returned as major, minor, 999, 999 -func New(in string) (v Version, err error) { - isGit := strings.HasSuffix(in, "-DEV") - if isGit { - in = in[:len(in)-4] - } - r := parseVersion.FindStringSubmatch(in) - if r == nil { - return v, errors.Errorf("failed to match version string %q", in) - } - atoi := func(s string) int { - i, err := strconv.Atoi(s) - if err != nil { - fs.Errorf(nil, "Failed to parse %q as int from %q: %v", s, in, err) - } - return i - } - v = Version{ - atoi(r[1]), // major - atoi(r[2]), // minor - } - if r[3] != "" { - v = append(v, atoi(r[3])) // patch - } else if r[4] != "" { - v = append(v, 0) // patch - } - if r[4] != "" { - v = append(v, atoi(r[4])) // dev - } - if isGit { - v = append(v, 999, 999) - } - return v, nil -} - -// String converts v to a string -func (v Version) String() string { - var out []string - for _, vv := range v { - out = append(out, fmt.Sprint(vv)) - } - return strings.Join(out, ".") -} - -// Cmp compares two versions returning >0, <0 or 0 -func (v Version) Cmp(o Version) (d int) { - n := len(v) - if n > len(o) { - n = len(o) - } - for i := 0; i < n; i++ { - d = v[i] - o[i] - if d != 0 { - return d - } - } - return len(v) - len(o) -} - -// IsGit returns true if the current version was compiled from git -func (v Version) IsGit() bool { - return len(v) >= 4 && v[2] == 999 && v[3] == 999 -} diff --git a/fs/version/version_test.go b/fs/version/version_test.go deleted file mode 100644 index 42095b4aa..000000000 --- a/fs/version/version_test.go +++ /dev/null @@ -1,89 +0,0 @@ -package version - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestNew(t *testing.T) { - for _, test := range []struct { - in string - want Version - wantErr bool - }{ - {"v1.41", Version{1, 41}, false}, - {"rclone v1.41", Version{1, 41}, false}, - {"rclone v1.41.23", Version{1, 41, 23}, false}, - {"rclone v1.41.23-100", Version{1, 41, 23, 100}, false}, - {"rclone v1.41-100", Version{1, 41, 0, 100}, false}, - {"rclone v1.41.23-100-g12312a", Version{1, 41, 23, 100}, false}, - {"rclone v1.41-100-g12312a", Version{1, 41, 0, 100}, false}, - {"rclone v1.42-005-g56e1e820β", Version{1, 42, 0, 5}, false}, - {"rclone v1.42-005-g56e1e820-feature-branchβ", Version{1, 42, 0, 5}, false}, - - {"v1.41s", nil, true}, - {"rclone v1-41", nil, true}, - {"rclone v1.41.2c3", nil, true}, - {"rclone v1.41.23-100 potato", nil, true}, - {"rclone 1.41-100", nil, true}, - {"rclone v1.41.23-100-12312a", nil, true}, - - {"v1.41-DEV", Version{1, 41, 999, 999}, false}, - } { - what := fmt.Sprintf("in=%q", test.in) - got, err := New(test.in) - if test.wantErr { - assert.Error(t, err, what) - } else { - assert.NoError(t, err, what) - } - assert.Equal(t, test.want, got, what) - } - -} - -func TestCmp(t *testing.T) { - for _, test := range []struct { - a, b Version - want int - }{ - {Version{1}, Version{1}, 0}, - {Version{1}, Version{2}, -1}, - {Version{2}, Version{1}, 1}, - {Version{2}, Version{2, 1}, -1}, - {Version{2, 1}, Version{2}, 1}, - {Version{2, 1}, Version{2, 1}, 0}, - {Version{2, 1}, Version{2, 2}, -1}, - {Version{2, 2}, Version{2, 1}, 1}, - } { - got := test.a.Cmp(test.b) - if got < 0 { - got = -1 - } else if got > 0 { - got = 1 - } - assert.Equal(t, test.want, got, fmt.Sprintf("%v cmp %v", test.a, test.b)) - // test the reverse - got = -test.b.Cmp(test.a) - assert.Equal(t, test.want, got, fmt.Sprintf("%v cmp %v", test.b, test.a)) - } -} - -func TestString(t *testing.T) { - v, err := New("v1.44.1-2") - assert.NoError(t, err) - - assert.Equal(t, "1.44.1.2", v.String()) -} - -func TestIsGit(t *testing.T) { - v, err := New("v1.44") - assert.NoError(t, err) - assert.Equal(t, false, v.IsGit()) - - v, err = New("v1.44-DEV") - assert.NoError(t, err) - assert.Equal(t, true, v.IsGit()) -}