Updater works...

This commit is contained in:
Martin Rotter 2014-04-12 17:52:28 +02:00
parent 050bb4b601
commit 615f27f94c
3 changed files with 343 additions and 55 deletions

View File

@ -30,14 +30,16 @@
#include <QDesktopServices> #include <QDesktopServices>
#include <QProcess> #include <QProcess>
#if defined(Q_OS_WIN)
#include "qt_windows.h"
#endif
FormUpdate::FormUpdate(QWidget *parent) FormUpdate::FormUpdate(QWidget *parent)
: QDialog(parent), m_ui(new Ui::FormUpdate) { : QDialog(parent), m_ui(new Ui::FormUpdate) {
m_ui->setupUi(this); m_ui->setupUi(this);
#if defined(Q_OS_WIN) || defined(Q_OS_OS2)
m_downloader = NULL;
m_readyToInstall = false;
#endif
// Set flags and attributes. // Set flags and attributes.
setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog); setWindowFlags(Qt::MSWindowsFixedSizeDialogHint | Qt::Dialog);
setWindowIcon(IconFactory::instance()->fromTheme("application-about")); setWindowIcon(IconFactory::instance()->fromTheme("application-about"));
@ -84,6 +86,8 @@ void FormUpdate::checkForUpdates() {
m_ui->m_txtChanges->setText(update.first.m_changes); m_ui->m_txtChanges->setText(update.first.m_changes);
if (update.first.m_availableVersion >= APP_VERSION) { if (update.first.m_availableVersion >= APP_VERSION) {
bool update_for_this_system = isUpdateForThisSystem();
m_ui->m_lblStatus->setStatus(WidgetWithStatus::Ok, m_ui->m_lblStatus->setStatus(WidgetWithStatus::Ok,
tr("New release available."), tr("New release available."),
tr("This is new version which can be\ndownloaded and installed.")); tr("This is new version which can be\ndownloaded and installed."));
@ -92,6 +96,10 @@ void FormUpdate::checkForUpdates() {
tr("Download installation file for your OS.") : tr("Download installation file for your OS.") :
tr("Installation file is not available directly.\n" tr("Installation file is not available directly.\n"
"Go to application website to obtain it manually.")); "Go to application website to obtain it manually."));
if (update_for_this_system) {
m_btnUpdate->setText(tr("Download update"));
}
} }
else { else {
m_ui->m_lblStatus->setStatus(WidgetWithStatus::Warning, m_ui->m_lblStatus->setStatus(WidgetWithStatus::Warning,
@ -103,6 +111,74 @@ void FormUpdate::checkForUpdates() {
} }
} }
#if defined(Q_OS_WIN) || defined(Q_OS_OS2)
void FormUpdate::updateProgress(qint64 bytes_received, qint64 bytes_total) {
qApp->processEvents();
m_ui->m_lblStatus->setStatus(WidgetWithStatus::Information,
tr("Downloaded %1% (update size is %2 kB).").arg(QString::number((bytes_received * 100.0) / bytes_total,
'f',
2),
QString::number(bytes_total / 1000,
'f',
2)),
tr("Downloading update..."));
}
void FormUpdate::saveUpdateFile(const QByteArray &file_contents) {
QString url_file = m_updateInfo.m_urls.value(OS_ID).m_fileUrl;;
#if QT_VERSION >= 0x050000
QString temp_directory = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
#else
QString temp_directory = QDesktopServices::storageLocation(QDesktopServices::TempLocation);
#endif
if (!temp_directory.isEmpty()) {
QString output_file_name = url_file.mid(url_file.lastIndexOf('/') + 1);
QFile output_file(temp_directory + QDir::separator() + output_file_name);
if (output_file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
qDebug("Storing update file to temporary location '%s'.",
qPrintable(output_file_name));
output_file.write(file_contents);
output_file.flush();
output_file.close();
qDebug("Update file contents was successfuly saved.");
m_updateFilePath = output_file.fileName();
m_readyToInstall = true;
}
else {
qDebug("Cannot save downloaded update file because target temporary file '%s' cannot be "
"opened for writing.", output_file_name);
}
}
else {
qDebug("Cannot save downloaded update file because no TEMP folder is available.");
}
}
void FormUpdate::updateCompleted(QNetworkReply::NetworkError status, QByteArray contents) {
qDebug("Download of application update file was completed with code '%s'.",
status);
switch (status) {
case QNetworkReply::NoError:
saveUpdateFile(contents);
m_btnUpdate->setText(tr("Install update"));
m_btnUpdate->setEnabled(true);
break;
default:
m_btnUpdate->setText(tr("Error occured"));
break;
}
}
#endif
void FormUpdate::startUpdate() { void FormUpdate::startUpdate() {
QString url_file; QString url_file;
bool update_for_this_system = isUpdateForThisSystem(); bool update_for_this_system = isUpdateForThisSystem();
@ -115,35 +191,71 @@ void FormUpdate::startUpdate() {
} }
#if defined(Q_OS_WIN) || defined(Q_OS_OS2) #if defined(Q_OS_WIN) || defined(Q_OS_OS2)
Downloader *downloader = new Downloader(this); if (m_readyToInstall) {
close();
connect(downloader, SIGNAL(completed(QNetworkReply::NetworkError,QByteArray)), qDebug("Preparing to launch external updater '%s'.", APP_UPDATER_EXECUTABLE);
this, SLOT(finish(QNetworkReply::NetworkError,QByteArray)));
// TODO: tady jen zavolat updater a ten by si to mohl stahnout sam. if (!QProcess::startDetached(APP_UPDATER_EXECUTABLE,
downloader->downloadFile(url_file); QStringList() <<
#else APP_VERSION <<
if (!WebFactory::instance()->openUrlInExternalBrowser(url_file)) { m_updateInfo.m_availableVersion <<
if (SystemTrayIcon::isSystemTrayActivated()) { QDir::toNativeSeparators(qApp->applicationFilePath()) <<
SystemTrayIcon::instance()->showMessage(tr("Cannot update application"), QDir::toNativeSeparators(m_updateFilePath))) {
tr("Cannot navigate to installation file. Check new installation downloads " qDebug("External updater was not launched due to error.");
"manually on project website."),
QSystemTrayIcon::Warning); if (SystemTrayIcon::isSystemTrayActivated()) {
SystemTrayIcon::instance()->showMessage(tr("Cannot update application"),
tr("Cannot launch external updater. Update application manually."),
QSystemTrayIcon::Warning);
}
else {
MessageBox::show(this,
QMessageBox::Warning,
tr("Cannot update application"),
tr("Cannot launch external updater. Update application manually."));
}
} }
else {
MessageBox::show(this, return;
QMessageBox::Warning, }
tr("Cannot update application"),
tr("Cannot navigate to installation file. Check new installation downloads " if (update_for_this_system) {
"manually on project website.")); if (m_downloader == NULL) {
// Initialie downloader.
m_downloader = new Downloader(this);
connect(m_downloader, SIGNAL(progress(qint64,qint64)),
this, SLOT(updateProgress(qint64,qint64)));
connect(m_downloader, SIGNAL(completed(QNetworkReply::NetworkError,QByteArray)),
this, SLOT(updateCompleted(QNetworkReply::NetworkError,QByteArray)));
}
m_btnUpdate->setText(tr("Downloading update..."));
m_btnUpdate->setEnabled(false);
m_downloader->downloadFile(url_file);
} else {
if (!WebFactory::instance()->openUrlInExternalBrowser(url_file)) {
if (SystemTrayIcon::isSystemTrayActivated()) {
SystemTrayIcon::instance()->showMessage(tr("Cannot update application"),
tr("Cannot navigate to installation file. Check new installation downloads "
"manually on project website."),
QSystemTrayIcon::Warning);
}
else {
MessageBox::show(this,
QMessageBox::Warning,
tr("Cannot update application"),
tr("Cannot navigate to installation file. Check new installation downloads "
"manually on project website."));
}
} }
} }
#endif /*
} * // TODO: http://pastebin.com/Lvb1bsJP
// chyba od elberta
#if defined(Q_OS_WIN) || defined(Q_OS_OS2)
void FormUpdate::finish(QNetworkReply::NetworkError err, QByteArray arr)
{
// TODO: presunou do updatera. // TODO: presunou do updatera.
QString url_file = m_updateInfo.m_urls.value(OS_ID).m_fileUrl;; QString url_file = m_updateInfo.m_urls.value(OS_ID).m_fileUrl;;
@ -163,27 +275,23 @@ void FormUpdate::finish(QNetworkReply::NetworkError err, QByteArray arr)
output_file.close(); output_file.close();
close(); close();
}
QProcess::startDetached(APP_UPDATER_EXECUTABLE, }*/
QStringList() << temp_directory <<qApp->applicationFilePath() << output_file.fileName()); #else
if (!WebFactory::instance()->openUrlInExternalBrowser(url_file)) {
//ShellExecute(0, if (SystemTrayIcon::isSystemTrayActivated()) {
// 0, SystemTrayIcon::instance()->showMessage(tr("Cannot update application"),
// (wchar_t *) QString(APP_UPDATER_EXECUTABLE).utf16(), tr("Cannot navigate to installation file. Check new installation downloads "
// (wchar_t *) QString("\"%1\" \"%2\" \"%3\"").arg(temp_directory, "manually on project website."),
// qApp->applicationFilePath(), QSystemTrayIcon::Warning);
// output_file.fileName()).utf16(),
// 0,
// SW_SHOWNORMAL);
} }
else { else {
// TODO: chyba - nelze zapisovat do souboru MessageBox::show(this,
QMessageBox::Warning,
tr("Cannot update application"),
tr("Cannot navigate to installation file. Check new installation downloads "
"manually on project website."));
} }
} }
else {
// TODO: chyba - nelze ulozit soubor.
}
}
#endif #endif
}

