mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-10 12:46:46 +00:00
GODT-1977: fix launcher for v2 to v3 updates.
This commit is contained in:
@ -56,6 +56,7 @@ const (
|
|||||||
func main() { //nolint:funlen
|
func main() { //nolint:funlen
|
||||||
logrus.SetLevel(logrus.DebugLevel)
|
logrus.SetLevel(logrus.DebugLevel)
|
||||||
l := logrus.WithField("launcher_version", constants.Version)
|
l := logrus.WithField("launcher_version", constants.Version)
|
||||||
|
|
||||||
reporter := sentry.NewReporter(appName, constants.Version, useragent.New())
|
reporter := sentry.NewReporter(appName, constants.Version, useragent.New())
|
||||||
|
|
||||||
crashHandler := crash.NewHandler(reporter.ReportException)
|
crashHandler := crash.NewHandler(reporter.ReportException)
|
||||||
@ -75,7 +76,7 @@ func main() { //nolint:funlen
|
|||||||
crashHandler.AddRecoveryAction(logging.DumpStackTrace(logsPath))
|
crashHandler.AddRecoveryAction(logging.DumpStackTrace(logsPath))
|
||||||
|
|
||||||
if err := logging.Init(logsPath, os.Getenv("VERBOSITY")); err != nil {
|
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()
|
updatesPath, err := locations.ProvideUpdatesPath()
|
||||||
@ -240,7 +241,7 @@ func getPathToUpdatedExecutable(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Skip versions that are less or equal to launcher version.
|
// 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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,10 +19,12 @@ package bridge
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
"github.com/ProtonMail/proton-bridge/v2/internal/events"
|
"github.com/ProtonMail/proton-bridge/v2/internal/events"
|
||||||
"github.com/ProtonMail/proton-bridge/v2/internal/safe"
|
"github.com/ProtonMail/proton-bridge/v2/internal/safe"
|
||||||
"github.com/ProtonMail/proton-bridge/v2/internal/updater"
|
"github.com/ProtonMail/proton-bridge/v2/internal/updater"
|
||||||
|
"github.com/ProtonMail/proton-bridge/v2/internal/versioner"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -58,7 +60,7 @@ func (bridge *Bridge) handleUpdate(version updater.VersionInfo) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case !version.Version.GreaterThan(bridge.curVersion):
|
case !versioner.IsNewerIgnorePrerelease(version.Version, bridge.curVersion):
|
||||||
log.Debug("No update available")
|
log.Debug("No update available")
|
||||||
|
|
||||||
bridge.publish(events.UpdateNotAvailable{})
|
bridge.publish(events.UpdateNotAvailable{})
|
||||||
@ -68,7 +70,7 @@ func (bridge *Bridge) handleUpdate(version updater.VersionInfo) {
|
|||||||
|
|
||||||
bridge.publish(events.UpdateNotAvailable{})
|
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")
|
log.Info("An update is available but is incompatible with this version")
|
||||||
|
|
||||||
bridge.publish(events.UpdateAvailable{
|
bridge.publish(events.UpdateAvailable{
|
||||||
@ -88,7 +90,7 @@ func (bridge *Bridge) handleUpdate(version updater.VersionInfo) {
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
safe.RLock(func() {
|
safe.RLock(func() {
|
||||||
if version.Version.GreaterThan(bridge.newVersion) {
|
if versioner.IsNewerIgnorePrerelease(version.Version, bridge.newVersion) {
|
||||||
log.Info("An update is available")
|
log.Info("An update is available")
|
||||||
|
|
||||||
select {
|
select {
|
||||||
@ -127,15 +129,21 @@ func (bridge *Bridge) installUpdate(ctx context.Context, job installJob) {
|
|||||||
Silent: job.silent,
|
Silent: job.silent,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err := bridge.updater.InstallUpdate(ctx, bridge.api, job.version); err != nil {
|
err := bridge.updater.InstallUpdate(ctx, bridge.api, job.version)
|
||||||
log.Error("The update could not be installed")
|
|
||||||
|
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{
|
bridge.publish(events.UpdateFailed{
|
||||||
Version: job.version,
|
Version: job.version,
|
||||||
Silent: job.silent,
|
Silent: job.silent,
|
||||||
Error: err,
|
Error: err,
|
||||||
})
|
})
|
||||||
} else {
|
default:
|
||||||
log.Info("The update was installed successfully")
|
log.Info("The update was installed successfully")
|
||||||
|
|
||||||
bridge.publish(events.UpdateInstalled{
|
bridge.publish(events.UpdateInstalled{
|
||||||
|
|||||||
@ -61,3 +61,7 @@ func (i *InstallerDarwin) InstallUpdate(_ *semver.Version, r io.Reader) error {
|
|||||||
|
|
||||||
return syncFolders(oldBundle, newBundle)
|
return syncFolders(oldBundle, newBundle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i *InstallerDarwin) IsAlreadyInstalled(version *semver.Version) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import (
|
|||||||
|
|
||||||
"github.com/Masterminds/semver/v3"
|
"github.com/Masterminds/semver/v3"
|
||||||
"github.com/ProtonMail/proton-bridge/v2/internal/versioner"
|
"github.com/ProtonMail/proton-bridge/v2/internal/versioner"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
type InstallerDefault struct {
|
type InstallerDefault struct {
|
||||||
@ -40,3 +41,15 @@ func NewInstaller(versioner *versioner.Versioner) *InstallerDefault {
|
|||||||
func (i *InstallerDefault) InstallUpdate(version *semver.Version, r io.Reader) error {
|
func (i *InstallerDefault) InstallUpdate(version *semver.Version, r io.Reader) error {
|
||||||
return i.versioner.InstallNewVersion(version, r)
|
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)
|
||||||
|
}
|
||||||
|
|||||||
@ -30,8 +30,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrDownloadVerify = errors.New("failed to download or verify the update")
|
ErrDownloadVerify = errors.New("failed to download or verify the update")
|
||||||
ErrInstall = errors.New("failed to install the update")
|
ErrInstall = errors.New("failed to install the update")
|
||||||
|
ErrUpdateAlreadyInstalled = errors.New("update is already installed")
|
||||||
)
|
)
|
||||||
|
|
||||||
type Downloader interface {
|
type Downloader interface {
|
||||||
@ -39,6 +40,7 @@ type Downloader interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Installer interface {
|
type Installer interface {
|
||||||
|
IsAlreadyInstalled(*semver.Version) bool
|
||||||
InstallUpdate(*semver.Version, io.Reader) error
|
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 {
|
func (u *Updater) InstallUpdate(ctx context.Context, downloader Downloader, update VersionInfo) error {
|
||||||
|
if u.installer.IsAlreadyInstalled(update.Version) {
|
||||||
|
return ErrUpdateAlreadyInstalled
|
||||||
|
}
|
||||||
|
|
||||||
b, err := downloader.DownloadAndVerify(
|
b, err := downloader.DownloadAndVerify(
|
||||||
ctx,
|
ctx,
|
||||||
u.verifier,
|
u.verifier,
|
||||||
|
|||||||
@ -50,6 +50,16 @@ func (v Versions) Swap(i, j int) {
|
|||||||
v[i], v[j] = v[j], v[i]
|
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 {
|
func (v *Version) String() string {
|
||||||
return fmt.Sprintf("%v", v.version)
|
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.
|
// 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.
|
// It returns an error if the executable is missing or does not have executable permissions set.
|
||||||
func (v *Version) GetExecutable(name string) (string, error) {
|
func (v *Version) GetExecutable(name string) (string, error) {
|
||||||
exe := filepath.Join(v.path, getExeName(name))
|
return getExecutableInDirectory(name, v.path)
|
||||||
|
|
||||||
if !fileExists(exe) || !fileIsExecutable(exe) {
|
|
||||||
return "", ErrNoExecutable
|
|
||||||
}
|
|
||||||
|
|
||||||
return exe, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove removes this version directory.
|
// Remove removes this version directory.
|
||||||
|
|||||||
@ -72,6 +72,10 @@ func (v *Versioner) ListVersions() (Versions, error) {
|
|||||||
// GetExecutableInDirectory returns the full path to the executable in the given directory, if present.
|
// 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.
|
// 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) {
|
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))
|
exe := filepath.Join(directory, getExeName(name))
|
||||||
|
|
||||||
if !fileExists(exe) || !fileIsExecutable(exe) {
|
if !fileExists(exe) || !fileIsExecutable(exe) {
|
||||||
@ -80,3 +84,10 @@ func (v *Versioner) GetExecutableInDirectory(name, directory string) (string, er
|
|||||||
|
|
||||||
return exe, nil
|
return exe, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsNewerIgnorePrerelease(a, b *semver.Version) bool {
|
||||||
|
aN, _ := a.SetPrerelease("")
|
||||||
|
bN, _ := b.SetPrerelease("")
|
||||||
|
|
||||||
|
return aN.GreaterThan(&bN)
|
||||||
|
}
|
||||||
|
|||||||
@ -27,6 +27,21 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"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) {
|
func TestListVersions(t *testing.T) {
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user