From 2b998bb8cc8e83efafb20ed2fbe1a245d4d5ec5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 26 Sep 2017 13:38:34 +0200 Subject: [PATCH] NOISSUE implement LEgacy instance migration --- api/logic/CMakeLists.txt | 4 +- api/logic/FolderInstanceProvider.cpp | 10 ++ api/logic/FolderInstanceProvider.h | 3 + .../minecraft/legacy/LegacyMigrationTask.cpp | 51 ------- .../minecraft/legacy/LegacyUpgradeTask.cpp | 133 ++++++++++++++++++ ...acyMigrationTask.h => LegacyUpgradeTask.h} | 5 +- application/InstancePageProvider.h | 2 +- application/pages/LegacyUpgradePage.cpp | 21 ++- application/pages/LegacyUpgradePage.h | 12 +- 9 files changed, 179 insertions(+), 62 deletions(-) delete mode 100644 api/logic/minecraft/legacy/LegacyMigrationTask.cpp create mode 100644 api/logic/minecraft/legacy/LegacyUpgradeTask.cpp rename api/logic/minecraft/legacy/{LegacyMigrationTask.h => LegacyUpgradeTask.h} (73%) diff --git a/api/logic/CMakeLists.txt b/api/logic/CMakeLists.txt index 0a65c6e2..a99d22ab 100644 --- a/api/logic/CMakeLists.txt +++ b/api/logic/CMakeLists.txt @@ -232,8 +232,8 @@ set(MINECRAFT_SOURCES minecraft/legacy/LegacyModList.cpp minecraft/legacy/LegacyInstance.h minecraft/legacy/LegacyInstance.cpp - minecraft/legacy/LegacyMigrationTask.h - minecraft/legacy/LegacyMigrationTask.cpp + minecraft/legacy/LegacyUpgradeTask.h + minecraft/legacy/LegacyUpgradeTask.cpp minecraft/GradleSpecifier.h minecraft/MinecraftInstance.cpp minecraft/MinecraftInstance.h diff --git a/api/logic/FolderInstanceProvider.cpp b/api/logic/FolderInstanceProvider.cpp index 25e9bb84..53618439 100644 --- a/api/logic/FolderInstanceProvider.cpp +++ b/api/logic/FolderInstanceProvider.cpp @@ -430,6 +430,16 @@ Task * FolderInstanceProvider::copyTask(const InstancePtr& oldInstance, const QS return new FolderInstanceStaging(this, task, stagingPath, instName, instGroup); } +// FIXME: find a better place for this +#include "minecraft/legacy/LegacyUpgradeTask.h" +Task * FolderInstanceProvider::legacyUpgradeTask(const InstancePtr& oldInstance) +{ + auto stagingPath = getStagedInstancePath(); + QString newName = tr("%1 (Migrated)").arg(oldInstance->name()); + auto task = new LegacyUpgradeTask(m_globalSettings, stagingPath, oldInstance, newName); + return new FolderInstanceStaging(this, task, stagingPath, newName, oldInstance->group()); +} + QString FolderInstanceProvider::getStagedInstancePath() { QString key = QUuid::createUuid().toString(); diff --git a/api/logic/FolderInstanceProvider.h b/api/logic/FolderInstanceProvider.h index b3c6d955..a8d1a7bf 100644 --- a/api/logic/FolderInstanceProvider.h +++ b/api/logic/FolderInstanceProvider.h @@ -28,6 +28,9 @@ public: // import zipped instance into this provider Task * zipImportTask(const QUrl sourceUrl, const QString &instName, const QString &instGroup, const QString &instIcon); + // migrate an instance to the current format + Task * legacyUpgradeTask(const InstancePtr& oldInstance); + /** * Create a new empty staging area for instance creation and @return a path/key top commit it later. * Used by instance manipulation tasks. diff --git a/api/logic/minecraft/legacy/LegacyMigrationTask.cpp b/api/logic/minecraft/legacy/LegacyMigrationTask.cpp deleted file mode 100644 index 0d3cef35..00000000 --- a/api/logic/minecraft/legacy/LegacyMigrationTask.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include "LegacyMigrationTask.h" -#include "BaseInstanceProvider.h" -#include "settings/INISettingsObject.h" -#include "FileSystem.h" -#include "NullInstance.h" -#include "pathmatcher/RegexpMatcher.h" -#include - -LegacyMigrationTask::LegacyMigrationTask(SettingsObjectPtr settings, const QString & stagingPath, InstancePtr origInstance) -{ - m_globalSettings = settings; - m_stagingPath = stagingPath; - m_origInstance = origInstance; -} - -void LegacyMigrationTask::executeTask() -{ - setStatus(tr("Copying instance %1").arg(m_origInstance->name())); - - FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath); - folderCopy.followSymlinks(true); - - m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), folderCopy); - connect(&m_copyFutureWatcher, &QFutureWatcher::finished, this, &LegacyMigrationTask::copyFinished); - connect(&m_copyFutureWatcher, &QFutureWatcher::canceled, this, &LegacyMigrationTask::copyAborted); - m_copyFutureWatcher.setFuture(m_copyFuture); -} - -void LegacyMigrationTask::copyFinished() -{ - auto successful = m_copyFuture.result(); - if(!successful) - { - emitFailed(tr("Instance folder copy failed.")); - return; - } - // FIXME: shouldn't this be able to report errors? - auto instanceSettings = std::make_shared(FS::PathCombine(m_stagingPath, "instance.cfg")); - instanceSettings->registerSetting("InstanceType", "Legacy"); - - InstancePtr inst(new NullInstance(m_globalSettings, instanceSettings, m_stagingPath)); - inst->setName(tr("%1 (Migrated)").arg(m_origInstance->name())); - emitSucceeded(); -} - -void LegacyMigrationTask::copyAborted() -{ - emitFailed(tr("Instance folder copy has been aborted.")); - return; -} - diff --git a/api/logic/minecraft/legacy/LegacyUpgradeTask.cpp b/api/logic/minecraft/legacy/LegacyUpgradeTask.cpp new file mode 100644 index 00000000..cb0572ed --- /dev/null +++ b/api/logic/minecraft/legacy/LegacyUpgradeTask.cpp @@ -0,0 +1,133 @@ +#include "LegacyUpgradeTask.h" +#include "BaseInstanceProvider.h" +#include "settings/INISettingsObject.h" +#include "FileSystem.h" +#include "NullInstance.h" +#include "pathmatcher/RegexpMatcher.h" +#include +#include "LegacyInstance.h" +#include "minecraft/MinecraftInstance.h" +#include "minecraft/MinecraftProfile.h" + +LegacyUpgradeTask::LegacyUpgradeTask(SettingsObjectPtr settings, const QString & stagingPath, InstancePtr origInstance, const QString & newName) +{ + m_globalSettings = settings; + m_stagingPath = stagingPath; + m_origInstance = origInstance; + m_newName = newName; +} + +void LegacyUpgradeTask::executeTask() +{ + setStatus(tr("Copying instance %1").arg(m_origInstance->name())); + + FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath); + folderCopy.followSymlinks(true); + + m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), folderCopy); + connect(&m_copyFutureWatcher, &QFutureWatcher::finished, this, &LegacyUpgradeTask::copyFinished); + connect(&m_copyFutureWatcher, &QFutureWatcher::canceled, this, &LegacyUpgradeTask::copyAborted); + m_copyFutureWatcher.setFuture(m_copyFuture); +} + +static QString decideVersion(const QString& currentVersion, const QString& intendedVersion) +{ + if(intendedVersion != currentVersion) + { + if(!intendedVersion.isEmpty()) + { + return intendedVersion; + } + else if(!currentVersion.isEmpty()) + { + return currentVersion; + } + } + else + { + if(!intendedVersion.isEmpty()) + { + return intendedVersion; + } + } + // TODO: possibly add fallback to the old jar/classfile analysis method from MultiMC4 + return QString(); +} + +void LegacyUpgradeTask::copyFinished() +{ + auto successful = m_copyFuture.result(); + if(!successful) + { + emitFailed(tr("Instance folder copy failed.")); + return; + } + auto legacyInst = std::dynamic_pointer_cast(m_origInstance); + + auto instanceSettings = std::make_shared(FS::PathCombine(m_stagingPath, "instance.cfg")); + instanceSettings->registerSetting("InstanceType", "Legacy"); + instanceSettings->set("InstanceType", "OneSix"); + std::shared_ptr inst(new MinecraftInstance(m_globalSettings, instanceSettings, m_stagingPath)); + inst->setName(m_newName); + inst->init(); + + QString preferredVersionNumber = decideVersion(legacyInst->currentVersionId(), legacyInst->intendedVersionId()); + if(preferredVersionNumber.isNull()) + { + // FIXME: let the user decide + emitFailed(tr("Could not decide Minecraft version.")); + return; + } + inst->setComponentVersion("net.minecraft", preferredVersionNumber); + + // BUG: reloadProfile should not be necessary, but setComponentVersion voids the profile created by init()! + inst->reloadProfile(); + auto profile = inst->getMinecraftProfile(); + + if(legacyInst->shouldUseCustomBaseJar()) + { + QString jarPath = legacyInst->customBaseJar(); + qDebug() << "Base jar is custom! : " << jarPath; + // FIXME: handle case when the jar is unreadable? + // TODO: check the hash, if it's the same as the upstream jar, do not do this + profile->installCustomJar(jarPath); + } + + auto jarMods = legacyInst->getJarMods(); + for(auto & jarMod: jarMods) + { + QString modPath = jarMod.filename().absoluteFilePath(); + qDebug() << "jarMod: " << modPath; + profile->installJarMods({modPath}); + } + + // remove all the extra garbage we no longer need + auto removeAll = [&](const QString &root, const QStringList &things) + { + for(auto &thing : things) + { + auto removePath = FS::PathCombine(root, thing); + QFileInfo stat(removePath); + if(stat.isDir()) + { + FS::deletePath(removePath); + } + else + { + QFile::remove(removePath); + } + } + }; + QStringList rootRemovables = {"modlist", "version", "instMods"}; + QStringList mcRemovables = {"bin", "MultiMCLauncher.jar", "icon.png"}; + removeAll(inst->instanceRoot(), rootRemovables); + removeAll(inst->minecraftRoot(), mcRemovables); + emitSucceeded(); +} + +void LegacyUpgradeTask::copyAborted() +{ + emitFailed(tr("Instance folder copy has been aborted.")); + return; +} + diff --git a/api/logic/minecraft/legacy/LegacyMigrationTask.h b/api/logic/minecraft/legacy/LegacyUpgradeTask.h similarity index 73% rename from api/logic/minecraft/legacy/LegacyMigrationTask.h rename to api/logic/minecraft/legacy/LegacyUpgradeTask.h index 36cfa240..56896385 100644 --- a/api/logic/minecraft/legacy/LegacyMigrationTask.h +++ b/api/logic/minecraft/legacy/LegacyUpgradeTask.h @@ -13,11 +13,11 @@ class BaseInstanceProvider; -class MULTIMC_LOGIC_EXPORT LegacyMigrationTask : public Task +class MULTIMC_LOGIC_EXPORT LegacyUpgradeTask : public Task { Q_OBJECT public: - explicit LegacyMigrationTask(SettingsObjectPtr settings, const QString & stagingPath, InstancePtr origInstance); + explicit LegacyUpgradeTask(SettingsObjectPtr settings, const QString & stagingPath, InstancePtr origInstance, const QString & newName); protected: //! Entry point for tasks. @@ -29,6 +29,7 @@ private: /* data */ SettingsObjectPtr m_globalSettings; InstancePtr m_origInstance; QString m_stagingPath; + QString m_newName; QFuture m_copyFuture; QFutureWatcher m_copyFutureWatcher; }; diff --git a/application/InstancePageProvider.h b/application/InstancePageProvider.h index 1f5a6aef..b13ce93d 100644 --- a/application/InstancePageProvider.h +++ b/application/InstancePageProvider.h @@ -49,7 +49,7 @@ public: std::shared_ptr legacy = std::dynamic_pointer_cast(inst); if(legacy) { - values.append(new LegacyUpgradePage(legacy.get())); + values.append(new LegacyUpgradePage(legacy)); values.append(new NotesPage(legacy.get())); values.append(new WorldListPage(legacy.get(), legacy->worldList(), "worlds", "worlds", tr("Worlds"), "Worlds")); values.append(new ScreenshotsPage(FS::PathCombine(legacy->minecraftRoot(), "screenshots"))); diff --git a/application/pages/LegacyUpgradePage.cpp b/application/pages/LegacyUpgradePage.cpp index 14cb916d..c1ad0146 100644 --- a/application/pages/LegacyUpgradePage.cpp +++ b/application/pages/LegacyUpgradePage.cpp @@ -2,8 +2,13 @@ #include "ui_LegacyUpgradePage.h" #include "minecraft/legacy/LegacyInstance.h" +#include "minecraft/legacy/LegacyUpgradeTask.h" +#include "MultiMC.h" +#include "FolderInstanceProvider.h" +#include "dialogs/CustomMessageBox.h" +#include "dialogs/ProgressDialog.h" -LegacyUpgradePage::LegacyUpgradePage(LegacyInstance *inst, QWidget *parent) +LegacyUpgradePage::LegacyUpgradePage(InstancePtr inst, QWidget *parent) : QWidget(parent), ui(new Ui::LegacyUpgradePage), m_inst(inst) { ui->setupUi(this); @@ -14,9 +19,21 @@ LegacyUpgradePage::~LegacyUpgradePage() delete ui; } +void LegacyUpgradePage::runModalTask(Task *task) +{ + connect(task, &Task::failed, [this](QString reason) + { + CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Warning)->show(); + }); + ProgressDialog loadDialog(this); + loadDialog.setSkipButton(true, tr("Abort")); + loadDialog.execWithTask(task); +} + void LegacyUpgradePage::on_upgradeButton_clicked() { - // now what? + std::unique_ptr task(MMC->folderProvider()->legacyUpgradeTask(m_inst)); + runModalTask(task.get()); } bool LegacyUpgradePage::shouldDisplay() const diff --git a/application/pages/LegacyUpgradePage.h b/application/pages/LegacyUpgradePage.h index 4731bb82..5de958c4 100644 --- a/application/pages/LegacyUpgradePage.h +++ b/application/pages/LegacyUpgradePage.h @@ -20,6 +20,7 @@ #include "minecraft/legacy/LegacyInstance.h" #include "pages/BasePage.h" #include +#include "tasks/Task.h" namespace Ui { @@ -31,7 +32,7 @@ class LegacyUpgradePage : public QWidget, public BasePage Q_OBJECT public: - explicit LegacyUpgradePage(LegacyInstance *inst, QWidget *parent = 0); + explicit LegacyUpgradePage(InstancePtr inst, QWidget *parent = 0); virtual ~LegacyUpgradePage(); virtual QString displayName() const override { @@ -50,11 +51,14 @@ public: return "Legacy-upgrade"; } virtual bool shouldDisplay() const override; -private -slots: + +private slots: void on_upgradeButton_clicked(); +private: + void runModalTask(Task *task); + private: Ui::LegacyUpgradePage *ui; - LegacyInstance *m_inst; + InstancePtr m_inst; };