mirror of
https://github.com/rclone/rclone.git
synced 2026-10-09 22:45:26 -04:00
selfupdate: fix --version X.Y depending on ./ in the download site links
To find the latest patch release of a minor version, for example `rclone selfupdate --version 1.75`, selfupdate searched the listing of downloads.rclone.org for href="./vX.Y.Z/". The leading ./ is a detail of how Caddy's file server writes its links. A listing which linked to the same directories as "vX.Y.Z/", which is an equally valid relative URL, made selfupdate fail with "could not find the minor release". This makes the ./ optional in the pattern, so selfupdate no longer depends on which program wrote the listing, and takes the version from a capture group rather than from fixed offsets into the match. The listings written by rclone index now include the ./ for the benefit of rclone versions without this fix, so this is to remove the dependency for the future.
This commit is contained in:
1 parent
89521d875d
commit
8cd43746a3
2 files changed
+61
-7
No files matched your search
@@ -133,18 +133,28 @@ func GetVersion(ctx context.Context, beta bool, version string) (newVersion, sit
|
||||
if err != nil {
|
||||
return "", siteURL, fmt.Errorf("failed to get list of releases: %w", err)
|
||||
}
|
||||
reSubver := fmt.Sprintf(`href="\./%s\.\d+/"`, regexp.QuoteMeta(newVersion))
|
||||
allSubvers := regexp.MustCompile(reSubver).FindAllString(string(html), -1)
|
||||
if allSubvers == nil {
|
||||
return "", siteURL, errors.New("could not find the minor release")
|
||||
newVersion, err = latestMicroRelease(html, newVersion)
|
||||
if err != nil {
|
||||
return "", siteURL, err
|
||||
}
|
||||
// Use the fact that releases in the index are sorted by date
|
||||
lastSubver := allSubvers[len(allSubvers)-1]
|
||||
newVersion = lastSubver[8 : len(lastSubver)-2]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// latestMicroRelease returns the latest micro release of the
|
||||
// major.minor release version linked to from the HTML index of
|
||||
// releases.
|
||||
func latestMicroRelease(html []byte, version string) (string, error) {
|
||||
// The links may or may not start with ./ depending on what made the index
|
||||
reSubver := fmt.Sprintf(`href="(?:\./)?(%s\.\d+)/"`, regexp.QuoteMeta(version))
|
||||
allSubvers := regexp.MustCompile(reSubver).FindAllSubmatch(html, -1)
|
||||
if allSubvers == nil {
|
||||
return "", errors.New("could not find the minor release")
|
||||
}
|
||||
// Use the fact that releases in the index are sorted by date
|
||||
return string(allSubvers[len(allSubvers)-1][1]), nil
|
||||
}
|
||||
|
||||
// InstallUpdate performs rclone self-update
|
||||
func InstallUpdate(ctx context.Context, opt *Options) error {
|
||||
// Find the latest release number
|
||||
|
||||
@@ -45,6 +45,50 @@ func TestGetVersion(t *testing.T) {
|
||||
assert.Equal(t, "v1.52.3", resultVer)
|
||||
}
|
||||
|
||||
func TestLatestMicroRelease(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
html string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "caddy",
|
||||
html: `<a href="./v1.51.0/">v1.51.0/</a>
|
||||
<a href="./v1.52.0/">v1.52.0/</a>
|
||||
<a href="./v1.52.3/">v1.52.3/</a>
|
||||
<a href="./v1.53.0/">v1.53.0/</a>
|
||||
<a href="./v1.52-DEV/">v1.52-DEV/</a>
|
||||
<a href="./v1.52.3/rclone-v1.52.3-linux-amd64.zip">rclone</a>`,
|
||||
want: "v1.52.3",
|
||||
},
|
||||
{
|
||||
name: "no prefix",
|
||||
html: `<a href="v1.51.0/">v1.51.0/</a>
|
||||
<a href="v1.52.0/">v1.52.0/</a>
|
||||
<a href="v1.52.3/">v1.52.3/</a>
|
||||
<a href="v1.53.0/">v1.53.0/</a>`,
|
||||
want: "v1.52.3",
|
||||
},
|
||||
{
|
||||
name: "other prefix",
|
||||
html: `<a href="../v1.52.0/">v1.52.0/</a>
|
||||
<a href="https://example.com/v1.52.1/">v1.52.1/</a>
|
||||
<a href="v1.52.2/index.html">v1.52.2/</a>
|
||||
<a href="v1x52.3/">v1x52.3/</a>`,
|
||||
},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
got, err := latestMicroRelease([]byte(test.html), "v1.52")
|
||||
if test.want == "" {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, test.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInstallOnLinux(t *testing.T) {
|
||||
testy.SkipUnreliable(t)
|
||||
if runtime.GOOS != "linux" {
|
||||
|
||||
Reference in new issue
Block a user