diff options
author | Petr Mrázek <peterix@gmail.com> | 2015-06-08 02:43:16 +0200 |
---|---|---|
committer | Petr Mrázek <peterix@gmail.com> | 2015-06-09 00:03:42 +0200 |
commit | 82e05661d207621f917d79ebd513abc57a36c084 (patch) | |
tree | b13eb12af54ff1a6214d9b0c7b34ce6a9e5aa975 /application | |
parent | 166813cb918ebd029325e12377989bfdc2021074 (diff) | |
download | MultiMC-82e05661d207621f917d79ebd513abc57a36c084.tar MultiMC-82e05661d207621f917d79ebd513abc57a36c084.tar.gz MultiMC-82e05661d207621f917d79ebd513abc57a36c084.tar.lz MultiMC-82e05661d207621f917d79ebd513abc57a36c084.tar.xz MultiMC-82e05661d207621f917d79ebd513abc57a36c084.zip |
GH-1060 implement very basic updater (only linux and maybe osx right now)
Diffstat (limited to 'application')
-rw-r--r-- | application/MainWindow.cpp | 2 | ||||
-rw-r--r-- | application/MultiMC.cpp | 162 | ||||
-rw-r--r-- | application/MultiMC.h | 3 |
3 files changed, 156 insertions, 11 deletions
diff --git a/application/MainWindow.cpp b/application/MainWindow.cpp index 933c4dbc..8c827806 100644 --- a/application/MainWindow.cpp +++ b/application/MainWindow.cpp @@ -992,7 +992,7 @@ void MainWindow::downloadUpdates(GoUpdate::Status status) // If the task succeeds, install the updates. if (updateDlg.exec(&updateTask)) { - MMC->installUpdates(updateTask.updateFilesDir()); + MMC->installUpdates(updateTask.updateFilesDir(), updateTask.operations()); } else { diff --git a/application/MultiMC.cpp b/application/MultiMC.cpp index 67b50b40..a21455f0 100644 --- a/application/MultiMC.cpp +++ b/application/MultiMC.cpp @@ -583,7 +583,69 @@ std::shared_ptr<JavaVersionList> MultiMC::javalist() return m_javalist; } -void MultiMC::installUpdates(const QString updateFilesDir) +// from <sys/stat.h> +#ifndef S_IRUSR +#define __S_IREAD 0400 /* Read by owner. */ +#define __S_IWRITE 0200 /* Write by owner. */ +#define __S_IEXEC 0100 /* Execute by owner. */ +#define S_IRUSR __S_IREAD /* Read by owner. */ +#define S_IWUSR __S_IWRITE /* Write by owner. */ +#define S_IXUSR __S_IEXEC /* Execute by owner. */ + +#define S_IRGRP (S_IRUSR >> 3) /* Read by group. */ +#define S_IWGRP (S_IWUSR >> 3) /* Write by group. */ +#define S_IXGRP (S_IXUSR >> 3) /* Execute by group. */ + +#define S_IROTH (S_IRGRP >> 3) /* Read by others. */ +#define S_IWOTH (S_IWGRP >> 3) /* Write by others. */ +#define S_IXOTH (S_IXGRP >> 3) /* Execute by others. */ +#endif +static QFile::Permissions unixModeToPermissions(const int mode) +{ + QFile::Permissions perms; + + if (mode & S_IRUSR) + { + perms |= QFile::ReadUser; + } + if (mode & S_IWUSR) + { + perms |= QFile::WriteUser; + } + if (mode & S_IXUSR) + { + perms |= QFile::ExeUser; + } + + if (mode & S_IRGRP) + { + perms |= QFile::ReadGroup; + } + if (mode & S_IWGRP) + { + perms |= QFile::WriteGroup; + } + if (mode & S_IXGRP) + { + perms |= QFile::ExeGroup; + } + + if (mode & S_IROTH) + { + perms |= QFile::ReadOther; + } + if (mode & S_IWOTH) + { + perms |= QFile::WriteOther; + } + if (mode & S_IXOTH) + { + perms |= QFile::ExeOther; + } + return perms; +} + +void MultiMC::installUpdates(const QString updateFilesDir, GoUpdate::OperationList operations) { qDebug() << "Installing updates."; #ifdef WINDOWS @@ -596,14 +658,96 @@ void MultiMC::installUpdates(const QString updateFilesDir) #error Unsupported operating system. #endif - QStringList args; - args << "--install-dir" << root(); - args << "--package-dir" << updateFilesDir; - args << "--script" << PathCombine(updateFilesDir, "file_list.xml"); - args << "--wait" << QString::number(applicationPid()); - args << "--finish-cmd" << finishCmd; - args << "--finish-dir" << dataPath; - qDebug() << "Running updater with args" << args.join(" "); + QString backupPath = PathCombine(root(), "update-backup"); + QString trashPath = PathCombine(root(), "update-trash"); + if(!ensureFolderPathExists(backupPath)) + { + qWarning() << "couldn't create folder" << backupPath; + return; + } + if(!ensureFolderPathExists(trashPath)) + { + qWarning() << "couldn't create folder" << trashPath; + return; + } + struct BackupEntry + { + QString orig; + QString backup; + }; + QList <BackupEntry> backups; + QList <BackupEntry> trashcan; + for(auto op: operations) + { + switch(op.type) + { + case GoUpdate::Operation::OP_COPY: + { + QFileInfo replaced (PathCombine(root(), op.dest)); + if(replaced.exists()) + { + QString backupFilePath = PathCombine(backupPath, replaced.completeBaseName()); + QFile::rename(replaced.absoluteFilePath(), backupFilePath); + BackupEntry be; + be.orig = replaced.absoluteFilePath(); + be.backup = backupFilePath; + backups.append(be); + } + QFile::copy(op.file, replaced.absoluteFilePath()); + QFile::setPermissions(replaced.absoluteFilePath(), unixModeToPermissions(op.mode)); + } + break; + case GoUpdate::Operation::OP_DELETE: + { + QString trashFilePath = PathCombine(backupPath, op.file); + QString origFilePath = PathCombine(root(), op.file); + if(QFile::exists(origFilePath)) + { + QFile::rename(origFilePath, trashFilePath); + BackupEntry be; + be.orig = origFilePath; + be.backup = trashFilePath; + trashcan.append(be); + } + } + break; + } + } + + // try to start the new binary + qint64 pid = -1; + auto args = qApp->arguments(); + args.removeFirst(); + QProcess::startDetached(finishCmd, args, QDir::currentPath(), &pid); + // failed to start... ? + if(pid == -1) + { + goto FAILED; + } + // now clean up the backed up stuff. + for(auto backup:backups) + { + QFile::remove(backup.backup); + } + for(auto backup:trashcan) + { + QFile::remove(backup.backup); + } + qApp->quit(); + return; + +FAILED: + // if the above failed, roll back changes + for(auto backup:backups) + { + QFile::remove(backup.orig); + QFile::rename(backup.backup, backup.orig); + } + for(auto backup:trashcan) + { + QFile::rename(backup.backup, backup.orig); + } + // and do nothing } void MultiMC::setIconTheme(const QString& name) diff --git a/application/MultiMC.h b/application/MultiMC.h index f815b8e4..9edf0596 100644 --- a/application/MultiMC.h +++ b/application/MultiMC.h @@ -6,6 +6,7 @@ #include <QFlag> #include <QIcon> #include <QDateTime> +#include <updater/GoUpdate.h> class QFile; class MinecraftVersionList; @@ -105,7 +106,7 @@ public: } // APPLICATION ONLY - void installUpdates(const QString updateFilesDir); + void installUpdates(const QString updateFilesDir, GoUpdate::OperationList operations); /*! * Opens a json file using either a system default editor, or, if note empty, the editor |