View File

@ -21,6 +21,10 @@
#include <QDialog> #include <QDialog>
#include <QPushButton> #include <QPushButton>
#if defined(Q_OS_WIN) || defined(Q_OS_OS2)
#include <QNetworkReply>
#endif
#include "ui_formupdate.h" #include "ui_formupdate.h"
#include "miscellaneous/systemfactory.h" #include "miscellaneous/systemfactory.h"
@ -30,6 +34,10 @@ namespace Ui {
class FormUpdate; class FormUpdate;
} }
#if defined(Q_OS_WIN) || defined(Q_OS_OS2)
class Downloader;
#endif
class FormUpdate : public QDialog { class FormUpdate : public QDialog {
Q_OBJECT Q_OBJECT
@ -48,10 +56,16 @@ class FormUpdate : public QDialog {
void startUpdate(); void startUpdate();
#if defined(Q_OS_WIN) || defined(Q_OS_OS2) #if defined(Q_OS_WIN) || defined(Q_OS_OS2)
void finish(QNetworkReply::NetworkError err, QByteArray arr); void updateProgress(qint64 bytes_received, qint64 bytes_total);
#endif void updateCompleted(QNetworkReply::NetworkError status, QByteArray contents);
void saveUpdateFile(const QByteArray &file_contents);
private: private:
Downloader *m_downloader;
bool m_readyToInstall;
QString m_updateFilePath;
#endif
Ui::FormUpdate *m_ui; Ui::FormUpdate *m_ui;
UpdateInfo m_updateInfo; UpdateInfo m_updateInfo;
QPushButton *m_btnUpdate; QPushButton *m_btnUpdate;

View File

@ -34,7 +34,8 @@ bool removeDir(const QString & dirName) {
QDir dir(dirName); QDir dir(dirName);
if (dir.exists(dirName)) { if (dir.exists(dirName)) {
foreach (QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst)) { foreach (QFileInfo info,
dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst)) {
if (info.isDir()) { if (info.isDir()) {
result = removeDir(info.absoluteFilePath()); result = removeDir(info.absoluteFilePath());
} }
@ -55,6 +56,7 @@ bool removeDir(const QString & dirName) {
bool copyPath(QString src, QString dst) { bool copyPath(QString src, QString dst) {
QDir dir(src); QDir dir(src);
if (! dir.exists()) { if (! dir.exists()) {
return false; return false;
} }
@ -71,25 +73,34 @@ bool copyPath(QString src, QString dst) {
if (!QFile::exists(destination_file) || QFile::remove(destination_file)) { if (!QFile::exists(destination_file) || QFile::remove(destination_file)) {
if (QFile::copy(src + QDir::separator() + f, destination_file)) { if (QFile::copy(src + QDir::separator() + f, destination_file)) {
qDebug("Copied %s", qPrintable(f)); qDebug("Copied file '%s'.", qPrintable(f));
} }
else { else {
qDebug("Failed to copy file '%s'", qPrintable(original_file)); qDebug("Failed to copy file '%s'.", qPrintable(original_file));
} }
} }
else { else {
qDebug("Failed to remove file '%s'", qPrintable(original_file)); qDebug("Failed to remove file '%s'.", qPrintable(original_file));
} }
} }
return true; return true;
} }
// Main entry point to "rssguard_updater.exe".
// It expects 4 ARGUMENTS:
// 0) - the actual path of this process,
// 1) - string with current version,
// 2) - string with future version,
// 3) - path to RSS Guard ("rssguard.exe") file,
// 4) - path to update file (stored in TEMP folder).
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
// Instantiate base application object. // Instantiate base application object.
QtSingleCoreApplication application(APP_LOW_NAME, argc, argv); QtSingleCoreApplication application(APP_LOW_NAME, argc, argv);
if (argc != 4) { qDebug("\n===== RSS Guard updater ====\n");
if (argc != 5) {
qDebug("Insufficient arguments passed. Update process cannot proceed."); qDebug("Insufficient arguments passed. Update process cannot proceed.");
qDebug("Press any key to exit updater..."); qDebug("Press any key to exit updater...");
@ -98,6 +109,162 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
QString this_process_path = QDir::toNativeSeparators(application.applicationFilePath());
QString current_version(argv[1]);
QString next_version(argv[2]);
QString rssguard_executable_path(argv[3]);
QString rssguard_path = QDir::toNativeSeparators(QFileInfo(rssguard_executable_path).absolutePath());
QString update_file_path(argv[4]);
QString temp_path = QDir::toNativeSeparators(QFileInfo(update_file_path).absolutePath());
QString output_temp_path = temp_path + QDir::separator() + APP_LOW_NAME;
qDebug("Starting updater.");
qDebug("Version changes from %s to %s.",
qPrintable(current_version),
qPrintable(next_version));
qDebug("\n===== Files & versions ====\n");
qDebug("This process:\n\t %s", qPrintable(this_process_path));
qDebug("Application executable:\n\t %s", qPrintable(rssguard_executable_path));
qDebug("TEMP path:\n\t %s", qPrintable(temp_path));
qDebug("\n===== Update file metadata ====\n");
bool update_file_exists = QFile::exists(update_file_path);
qDebug("Update file exists:\n\t %s", update_file_exists ? "yes" : "no");
qDebug("Update file path:\n\t %s", qPrintable(update_file_path));
qDebug("Update file size:\n\t %d bytes", QFileInfo(update_file_path).size());
if (!update_file_exists) {
qDebug("\nUpdate file does NOT exist. Updater cannot proceed.");
qDebug("Press any key to exit updater...");
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
return EXIT_FAILURE;
}
// Check if main RSS Guard instance is running.
if (application.sendMessage(APP_QUIT_INSTANCE)) {
qDebug("RSS Guard application is running. Quitting it.");
}
qDebug("\n===== Cleanup ====\n");
// Remove old folders.
if (QDir(output_temp_path).exists()) {
if (!removeDir(output_temp_path)) {
qDebug("Cleanup of old temporary files failed.");
qDebug("Press any key to exit updater...");
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
return EXIT_FAILURE;
}
}
qDebug("Old files removed.");
qDebug("Update files are ready. Press any key to proceed...");
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
QString extractor(APP_7ZA_EXECUTABLE);
QStringList extractor_arguments;
extractor_arguments << "x" << update_file_path << "-r" <<
"-y" << QString("-o%1").arg(output_temp_path);
qDebug("\n===== Decompression =====\n");
switch (QProcess::execute(extractor, extractor_arguments)) {
case -1:
qDebug("\nDecompressor crashed. Upgrading process failed.");
qDebug("Press any key to exit updater...");
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
return EXIT_FAILURE;
case -2:
qDebug("\nDecompressor was not started successfully. Upgrading process failed.");
qDebug("Press any key to exit updater...");
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
return EXIT_FAILURE;
case 0:
qDebug("\nDecompression is done. Proceeding to copying files to application directory.");
break;
default:
qDebug("\nUnspecified error occured.");
qDebug("Press any key to exit updater...");
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
return EXIT_FAILURE;
}
qDebug("\n===== Copying =====\n");
// Find "rssguard" subfolder path in
QFileInfoList rssguard_temp_root = QDir(output_temp_path).entryInfoList(QDir::Dirs |
QDir::NoDotAndDotDot |
QDir::NoSymLinks);
if (rssguard_temp_root.size() != 1) {
qDebug("Could not find root of downloaded application data.");
qDebug("Press any key to exit updater...");
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
return EXIT_FAILURE;
}
QString rssguard_single_temp_root = rssguard_temp_root.at(0).absoluteFilePath();
if (!copyPath(rssguard_single_temp_root, rssguard_path)) {
qDebug("Critical error appeared during copying of application files.");
qDebug("Press any key to exit updater...");
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
return EXIT_FAILURE;
}
qDebug("\n===== Cleanup =====\n");
removeDir(output_temp_path);
QFile::remove(update_file_path);
qDebug("Temporary files removed.");
qDebug("Press any key to exit updater and start RSS Guard.");
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
if (!QProcess::startDetached(rssguard_executable_path)) {
qDebug("RSS Guard was not started successfully. Start it manually.");
qDebug("Press any key to exit updater...");
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
/*
QString temp_directory = QDir::toNativeSeparators(argv[1]); QString temp_directory = QDir::toNativeSeparators(argv[1]);
QString rssguard_executable = QDir::toNativeSeparators(argv[2]); QString rssguard_executable = QDir::toNativeSeparators(argv[2]);
QString rssguard_path = QDir::toNativeSeparators(QFileInfo(rssguard_executable).absolutePath()); QString rssguard_path = QDir::toNativeSeparators(QFileInfo(rssguard_executable).absolutePath());
@ -209,7 +376,6 @@ int main(int argc, char *argv[]) {
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
QProcess::startDetached(rssguard_executable); QProcess::startDetached(rssguard_executable);
*/
return EXIT_SUCCESS;
} }