From b49fa9d2a99b1230dd9b3146d5a1bb65848b4aae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 5 Jan 2014 00:06:55 +0100 Subject: [PATCH] Mess with the updater again. --- CMakeLists.txt | 2 + MultiMC.cpp | 64 +++++++----------- MultiMC.h | 1 + config.h.in | 5 ++ logic/updater/DownloadUpdateTask.cpp | 6 +- logic/updater/DownloadUpdateTask.h | 4 +- logic/updater/UpdateChecker.cpp | 1 - mmc_updater/src/UpdateInstaller.cpp | 98 +++++++++++++++++++--------- mmc_updater/src/UpdateInstaller.h | 16 ++--- mmc_updater/src/UpdaterOptions.cpp | 77 +--------------------- mmc_updater/src/UpdaterOptions.h | 5 +- mmc_updater/src/main.cpp | 1 + 12 files changed, 119 insertions(+), 161 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ac13fa0..068282d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -503,6 +503,8 @@ IF(WIN32) ) ENDIF(WIN32) +OPTION(MultiMC_UPDATER_DRY_RUN "Enable updater dry-run mode." OFF) + OPTION(MultiMC_CODE_COVERAGE "Compiles for code coverage" OFF) IF(MultiMC_CODE_COVERAGE) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 --coverage") diff --git a/MultiMC.cpp b/MultiMC.cpp index b105fd66..1b915542 100644 --- a/MultiMC.cpp +++ b/MultiMC.cpp @@ -35,17 +35,6 @@ #include "logger/QsLog.h" #include -#include "config.h" -#ifdef WINDOWS -#define UPDATER_BIN "updater.exe" -#elif LINUX -#define UPDATER_BIN "updater" -#elif OSX -#define UPDATER_BIN "updater" -#else -#error Unsupported operating system. -#endif - using namespace Util::Commandline; MultiMC::MultiMC(int &argc, char **argv, const QString &data_dir_override) @@ -136,6 +125,11 @@ MultiMC::MultiMC(int &argc, char **argv, const QString &data_dir_override) adjustedBy += "Command line " + dirParam; dataPath = dirParam; } + else + { + dataPath = applicationDirPath(); + adjustedBy += "Fallback to binary path " + dataPath; + } if(!ensureFolderPathExists(dataPath) || !QDir::setCurrent(dataPath)) { // BAD STUFF. WHAT DO? @@ -150,8 +144,7 @@ MultiMC::MultiMC(int &argc, char **argv, const QString &data_dir_override) QDir foo(PathCombine(binPath, "..")); rootPath = foo.absolutePath(); #elif defined(Q_OS_WIN32) - QDir foo(PathCombine(binPath, "..")); - rootPath = foo.absolutePath(); + rootPath = binPath; #elif defined(Q_OS_MAC) QDir foo(PathCombine(binPath, "../..")); rootPath = foo.absolutePath(); @@ -341,7 +334,7 @@ void MultiMC::initLogger() QsLogging::Logger &logger = QsLogging::Logger::instance(); logger.setLoggingLevel(QsLogging::TraceLevel); m_fileDestination = QsLogging::DestinationFactory::MakeFileDestination(logBase.arg(0)); - m_debugDestination = QsLogging::DestinationFactory::MakeDebugOutputDestination(); + m_debugDestination = QsLogging::DestinationFactory::MakeQDebugDestination(); logger.addDestination(m_fileDestination.get()); logger.addDestination(m_debugDestination.get()); // log all the things @@ -468,7 +461,7 @@ void MultiMC::initHttpMetaCache() m_metacache->addBase("libraries", QDir("libraries").absolutePath()); m_metacache->addBase("minecraftforge", QDir("mods/minecraftforge").absolutePath()); m_metacache->addBase("skins", QDir("accounts/skins").absolutePath()); - m_metacache->addBase("root", QDir(".").absolutePath()); + m_metacache->addBase("root", QDir(root()).absolutePath()); m_metacache->Load(); } @@ -520,36 +513,29 @@ std::shared_ptr MultiMC::javalist() void MultiMC::installUpdates(const QString &updateFilesDir, bool restartOnFinish) { QLOG_INFO() << "Installing updates."; -#if LINUX - // On Linux, the MultiMC executable file is actually in the bin folder inside the - // installation directory. - // This means that MultiMC's *actual* install path is the parent folder. - // We need to tell the updater to run with this directory as the install path, rather than - // the bin folder where the executable is. - // On other operating systems, we'll just use the path to the executable. - QString appDir = QFileInfo(MMC->applicationDirPath()).dir().path(); - - // On Linux, we also need to set the finish command to the launch script, rather than the - // binary. - QString finishCmd = PathCombine(appDir, "MultiMC"); -#else - QString appDir = MMC->applicationDirPath(); - QString finishCmd = MMC->applicationFilePath(); -#endif - - // Build the command we'll use to run the updater. - // Note, the above comment about the app dir path on Linux is irrelevant here because the - // updater binary is always in the - // same folder as the main binary. - QString updaterBinary = PathCombine(MMC->applicationDirPath(), UPDATER_BIN); + #ifdef WINDOWS + QString finishCmd = MMC->applicationFilePath(); + QString updaterBinary = PathCombine(bin(), "updater.exe"); + #elif LINUX + QString finishCmd = PathCombine(root(), "MultiMC"); + QString updaterBinary = PathCombine(bin(), "updater"); + #elif OSX + QString finishCmd = MMC->applicationFilePath(); + QString updaterBinary = PathCombine(bin(), "updater"); + #else + #error Unsupported operating system. + #endif + QStringList args; // ./updater --install-dir $INSTALL_DIR --package-dir $UPDATEFILES_DIR --script // $UPDATEFILES_DIR/file_list.xml --wait $PID --mode main - args << "--install-dir" << appDir; + args << "--install-dir" << root(); args << "--package-dir" << updateFilesDir; args << "--script" << PathCombine(updateFilesDir, "file_list.xml"); args << "--wait" << QString::number(MMC->applicationPid()); - +#ifdef MultiMC_UPDATER_DRY_RUN + args << "--dry-run"; +#endif if (restartOnFinish) args << "--finish-cmd" << finishCmd; diff --git a/MultiMC.h b/MultiMC.h index 3a25aa5e..8e711f10 100644 --- a/MultiMC.h +++ b/MultiMC.h @@ -1,5 +1,6 @@ #pragma once +#include "config.h" #include #include "MultiMCVersion.h" #include diff --git a/config.h.in b/config.h.in index 9681b825..6eb3fcef 100644 --- a/config.h.in +++ b/config.h.in @@ -1,3 +1,5 @@ +#pragma once + // Minor and major version, used to communicate changes to users. #define VERSION_MAJOR @MultiMC_VERSION_MAJOR@ #define VERSION_MINOR @MultiMC_VERSION_MINOR@ @@ -16,6 +18,9 @@ // Used for matching notifications #define FULL_VERSION_STR "@MultiMC_VERSION_MAJOR@.@MultiMC_VERSION_MINOR@.@MultiMC_VERSION_BUILD@" +// enabled for updater dry run +#cmakedefine MultiMC_UPDATER_DRY_RUN + // The commit hash of this build #define GIT_COMMIT "@MultiMC_GIT_COMMIT@" diff --git a/logic/updater/DownloadUpdateTask.cpp b/logic/updater/DownloadUpdateTask.cpp index 029286dd..b82574f7 100644 --- a/logic/updater/DownloadUpdateTask.cpp +++ b/logic/updater/DownloadUpdateTask.cpp @@ -402,12 +402,17 @@ DownloadUpdateTask::processFileLists(NetJob *job, if (isUpdater) { +#ifdef MultiMC_UPDATER_DRY_RUN + QLOG_DEBUG() << "Skipping updater download and using local version."; +#else auto cache_entry = MMC->metacache()->resolveEntry("root", entry.path); QLOG_DEBUG() << "Updater will be in " << cache_entry->getFullPath(); // force check. cache_entry->stale = true; + auto download = CacheDownload::make(QUrl(source.url), cache_entry); job->addNetAction(download); +#endif } else { @@ -514,7 +519,6 @@ bool DownloadUpdateTask::fixPathForOSX(QString &path) { // remove the prefix and add a new, more appropriate one. path.remove(0, 12); - path = QString("../../") + path; return true; } else diff --git a/logic/updater/DownloadUpdateTask.h b/logic/updater/DownloadUpdateTask.h index b1d14846..4feab871 100644 --- a/logic/updater/DownloadUpdateTask.h +++ b/logic/updater/DownloadUpdateTask.h @@ -206,11 +206,9 @@ protected: * The updater runs in MultiMC.app/Contents/MacOs by default * The destination paths are such as this: MultiMC.app/blah/blah * - * Therefore we chop off the 'MultiMC.app' prefix and prepend ../.. + * Therefore we chop off the 'MultiMC.app' prefix * * Returns false if the path couldn't be fixed (is invalid) - * - * Has no effect on systems that aren't OSX */ static bool fixPathForOSX(QString &path); diff --git a/logic/updater/UpdateChecker.cpp b/logic/updater/UpdateChecker.cpp index d0795c0d..9af11cab 100644 --- a/logic/updater/UpdateChecker.cpp +++ b/logic/updater/UpdateChecker.cpp @@ -17,7 +17,6 @@ #include "MultiMC.h" -#include "config.h" #include "logger/QsLog.h" #include diff --git a/mmc_updater/src/UpdateInstaller.cpp b/mmc_updater/src/UpdateInstaller.cpp index ced6ff39..3459ab95 100644 --- a/mmc_updater/src/UpdateInstaller.cpp +++ b/mmc_updater/src/UpdateInstaller.cpp @@ -6,16 +6,6 @@ #include "ProcessUtils.h" #include "UpdateObserver.h" -UpdateInstaller::UpdateInstaller() -: m_mode(Setup) -, m_waitPid(0) -, m_script(0) -, m_observer(0) -, m_forceElevated(false) -, m_autoClose(false) -{ -} - void UpdateInstaller::setWaitPid(PLATFORM_PID pid) { m_waitPid = pid; @@ -69,6 +59,10 @@ std::list UpdateInstaller::updaterArgs() const { args.push_back("--auto-close"); } + if (m_dryRun) + { + args.push_back("--dry-run"); + } return args; } @@ -255,25 +249,32 @@ void UpdateInstaller::cleanup() void UpdateInstaller::revert() { + LOG(Info,"Reverting installation!"); std::map::const_iterator iter = m_backups.begin(); for (;iter != m_backups.end();iter++) { const std::string& installedFile = iter->first; const std::string& backupFile = iter->second; - - if (FileUtils::fileExists(installedFile.c_str())) + LOG(Info,"Restoring " + installedFile); + if(!m_dryRun) { - FileUtils::removeFile(installedFile.c_str()); + if (FileUtils::fileExists(installedFile.c_str())) + { + FileUtils::removeFile(installedFile.c_str()); + } + FileUtils::moveFile(backupFile.c_str(),installedFile.c_str()); } - FileUtils::moveFile(backupFile.c_str(),installedFile.c_str()); } } void UpdateInstaller::installFile(const UpdateScriptFile& file) { + std::string sourceFile = file.source; std::string destPath = file.dest; std::string target = file.linkTarget; + LOG(Info,"Installing file " + sourceFile + " to " + destPath); + // backup the existing file if any backupFile(destPath); @@ -281,22 +282,29 @@ void UpdateInstaller::installFile(const UpdateScriptFile& file) std::string destDir = FileUtils::dirname(destPath.c_str()); if (!FileUtils::fileExists(destDir.c_str())) { - FileUtils::mkpath(destDir.c_str()); + LOG(Info,"Destination path missing. Creating " + destDir); + if(!m_dryRun) + { + FileUtils::mkpath(destDir.c_str()); + } } - std::string sourceFile = file.source; if (!FileUtils::fileExists(sourceFile.c_str())) { throw "Source file does not exist: " + sourceFile; } - FileUtils::copyFile(sourceFile.c_str(),destPath.c_str()); + if(!m_dryRun) + { + FileUtils::copyFile(sourceFile.c_str(),destPath.c_str()); - // set the permissions on the newly extracted file - FileUtils::chmod(destPath.c_str(),file.permissions); + // set the permissions on the newly extracted file + FileUtils::chmod(destPath.c_str(),file.permissions); + } } void UpdateInstaller::installFiles() { + LOG(Info,"Installing files."); std::vector::const_iterator iter = m_script->filesToInstall().begin(); int filesInstalled = 0; for (;iter != m_script->filesToInstall().end();iter++) @@ -314,13 +322,18 @@ void UpdateInstaller::installFiles() void UpdateInstaller::uninstallFiles() { + LOG(Info,"Uninstalling files."); std::vector::const_iterator iter = m_script->filesToUninstall().begin(); for (;iter != m_script->filesToUninstall().end();iter++) { std::string path = m_installDir + '/' + iter->c_str(); if (FileUtils::fileExists(path.c_str())) { - FileUtils::removeFile(path.c_str()); + LOG(Info,"Uninstalling " + path); + if(!m_dryRun) + { + FileUtils::removeFile(path.c_str()); + } } else { @@ -336,30 +349,41 @@ void UpdateInstaller::backupFile(const std::string& path) // no existing file to backup return; } - std::string backupPath = path + ".bak"; - FileUtils::removeFile(backupPath.c_str()); - FileUtils::moveFile(path.c_str(), backupPath.c_str()); + LOG(Info,"Backing up file: " + path + " as " + backupPath); + if(!m_dryRun) + { + FileUtils::removeFile(backupPath.c_str()); + FileUtils::moveFile(path.c_str(), backupPath.c_str()); + } m_backups[path] = backupPath; } void UpdateInstaller::removeBackups() { + LOG(Info,"Removing backups."); std::map::const_iterator iter = m_backups.begin(); for (;iter != m_backups.end();iter++) { const std::string& backupFile = iter->second; - FileUtils::removeFile(backupFile.c_str()); + LOG(Info,"Removing " + backupFile); + if(!m_dryRun) + { + FileUtils::removeFile(backupFile.c_str()); + } } } bool UpdateInstaller::checkAccess() { std::string testFile = m_installDir + "/update-installer-test-file"; - + LOG(Info,"Checking for access: " + testFile); try { - FileUtils::removeFile(testFile.c_str()); + if(!m_dryRun) + { + FileUtils::removeFile(testFile.c_str()); + } } catch (const FileUtils::IOException& error) { @@ -368,8 +392,11 @@ bool UpdateInstaller::checkAccess() try { - FileUtils::touch(testFile.c_str()); - FileUtils::removeFile(testFile.c_str()); + if(!m_dryRun) + { + FileUtils::touch(testFile.c_str()); + FileUtils::removeFile(testFile.c_str()); + } return true; } catch (const FileUtils::IOException& error) @@ -394,7 +421,10 @@ void UpdateInstaller::restartMainApp() if (!command.empty()) { LOG(Info,"Starting main application " + command); - ProcessUtils::runAsync(command,args); + if(!m_dryRun) + { + ProcessUtils::runAsync(command,args); + } } else { @@ -415,7 +445,11 @@ void UpdateInstaller::postInstallUpdate() // touch the application's bundle directory so that // OS X' Launch Services notices any changes in the application's // Info.plist file. - FileUtils::touch(m_installDir.c_str()); + LOG(Info,"Touching " + m_installDir.c_str() + " to notify OSX of metadata changes."); + if(!m_dryRun) + { + FileUtils::touch(m_installDir.c_str()); + } #endif } @@ -424,3 +458,7 @@ void UpdateInstaller::setAutoClose(bool autoClose) m_autoClose = autoClose; } +void UpdateInstaller::setDryRun(bool dryRun) +{ + m_dryRun = dryRun; +} diff --git a/mmc_updater/src/UpdateInstaller.h b/mmc_updater/src/UpdateInstaller.h index 1eca0bc7..5cbac561 100644 --- a/mmc_updater/src/UpdateInstaller.h +++ b/mmc_updater/src/UpdateInstaller.h @@ -24,7 +24,6 @@ class UpdateInstaller Main }; - UpdateInstaller(); void setInstallDir(const std::string& path); void setPackageDir(const std::string& path); void setBackupDir(const std::string& path); @@ -33,6 +32,7 @@ class UpdateInstaller void setWaitPid(PLATFORM_PID pid); void setForceElevated(bool elevated); void setAutoClose(bool autoClose); + void setDryRun(bool dryRun); void setFinishCmd(const std::string& cmd); void setObserver(UpdateObserver* observer); @@ -57,16 +57,16 @@ class UpdateInstaller std::list updaterArgs() const; std::string friendlyErrorForError(const FileUtils::IOException& ex) const; - Mode m_mode; + Mode m_mode = Setup; std::string m_installDir; std::string m_packageDir; std::string m_backupDir; std::string m_finishCmd; - PLATFORM_PID m_waitPid; - UpdateScript* m_script; - UpdateObserver* m_observer; + PLATFORM_PID m_waitPid = 0; + UpdateScript* m_script = nullptr; + UpdateObserver* m_observer = nullptr; std::map m_backups; - bool m_forceElevated; - bool m_autoClose; + bool m_forceElevated = false; + bool m_autoClose = false; + bool m_dryRun = false; }; - diff --git a/mmc_updater/src/UpdaterOptions.cpp b/mmc_updater/src/UpdaterOptions.cpp index 0945431b..5f9e97d8 100644 --- a/mmc_updater/src/UpdaterOptions.cpp +++ b/mmc_updater/src/UpdaterOptions.cpp @@ -34,71 +34,6 @@ UpdateInstaller::Mode stringToMode(const std::string& modeStr) } } -void UpdaterOptions::parseOldFormatArg(const std::string& arg, std::string* key, std::string* value) -{ - size_t pos = arg.find('='); - if (pos != std::string::npos) - { - *key = arg.substr(0,pos); - *value = arg.substr(pos+1); - } -} - -// this is a compatibility function to allow the updater binary -// to be involved by legacy versions of Mendeley Desktop -// which used a different syntax for the updater's command-line -// arguments -void UpdaterOptions::parseOldFormatArgs(int argc, char** argv) -{ - for (int i=0; i < argc; i++) - { - std::string key; - std::string value; - - parseOldFormatArg(argv[i],&key,&value); - - if (key == "CurrentDir") - { - // CurrentDir is the directory containing the main application - // binary. On Mac and Linux this differs from the root of - // the installation directory - -#ifdef PLATFORM_LINUX - // the main binary is in lib/mendeleydesktop/libexec, - // go up 3 levels - installDir = FileUtils::canonicalPath((value + "/../../../").c_str()); -#elif defined(PLATFORM_MAC) - // the main binary is in Contents/MacOS, - // go up 2 levels - installDir = FileUtils::canonicalPath((value + "/../../").c_str()); -#elif defined(PLATFORM_WINDOWS) - // the main binary is in the root of the install directory - installDir = value; -#endif - } - else if (key == "TempDir") - { - packageDir = value; - } - else if (key == "UpdateScriptFileName") - { - scriptPath = value; - } - else if (key == "AppFileName") - { - // TODO - Store app file name - } - else if (key == "PID") - { - waitPid = static_cast(atoll(value.c_str())); - } - else if (key == "--main") - { - mode = UpdateInstaller::Main; - } - } -} - void UpdaterOptions::parse(int argc, char** argv) { AnyOption parser; @@ -110,6 +45,7 @@ void UpdaterOptions::parse(int argc, char** argv) parser.setOption("mode"); parser.setFlag("version"); parser.setFlag("force-elevated"); + parser.setFlag("dry-run"); parser.setFlag("auto-close"); parser.processCommandArgs(argc,argv); @@ -141,15 +77,6 @@ void UpdaterOptions::parse(int argc, char** argv) showVersion = parser.getFlag("version"); forceElevated = parser.getFlag("force-elevated"); + dryRun = parser.getFlag("dry-run"); autoClose = parser.getFlag("auto-close"); - - if (installDir.empty()) - { - // if no --install-dir argument is present, try parsing - // the command-line arguments in the old format (which uses - // a list of 'Key=Value' args) - parseOldFormatArgs(argc,argv); - } } - - diff --git a/mmc_updater/src/UpdaterOptions.h b/mmc_updater/src/UpdaterOptions.h index b4473a82..d9104804 100644 --- a/mmc_updater/src/UpdaterOptions.h +++ b/mmc_updater/src/UpdaterOptions.h @@ -18,11 +18,8 @@ class UpdaterOptions PLATFORM_PID waitPid; std::string logFile; bool showVersion; + bool dryRun; bool forceElevated; bool autoClose; - - private: - void parseOldFormatArgs(int argc, char** argv); - static void parseOldFormatArg(const std::string& arg, std::string* key, std::string* value); }; diff --git a/mmc_updater/src/main.cpp b/mmc_updater/src/main.cpp index fb072ab5..f6b31a32 100644 --- a/mmc_updater/src/main.cpp +++ b/mmc_updater/src/main.cpp @@ -148,6 +148,7 @@ int main(int argc, char** argv) installer.setForceElevated(options.forceElevated); installer.setAutoClose(options.autoClose); installer.setFinishCmd(options.finishCmd); + installer.setDryRun(options.dryRun); if (options.mode == UpdateInstaller::Main) {