Updater: Fix corner cases related to failed auto-updates

- Don't re-download updates whom's auto-install has clearly failed before
- Don't signal newly available auto-upgrade if it has failed once
- Remove downloaded update after (un)successful auto-update
- Remove as many temporary keys after an (un)successful auto-update
This commit is contained in:
Daniel Molkentin 2014-01-31 12:42:00 +01:00
parent 4c6e0b5c07
commit b3683976ca
6 changed files with 48 additions and 44 deletions

View file

@ -80,6 +80,7 @@ void GeneralSettings::slotUpdateInfo()
{
connect(updater, SIGNAL(downloadStateChanged()), SLOT(slotUpdateInfo()), Qt::UniqueConnection);
connect(_ui->restartButton, SIGNAL(clicked()), updater, SLOT(slotStartInstaller()), Qt::UniqueConnection);
connect(_ui->restartButton, SIGNAL(clicked()), qApp, SLOT(quit()), Qt::UniqueConnection);
_ui->updateStateLabel->setText(updater->statusString());
_ui->restartButton->setVisible(updater->downloadState() == OCUpdater::DownloadComplete);
} else {

View file

@ -57,7 +57,6 @@ static const char useDownloadLimitC[] = "BWLimit/useDownloadLimit";
static const char uploadLimitC[] = "BWLimit/uploadLimit";
static const char downloadLimitC[] = "BWLimit/downloadLimit";
static const char seenVersionC[] = "Updater/seenVersion";
static const char maxLogLinesC[] = "Logging/maxLogLines";
QString MirallConfigFile::_confDir = QString::null;
@ -108,19 +107,6 @@ void MirallConfigFile::setOptionalDesktopNotifications(bool show)
settings.sync();
}
QString MirallConfigFile::seenVersion() const
{
QSettings settings(configFile(), QSettings::IniFormat);
return settings.value(QLatin1String(seenVersionC)).toString();
}
void MirallConfigFile::setSeenVersion(const QString &version)
{
QSettings settings(configFile(), QSettings::IniFormat);
settings.setValue(QLatin1String(seenVersionC), version);
settings.sync();
}
void MirallConfigFile::saveGeometry(QWidget *w)
{
Q_ASSERT(!w->objectName().isNull());

View file

@ -106,9 +106,6 @@ public:
QString lastVersion() const;
void setLastVersion(const QString &version);
QString seenVersion() const;
void setSeenVersion(const QString &version);
void saveGeometryHeader(QHeaderView *header);
void restoreGeometryHeader(QHeaderView *header);
protected:

View file

@ -32,7 +32,9 @@
namespace Mirall {
static const char updateAvailableC[] = "Updater/updateAvailable";
static const char lastVersionC[] = "Updater/lastVersion";
static const char updateTargetVersionC[] = "Updater/updateTargetVersion";
static const char seenVersionC[] = "Updater/seenVersion";
static const char autoUpdateFailedVersionC[] = "Updater/autoUpdateFailedVersion";
static const char ranUpdateC[] = "Updater/ranUpdate";
OCUpdater::OCUpdater(const QUrl &url, QObject *parent) :
@ -107,9 +109,9 @@ void OCUpdater::slotStartInstaller()
QSettings settings(cfg.configFile(), QSettings::IniFormat);
QString updateFile = settings.value(updateAvailableC).toString();
settings.setValue(ranUpdateC, true);
settings.sync();
qDebug() << "Running updater" << updateFile;
QProcess::startDetached(updateFile, QStringList() << "/S" << "/launch");
qApp->quit();
}
void OCUpdater::checkForUpdate()
@ -145,12 +147,6 @@ void OCUpdater::slotOpenUpdateUrl()
QDesktopServices::openUrl(_updateInfo.web());
}
void OCUpdater::slotSetVersionSeen()
{
MirallConfigFile cfg;
cfg.setSeenVersion(_updateInfo.version());
}
QString OCUpdater::getSystemInfo()
{
#ifdef Q_OS_LINUX
@ -171,8 +167,8 @@ bool OCUpdater::updateSucceeded() const
{
MirallConfigFile cfg;
QSettings settings(cfg.configFile(), QSettings::IniFormat);
qint64 oldVersionInt = Helper::stringVersionToInt(settings.value(lastVersionC).toString().toLatin1());
return Helper::currentVersionToInt() > oldVersionInt;
qint64 targetVersionInt = Helper::stringVersionToInt(settings.value(updateTargetVersionC).toString());
return Helper::currentVersionToInt() >= targetVersionInt;
}
QString OCUpdater::clientVersion() const
@ -236,27 +232,25 @@ void NSISUpdater::slotDownloadFinished()
qDebug() << "Downloaded" << url.toString() << "to" << _targetFile;
MirallConfigFile cfg;
QSettings settings(cfg.configFile(), QSettings::IniFormat);
settings.setValue(lastVersionC, clientVersion());
settings.setValue(updateTargetVersionC, updateInfo().version());
settings.setValue(updateAvailableC, _targetFile);
}
void NSISUpdater::showFallbackMessage()
{
_showFallbackMessage = true;
}
void NSISUpdater::versionInfoArrived(const UpdateInfo &info)
{
MirallConfigFile cfg;
QSettings settings(cfg.configFile(), QSettings::IniFormat);
qint64 infoVersion = Helper::stringVersionToInt(info.version());
qint64 seenVersion = Helper::stringVersionToInt(cfg.seenVersion());
qint64 seenVersion = Helper::stringVersionToInt(settings.value(seenVersionC).toString());
if(info.version().isEmpty() || infoVersion <= seenVersion ) {
qDebug() << "Client is on latest version!";
setDownloadState(UpToDate);
} else {
QString url = info.downloadUrl();
if (url.isEmpty() || _showFallbackMessage) {
qint64 autoUpdateFailedVersion =
Helper::stringVersionToInt(settings.value(autoUpdateFailedVersionC).toString());
if (url.isEmpty() || _showFallbackMessage || infoVersion == autoUpdateFailedVersion) {
showDialog(info);
}
if (!url.isEmpty()) {
@ -318,7 +312,7 @@ void NSISUpdater::showDialog(const UpdateInfo &info)
connect(reject, SIGNAL(clicked()), msgBox, SLOT(reject()));
connect(getupdate, SIGNAL(clicked()), msgBox, SLOT(accept()));
connect(skip, SIGNAL(clicked()), SLOT(slotSetVersionSeen()));
connect(skip, SIGNAL(clicked()), SLOT(slotSetSeenVersion()));
connect(getupdate, SIGNAL(clicked()), SLOT(slotOpenUpdateUrl()));
layout->addWidget(bb);
@ -326,7 +320,7 @@ void NSISUpdater::showDialog(const UpdateInfo &info)
msgBox->open();
}
NSISUpdater::UpdateState NSISUpdater::updateState() const
NSISUpdater::UpdateState NSISUpdater::updateState()
{
MirallConfigFile cfg;
QSettings settings(cfg.configFile(), QSettings::IniFormat);
@ -336,14 +330,27 @@ NSISUpdater::UpdateState NSISUpdater::updateState() const
// we have an update, did we succeed running it?
bool ranUpdate = settings.value(ranUpdateC, false).toBool();
if (ranUpdate) {
// regardless if things went well or not
QFile::remove(updateFile);
settings.remove(ranUpdateC);
if (updateSucceeded()) {
settings.remove(ranUpdateC);
settings.remove(updateTargetVersionC);
settings.remove(autoUpdateFailedVersionC);
slotSetSeenVersion();
return NoUpdate;
} else {
QString targetVersion = settings.value(updateTargetVersionC).toString();
settings.setValue(autoUpdateFailedVersionC, targetVersion);
settings.remove(updateTargetVersionC);
return UpdateFailed;
}
} else {
return UpdateAvailable;
if (settings.contains(autoUpdateFailedVersionC)) {
return NoUpdate;
} else {
return UpdateAvailable;
}
}
} else {
return NoUpdate;
@ -356,7 +363,7 @@ bool NSISUpdater::handleStartup()
case NSISUpdater::UpdateAvailable:
return performUpdate();
case NSISUpdater::UpdateFailed:
showFallbackMessage();
_showFallbackMessage = true;
return false;
case NSISUpdater::NoUpdate:
default:
@ -364,6 +371,13 @@ bool NSISUpdater::handleStartup()
}
}
void NSISUpdater::slotSetSeenVersion()
{
MirallConfigFile cfg;
QSettings settings(cfg.configFile(), QSettings::IniFormat);
settings.setValue(seenVersionC, updateInfo().version());
}
////////////////////////////////////////////////////////////////////////
PassiveUpdateNotifier::PassiveUpdateNotifier(const QUrl &url, QObject *parent)
@ -375,7 +389,12 @@ PassiveUpdateNotifier::PassiveUpdateNotifier(const QUrl &url, QObject *parent)
void PassiveUpdateNotifier::versionInfoArrived(const UpdateInfo &info)
{
MirallConfigFile cfg;
if( info.version().isEmpty() || info.version() == cfg.seenVersion() ) {
QSettings settings(cfg.configFile(), QSettings::IniFormat);
QString seenVersion = settings.value(seenVersionC).toString();
if( info.version().isEmpty() ||
Helper::stringVersionToInt(info.version())
>= Helper::stringVersionToInt(seenVersion))
{
qDebug() << "Client is on latest version!";
setDownloadState(UpToDate);
} else {

View file

@ -55,7 +55,6 @@ public slots:
private slots:
void slotOpenUpdateUrl();
void slotSetVersionSeen();
void slotVersionInfoArrived();
void slotTimedOut();
@ -65,7 +64,7 @@ protected:
QString clientVersion() const;
QString getSystemInfo();
QNetworkAccessManager* qnam() const { return _accessManager; }
UpdateInfo updateInfo() const { return _updateInfo; }
private:
QUrl _updateUrl;
int _state;
@ -82,12 +81,12 @@ public:
explicit NSISUpdater(const QUrl &url, QObject *parent = 0);
bool handleStartup();
private slots:
void slotSetSeenVersion();
void slotDownloadFinished();
void slotWriteFile();
private:
NSISUpdater::UpdateState updateState() const;
NSISUpdater::UpdateState updateState();
void showDialog(const UpdateInfo &info);
void showFallbackMessage();
void versionInfoArrived(const UpdateInfo &info);
QScopedPointer<QTemporaryFile> _file;
QString _targetFile;

View file

@ -58,6 +58,8 @@ qint64 Updater::Helper::currentVersionToInt()
qint64 Updater::Helper::stringVersionToInt(const QString& version)
{
if (version.isEmpty())
return 0;
QByteArray baVersion = version.toLatin1();
int major = 0, minor = 0, patch = 0, build = 0;
sscanf(baVersion, "%d.%d.%d.%d", &major, &minor, &patch, &build);