GODT-1977: fix launcher for v2 to v3 updates.

This commit is contained in:
Jakub
2022-11-03 14:01:26 +01:00
committed by James Houlahan
parent 34213d1607
commit c08d0eff7a
8 changed files with 79 additions and 17 deletions

View File

@ -56,6 +56,7 @@ const (
func main() { //nolint:funlen
logrus.SetLevel(logrus.DebugLevel)
l := logrus.WithField("launcher_version", constants.Version)
reporter := sentry.NewReporter(appName, constants.Version, useragent.New())
crashHandler := crash.NewHandler(reporter.ReportException)
@ -75,7 +76,7 @@ func main() { //nolint:funlen
crashHandler.AddRecoveryAction(logging.DumpStackTrace(logsPath))
if err := logging.Init(logsPath, os.Getenv("VERBOSITY")); err != nil {
logrus.WithError(err).Fatal("Failed to setup logging")
l.WithError(err).Fatal("Failed to setup logging")
}
updatesPath, err := locations.ProvideUpdatesPath()
@ -240,7 +241,7 @@ func getPathToUpdatedExecutable(
}
// Skip versions that are less or equal to launcher version.
if currentVersion != nil && !version.SemVer().GreaterThan(currentVersion) {
if currentVersion != nil && !versioner.IsNewerIgnorePrerelease(version.SemVer(), currentVersion) {
continue
}

View File

@ -19,10 +19,12 @@ package bridge
import (
"context"
"errors"
"github.com/ProtonMail/proton-bridge/v2/internal/events"
"github.com/ProtonMail/proton-bridge/v2/internal/safe"
"github.com/ProtonMail/proton-bridge/v2/internal/updater"
"github.com/ProtonMail/proton-bridge/v2/internal/versioner"
"github.com/sirupsen/logrus"
)
@ -58,7 +60,7 @@ func (bridge *Bridge) handleUpdate(version updater.VersionInfo) {
})
switch {
case !version.Version.GreaterThan(bridge.curVersion):
case !versioner.IsNewerIgnorePrerelease(version.Version, bridge.curVersion):
log.Debug("No update available")
bridge.publish(events.UpdateNotAvailable{})
@ -68,7 +70,7 @@ func (bridge *Bridge) handleUpdate(version updater.VersionInfo) {
bridge.publish(events.UpdateNotAvailable{})
case bridge.curVersion.LessThan(version.MinAuto):
case versioner.IsNewerIgnorePrerelease(version.MinAuto, bridge.curVersion):
log.Info("An update is available but is incompatible with this version")
bridge.publish(events.UpdateAvailable{
@ -88,7 +90,7 @@ func (bridge *Bridge) handleUpdate(version updater.VersionInfo) {
default:
safe.RLock(func() {
if version.Version.GreaterThan(bridge.newVersion) {
if versioner.IsNewerIgnorePrerelease(version.Version, bridge.newVersion) {
log.Info("An update is available")
select {
@ -127,15 +129,21 @@ func (bridge *Bridge) installUpdate(ctx context.Context, job installJob) {
Silent: job.silent,
})
if err := bridge.updater.InstallUpdate(ctx, bridge.api, job.version); err != nil {
log.Error("The update could not be installed")
err := bridge.updater.InstallUpdate(ctx, bridge.api, job.version)
switch {
case errors.Is(err, updater.ErrUpdateAlreadyInstalled):
log.Info("The update was already installed")
case err != nil:
log.WithError(err).Error("The update could not be installed")
bridge.publish(events.UpdateFailed{
Version: job.version,
Silent: job.silent,
Error: err,
})
} else {
default:
log.Info("The update was installed successfully")
bridge.publish(events.UpdateInstalled{

View File

@ -61,3 +61,7 @@ func (i *InstallerDarwin) InstallUpdate(_ *semver.Version, r io.Reader) error {
return syncFolders(oldBundle, newBundle)
}
func (i *InstallerDarwin) IsAlreadyInstalled(version *semver.Version) bool {
return false
}

View File

@ -25,6 +25,7 @@ import (
"github.com/Masterminds/semver/v3"
"github.com/ProtonMail/proton-bridge/v2/internal/versioner"
"github.com/sirupsen/logrus"
)
type InstallerDefault struct {
@ -40,3 +41,15 @@ func NewInstaller(versioner *versioner.Versioner) *InstallerDefault {
func (i *InstallerDefault) InstallUpdate(version *semver.Version, r io.Reader) error {
return i.versioner.InstallNewVersion(version, r)
}
func (i *InstallerDefault) IsAlreadyInstalled(version *semver.Version) bool {
versions, err := i.versioner.ListVersions()
if err != nil {
logrus.WithField("version", version).
WithError(err).Error("Failed to determine whether version is installed")
return false
}
return versions.HasVersion(version)
}

View File

@ -30,8 +30,9 @@ import (
)
var (
ErrDownloadVerify = errors.New("failed to download or verify the update")
ErrInstall = errors.New("failed to install the update")
ErrDownloadVerify = errors.New("failed to download or verify the update")
ErrInstall = errors.New("failed to install the update")
ErrUpdateAlreadyInstalled = errors.New("update is already installed")
)
type Downloader interface {
@ -39,6 +40,7 @@ type Downloader interface {
}
type Installer interface {
IsAlreadyInstalled(*semver.Version) bool
InstallUpdate(*semver.Version, io.Reader) error
}
@ -84,6 +86,10 @@ func (u *Updater) GetVersionInfo(ctx context.Context, downloader Downloader, cha
}
func (u *Updater) InstallUpdate(ctx context.Context, downloader Downloader, update VersionInfo) error {
if u.installer.IsAlreadyInstalled(update.Version) {
return ErrUpdateAlreadyInstalled
}
b, err := downloader.DownloadAndVerify(
ctx,
u.verifier,

View File

@ -50,6 +50,16 @@ func (v Versions) Swap(i, j int) {
v[i], v[j] = v[j], v[i]
}
func (v Versions) HasVersion(want *semver.Version) bool {
for i := range v {
if v[i].version.Equal(want) {
return true
}
}
return false
}
func (v *Version) String() string {
return fmt.Sprintf("%v", v.version)
}
@ -101,13 +111,7 @@ func (v *Version) VerifyFiles(kr *crypto.KeyRing) error {
// GetExecutable returns the full path to the executable of the given version.
// It returns an error if the executable is missing or does not have executable permissions set.
func (v *Version) GetExecutable(name string) (string, error) {
exe := filepath.Join(v.path, getExeName(name))
if !fileExists(exe) || !fileIsExecutable(exe) {
return "", ErrNoExecutable
}
return exe, nil
return getExecutableInDirectory(name, v.path)
}
// Remove removes this version directory.

View File

@ -72,6 +72,10 @@ func (v *Versioner) ListVersions() (Versions, error) {
// GetExecutableInDirectory returns the full path to the executable in the given directory, if present.
// It returns an error if the executable is missing or does not have executable permissions set.
func (v *Versioner) GetExecutableInDirectory(name, directory string) (string, error) {
return getExecutableInDirectory(name, directory)
}
func getExecutableInDirectory(name, directory string) (string, error) {
exe := filepath.Join(directory, getExeName(name))
if !fileExists(exe) || !fileIsExecutable(exe) {
@ -80,3 +84,10 @@ func (v *Versioner) GetExecutableInDirectory(name, directory string) (string, er
return exe, nil
}
func IsNewerIgnorePrerelease(a, b *semver.Version) bool {
aN, _ := a.SetPrerelease("")
bN, _ := b.SetPrerelease("")
return aN.GreaterThan(&bN)
}

View File

@ -27,6 +27,21 @@ import (
"github.com/stretchr/testify/require"
)
func TestIsNewerIgnorePrelease(t *testing.T) {
// older
assert.False(t, IsNewerIgnorePrerelease(semver.MustParse("2.5.0"), semver.MustParse("2.5.1")))
assert.False(t, IsNewerIgnorePrerelease(semver.MustParse("2.5.0"), semver.MustParse("2.5.0")))
assert.False(t, IsNewerIgnorePrerelease(semver.MustParse("2.5.0"), semver.MustParse("2.5.0+qa")))
assert.False(t, IsNewerIgnorePrerelease(semver.MustParse("2.5.0"), semver.MustParse("2.5.0-dev")))
assert.False(t, IsNewerIgnorePrerelease(semver.MustParse("2.5.0"), semver.MustParse("2.5.0-dev+qa")))
assert.False(t, IsNewerIgnorePrerelease(semver.MustParse("2.5.0+qa"), semver.MustParse("2.5.0-dev")))
assert.False(t, IsNewerIgnorePrerelease(semver.MustParse("2.5.0-dev"), semver.MustParse("2.5.0+qa")))
// not older
assert.True(t, IsNewerIgnorePrerelease(semver.MustParse("2.5.0"), semver.MustParse("2.4.9-dev+qa")))
assert.True(t, IsNewerIgnorePrerelease(semver.MustParse("2.5.0-dev+qa"), semver.MustParse("2.4.9")))
}
func TestListVersions(t *testing.T) {
dir := t.TempDir()