diff options
author | Petr Mrázek <peterix@gmail.com> | 2014-03-01 23:06:47 +0100 |
---|---|---|
committer | Petr Mrázek <peterix@gmail.com> | 2014-03-01 23:06:47 +0100 |
commit | 7c24bcc83476dcbdd7f7acbe14ecef4398962689 (patch) | |
tree | 4ab7e7020927d05274f079c3045bd572c218fa21 /logic/OneSixVersionBuilder.cpp | |
parent | 7dfd6aa051c582e26125e17e1d6eed5e675e1027 (diff) | |
download | MultiMC-7c24bcc83476dcbdd7f7acbe14ecef4398962689.tar MultiMC-7c24bcc83476dcbdd7f7acbe14ecef4398962689.tar.gz MultiMC-7c24bcc83476dcbdd7f7acbe14ecef4398962689.tar.lz MultiMC-7c24bcc83476dcbdd7f7acbe14ecef4398962689.tar.xz MultiMC-7c24bcc83476dcbdd7f7acbe14ecef4398962689.zip |
Reorganize the version-related code.
Diffstat (limited to 'logic/OneSixVersionBuilder.cpp')
-rw-r--r-- | logic/OneSixVersionBuilder.cpp | 797 |
1 files changed, 14 insertions, 783 deletions
diff --git a/logic/OneSixVersionBuilder.cpp b/logic/OneSixVersionBuilder.cpp index f6917697..0d4d66a2 100644 --- a/logic/OneSixVersionBuilder.cpp +++ b/logic/OneSixVersionBuilder.cpp @@ -26,806 +26,37 @@ #include <QDir> #include <QDebug> -#include "OneSixVersion.h" +#include "VersionFinal.h" #include "OneSixInstance.h" #include "OneSixRule.h" +#include "VersionFile.h" #include "modutils.h" #include "logger/QsLog.h" -#define CURRENT_MINIMUM_LAUNCHER_VERSION 14 - -struct VersionFile -{ - int order; - QString name; - QString fileId; - QString version; - // TODO use the mcVersion to determine if a version file should be removed on update - QString mcVersion; - QString filename; - // TODO requirements - // QMap<QString, QString> requirements; - QString id; - QString mainClass; - QString overwriteMinecraftArguments; - QString addMinecraftArguments; - QString removeMinecraftArguments; - QString processArguments; - QString type; - QString releaseTime; - QString time; - QString assets; - int minimumLauncherVersion = -1; - - bool shouldOverwriteTweakers = false; - QStringList overwriteTweakers; - QStringList addTweakers; - QStringList removeTweakers; - - struct Library - { - QString name; - QString url; - QString hint; - QString absoluteUrl; - bool applyExcludes = false; - QStringList excludes; - bool applyNatives = false; - QList<QPair<OpSys, QString>> natives; - bool applyRules = false; - QList<std::shared_ptr<Rule>> rules; - - // user for '+' libraries - enum InsertType - { - Apply, - Append, - Prepend, - Replace - }; - InsertType insertType = Append; - QString insertData; - enum DependType - { - Soft, - Hard - }; - DependType dependType = Soft; - }; - bool shouldOverwriteLibs = false; - QList<Library> overwriteLibs; - QList<Library> addLibs; - QList<QString> removeLibs; - - enum ApplyError - { - LauncherVersionError, - OtherError, - NoApplyError - }; - - static Library fromLibraryJson(const QJsonObject &libObj, const QString &filename, - bool &isError) - { - isError = true; - Library out; - if (!libObj.contains("name")) - { - QLOG_ERROR() << filename << "contains a library that doesn't have a 'name' field"; - return out; - } - out.name = libObj.value("name").toString(); - - auto readString = [libObj, filename](const QString &key, QString &variable) - { - if (libObj.contains(key)) - { - QJsonValue val = libObj.value(key); - if (!val.isString()) - { - QLOG_WARN() << key << "is not a string in" << filename << "(skipping)"; - } - else - { - variable = val.toString(); - } - } - }; - - readString("url", out.url); - readString("MMC-hint", out.hint); - readString("MMC-absulute_url", out.absoluteUrl); - readString("MMC-absoluteUrl", out.absoluteUrl); - if (libObj.contains("extract")) - { - if (!libObj.value("extract").isObject()) - { - QLOG_ERROR() - << filename - << "contains a library with an 'extract' field that's not an object"; - return out; - } - QJsonObject extractObj = libObj.value("extract").toObject(); - if (!extractObj.contains("exclude") || !extractObj.value("exclude").isArray()) - { - QLOG_ERROR() << filename - << "contains a library with an invalid 'extract' field"; - return out; - } - out.applyExcludes = true; - QJsonArray excludeArray = extractObj.value("exclude").toArray(); - for (auto excludeVal : excludeArray) - { - if (!excludeVal.isString()) - { - QLOG_WARN() << filename << "contains a library that contains an 'extract' " - "field that contains an invalid 'exclude' entry " - "(skipping)"; - } - else - { - out.excludes.append(excludeVal.toString()); - } - } - } - if (libObj.contains("natives")) - { - if (!libObj.value("natives").isObject()) - { - QLOG_ERROR() - << filename - << "contains a library with a 'natives' field that's not an object"; - return out; - } - out.applyNatives = true; - QJsonObject nativesObj = libObj.value("natives").toObject(); - for (auto it = nativesObj.begin(); it != nativesObj.end(); ++it) - { - if (!it.value().isString()) - { - QLOG_WARN() << filename << "contains an invalid native (skipping)"; - } - OpSys opSys = OpSys_fromString(it.key()); - if (opSys != Os_Other) - { - out.natives.append(qMakePair(opSys, it.value().toString())); - } - } - } - if (libObj.contains("rules")) - { - out.applyRules = true; - out.rules = rulesFromJsonV4(libObj); - } - isError = false; - return out; - } - static VersionFile fromJson(const QJsonDocument &doc, const QString &filename, - const bool requireOrder, bool &isError, const OneSixVersionBuilder::ParseFlags flags = OneSixVersionBuilder::NoFlags) - { - VersionFile out; - isError = true; - if (doc.isEmpty() || doc.isNull()) - { - QLOG_ERROR() << filename << "is empty or null"; - return out; - } - if (!doc.isObject()) - { - QLOG_ERROR() << "The root of" << filename << "is not an object"; - return out; - } - - QJsonObject root = doc.object(); - - if (requireOrder) - { - if (root.contains("order")) - { - if (root.value("order").isDouble()) - { - out.order = root.value("order").toDouble(); - } - else - { - QLOG_ERROR() << "'order' field contains an invalid value in" << filename; - return out; - } - } - else - { - QLOG_ERROR() << filename << "doesn't contain an order field"; - } - } - - out.name = root.value("name").toString(); - out.fileId = root.value("fileId").toString(); - out.version = root.value("version").toString(); - out.mcVersion = root.value("mcVersion").toString(); - out.filename = filename; - - auto readString = [root, filename](const QString &key, QString &variable) - { - if (root.contains(key)) - { - QJsonValue val = root.value(key); - if (!val.isString()) - { - QLOG_WARN() << key << "is not a string in" << filename << "(skipping)"; - } - else - { - variable = val.toString(); - } - } - }; - - if (!(flags & OneSixVersionBuilder::IsFTBPackJson)) - { - readString("id", out.id); - } - readString("mainClass", out.mainClass); - readString("processArguments", out.processArguments); - readString("minecraftArguments", out.overwriteMinecraftArguments); - readString("+minecraftArguments", out.addMinecraftArguments); - readString("-minecraftArguments", out.removeMinecraftArguments); - readString("type", out.type); - readString("releaseTime", out.releaseTime); - readString("time", out.time); - readString("assets", out.assets); - if (root.contains("minimumLauncherVersion")) - { - QJsonValue val = root.value("minimumLauncherVersion"); - if (!val.isDouble()) - { - QLOG_WARN() << "minimumLauncherVersion is not an int in" << filename - << "(skipping)"; - } - else - { - out.minimumLauncherVersion = val.toDouble(); - } - } - - if (root.contains("tweakers")) - { - QJsonValue tweakersVal = root.value("tweakers"); - if (!tweakersVal.isArray()) - { - QLOG_ERROR() << filename - << "contains a 'tweakers' field, but it's not an array"; - return out; - } - out.shouldOverwriteTweakers = true; - QJsonArray tweakers = root.value("tweakers").toArray(); - for (auto tweakerVal : tweakers) - { - if (!tweakerVal.isString()) - { - QLOG_ERROR() << filename - << "contains a 'tweakers' field entry that's not a string"; - return out; - } - out.overwriteTweakers.append(tweakerVal.toString()); - } - } - if (root.contains("+tweakers")) - { - QJsonValue tweakersVal = root.value("+tweakers"); - if (!tweakersVal.isArray()) - { - QLOG_ERROR() << filename - << "contains a '+tweakers' field, but it's not an array"; - return out; - } - QJsonArray tweakers = root.value("+tweakers").toArray(); - for (auto tweakerVal : tweakers) - { - if (!tweakerVal.isString()) - { - QLOG_ERROR() << filename - << "contains a '+tweakers' field entry that's not a string"; - return out; - } - out.addTweakers.append(tweakerVal.toString()); - } - } - if (root.contains("-tweakers")) - { - QJsonValue tweakersVal = root.value("-tweakers"); - if (!tweakersVal.isArray()) - { - QLOG_ERROR() << filename - << "contains a '-tweakers' field, but it's not an array"; - return out; - } - out.shouldOverwriteTweakers = true; - QJsonArray tweakers = root.value("-tweakers").toArray(); - for (auto tweakerVal : tweakers) - { - if (!tweakerVal.isString()) - { - QLOG_ERROR() << filename - << "contains a '-tweakers' field entry that's not a string"; - return out; - } - out.removeTweakers.append(tweakerVal.toString()); - } - } - - if (root.contains("libraries")) - { - out.shouldOverwriteLibs = !(flags & OneSixVersionBuilder::IsFTBPackJson); - QJsonValue librariesVal = root.value("libraries"); - if (!librariesVal.isArray()) - { - QLOG_ERROR() << filename - << "contains a 'libraries' field, but its not an array"; - return out; - } - QJsonArray librariesArray = librariesVal.toArray(); - for (auto libVal : librariesArray) - { - if (!libVal.isObject()) - { - QLOG_ERROR() << filename << "contains a library that's not an object"; - return out; - } - QJsonObject libObj = libVal.toObject(); - bool error; - Library lib = fromLibraryJson(libObj, filename, error); - if (error) - { - QLOG_ERROR() << "Error while reading a library entry in" << filename; - return out; - } - if (flags & OneSixVersionBuilder::IsFTBPackJson) - { - lib.hint = "local"; - lib.insertType = Library::Prepend; - out.addLibs.prepend(lib); - } - else - { - out.overwriteLibs.append(lib); - } - } - } - if (root.contains("+libraries")) - { - QJsonValue librariesVal = root.value("+libraries"); - if (!librariesVal.isArray()) - { - QLOG_ERROR() << filename - << "contains a '+libraries' field, but its not an array"; - return out; - } - QJsonArray librariesArray = librariesVal.toArray(); - for (auto libVal : librariesArray) - { - if (!libVal.isObject()) - { - QLOG_ERROR() << filename << "contains a library that's not an object"; - return out; - } - QJsonObject libObj = libVal.toObject(); - bool error; - Library lib = fromLibraryJson(libObj, filename, error); - if (error) - { - QLOG_ERROR() << "Error while reading a library entry in" << filename; - return out; - } - if (!libObj.contains("insert")) - { - QLOG_ERROR() << "Missing 'insert' field in '+libraries' field in" - << filename; - return out; - } - QJsonValue insertVal = libObj.value("insert"); - QString insertString; - { - if (insertVal.isString()) - { - insertString = insertVal.toString(); - } - else if (insertVal.isObject()) - { - QJsonObject insertObj = insertVal.toObject(); - if (insertObj.isEmpty()) - { - QLOG_ERROR() << "One library has an empty insert object in" - << filename; - return out; - } - insertString = insertObj.keys().first(); - lib.insertData = insertObj.value(insertString).toString(); - } - } - if (insertString == "apply") - { - lib.insertType = Library::Apply; - } - else if (insertString == "prepend") - { - lib.insertType = Library::Prepend; - } - else if (insertString == "append") - { - lib.insertType = Library::Prepend; - } - else if (insertString == "replace") - { - lib.insertType = Library::Replace; - } - else - { - QLOG_ERROR() << "A '+' library in" << filename - << "contains an invalid insert type"; - return out; - } - if (libObj.contains("MMC-depend") && libObj.value("MMC-depend").isString()) - { - const QString dependString = libObj.value("MMC-depend").toString(); - if (dependString == "hard") - { - lib.dependType = Library::Hard; - } - else if (dependString == "soft") - { - lib.dependType = Library::Soft; - } - else - { - QLOG_ERROR() << "A '+' library in" << filename - << "contains an invalid depend type"; - return out; - } - } - out.addLibs.append(lib); - } - } - if (root.contains("-libraries")) - { - QJsonValue librariesVal = root.value("-libraries"); - if (!librariesVal.isArray()) - { - QLOG_ERROR() << filename - << "contains a '-libraries' field, but its not an array"; - return out; - } - QJsonArray librariesArray = librariesVal.toArray(); - for (auto libVal : librariesArray) - { - if (!libVal.isObject()) - { - QLOG_ERROR() << filename << "contains a library that's not an object"; - return out; - } - QJsonObject libObj = libVal.toObject(); - if (!libObj.contains("name")) - { - QLOG_ERROR() << filename << "contains a library without a name"; - return out; - } - if (!libObj.value("name").isString()) - { - QLOG_ERROR() << filename - << "contains a library without a valid 'name' field"; - return out; - } - out.removeLibs.append(libObj.value("name").toString()); - } - } - - isError = false; - return out; - } - - static std::shared_ptr<OneSixLibrary> createLibrary(const Library &lib) - { - std::shared_ptr<OneSixLibrary> out(new OneSixLibrary(lib.name)); - if (!lib.url.isEmpty()) - { - out->setBaseUrl(lib.url); - } - out->setHint(lib.hint); - if (!lib.absoluteUrl.isEmpty()) - { - out->setAbsoluteUrl(lib.absoluteUrl); - } - out->setAbsoluteUrl(lib.absoluteUrl); - out->extract_excludes = lib.excludes; - for (auto native : lib.natives) - { - out->addNative(native.first, native.second); - } - out->setRules(lib.rules); - out->finalize(); - return out; - } - int findLibrary(QList<std::shared_ptr<OneSixLibrary>> haystack, const QString &needle) - { - for (int i = 0; i < haystack.size(); ++i) - { - if (QRegExp(needle, Qt::CaseSensitive, QRegExp::WildcardUnix) - .indexIn(haystack.at(i)->rawName()) != -1) - { - return i; - } - } - return -1; - } - ApplyError applyTo(OneSixVersion *version) - { - if (minimumLauncherVersion != -1) - { - if (minimumLauncherVersion > CURRENT_MINIMUM_LAUNCHER_VERSION) - { - QLOG_ERROR() << filename << "is for a different launcher version (" - << minimumLauncherVersion << "), current supported is" - << CURRENT_MINIMUM_LAUNCHER_VERSION; - return LauncherVersionError; - } - } - - if (!version->id.isNull() && !mcVersion.isNull()) - { - if (QRegExp(mcVersion, Qt::CaseInsensitive, QRegExp::Wildcard) - .indexIn(version->id) == -1) - { - QLOG_ERROR() << filename << "is for a different version of Minecraft"; - return OtherError; - } - } - - if (!id.isNull()) - { - version->id = id; - } - if (!mainClass.isNull()) - { - version->mainClass = mainClass; - } - if (!processArguments.isNull()) - { - version->processArguments = processArguments; - } - if (!type.isNull()) - { - version->type = type; - } - if (!releaseTime.isNull()) - { - version->releaseTime = releaseTime; - } - if (!time.isNull()) - { - version->time = time; - } - if (!assets.isNull()) - { - version->assets = assets; - } - if (minimumLauncherVersion >= 0) - { - version->minimumLauncherVersion = minimumLauncherVersion; - } - if (!overwriteMinecraftArguments.isNull()) - { - version->minecraftArguments = overwriteMinecraftArguments; - } - if (!addMinecraftArguments.isNull()) - { - version->minecraftArguments += addMinecraftArguments; - } - if (!removeMinecraftArguments.isNull()) - { - version->minecraftArguments.remove(removeMinecraftArguments); - } - if (shouldOverwriteTweakers) - { - version->tweakers = overwriteTweakers; - } - for (auto tweaker : addTweakers) - { - version->tweakers += tweaker; - } - for (auto tweaker : removeTweakers) - { - version->tweakers.removeAll(tweaker); - } - if (shouldOverwriteLibs) - { - version->libraries.clear(); - for (auto lib : overwriteLibs) - { - version->libraries.append(createLibrary(lib)); - } - } - for (auto lib : addLibs) - { - switch (lib.insertType) - { - case Library::Apply: - { - - int index = findLibrary(version->libraries, lib.name); - if (index >= 0) - { - auto library = version->libraries[index]; - if (!lib.url.isNull()) - { - library->setBaseUrl(lib.url); - } - if (!lib.hint.isNull()) - { - library->setHint(lib.hint); - } - if (!lib.absoluteUrl.isNull()) - { - library->setAbsoluteUrl(lib.absoluteUrl); - } - if (lib.applyExcludes) - { - library->extract_excludes = lib.excludes; - } - if (lib.applyNatives) - { - library->clearSuffixes(); - for (auto native : lib.natives) - { - library->addNative(native.first, native.second); - } - } - if (lib.applyRules) - { - library->setRules(lib.rules); - } - library->finalize(); - } - else - { - QLOG_WARN() << "Couldn't find" << lib.insertData << "(skipping)"; - } - break; - } - case Library::Append: - case Library::Prepend: - { - - const int startOfVersion = lib.name.lastIndexOf(':') + 1; - const int index = - findLibrary(version->libraries, - QString(lib.name).replace(startOfVersion, INT_MAX, '*')); - if (index < 0) - { - if (lib.insertType == Library::Append) - { - version->libraries.append(createLibrary(lib)); - } - else - { - version->libraries.prepend(createLibrary(lib)); - } - } - else - { - auto otherLib = version->libraries.at(index); - const Util::Version ourVersion = lib.name.mid(startOfVersion, INT_MAX); - const Util::Version otherVersion = otherLib->version(); - // if the existing version is a hard dependency we can either use it or - // fail, but we can't change it - if (otherLib->dependType == OneSixLibrary::Hard) - { - // we need a higher version, or we're hard to and the versions aren't - // equal - if (ourVersion > otherVersion || - (lib.dependType == Library::Hard && ourVersion != otherVersion)) - { - QLOG_ERROR() << "Error resolving library dependencies between" - << otherLib->rawName() << "and" << lib.name << "in" - << filename; - return OtherError; - } - else - { - // the library is already existing, so we don't have to do anything - } - } - else if (otherLib->dependType == OneSixLibrary::Soft) - { - // if we are higher it means we should update - if (ourVersion > otherVersion) - { - auto library = createLibrary(lib); - if (Util::Version(otherLib->minVersion) < ourVersion) - { - library->minVersion = ourVersion.toString(); - } - version->libraries.replace(index, library); - } - else - { - // our version is smaller than the existing version, but we require - // it: fail - if (lib.dependType == Library::Hard) - { - QLOG_ERROR() << "Error resolving library dependencies between" - << otherLib->rawName() << "and" << lib.name << "in" - << filename; - return OtherError; - } - } - } - } - break; - } - case Library::Replace: - { - int index = findLibrary(version->libraries, lib.insertData); - if (index >= 0) - { - version->libraries.replace(index, createLibrary(lib)); - } - else - { - QLOG_WARN() << "Couldn't find" << lib.insertData << "(skipping)"; - } - break; - } - } - } - for (auto lib : removeLibs) - { - int index = findLibrary(version->libraries, lib); - if (index >= 0) - { - version->libraries.removeAt(index); - } - else - { - QLOG_WARN() << "Couldn't find" << lib << "(skipping)"; - } - } - - OneSixVersion::VersionFile versionFile; - versionFile.name = name; - versionFile.id = fileId; - versionFile.version = this->version; - versionFile.mcVersion = mcVersion; - versionFile.filename = filename; - versionFile.order = order; - version->versionFiles.append(versionFile); - - return NoApplyError; - } -}; - OneSixVersionBuilder::OneSixVersionBuilder() { } -bool OneSixVersionBuilder::build(OneSixVersion *version, OneSixInstance *instance, +bool OneSixVersionBuilder::build(VersionFinal *version, OneSixInstance *instance, QWidget *widgetParent, const bool onlyVanilla, const QStringList &external) { OneSixVersionBuilder builder; builder.m_version = version; builder.m_instance = instance; builder.m_widgetParent = widgetParent; - return builder.build(onlyVanilla, external); + return builder.buildInternal(onlyVanilla, external); } -bool OneSixVersionBuilder::read(OneSixVersion *version, const QJsonObject &obj) +bool OneSixVersionBuilder::readJsonAndApplyToVersion(VersionFinal *version, const QJsonObject &obj) { OneSixVersionBuilder builder; builder.m_version = version; builder.m_instance = 0; builder.m_widgetParent = 0; - return builder.read(obj); + return builder.readJsonAndApply(obj); } -bool OneSixVersionBuilder::build(const bool onlyVanilla, const QStringList &external) +bool OneSixVersionBuilder::buildInternal(const bool onlyVanilla, const QStringList &external) { m_version->clear(); @@ -837,8 +68,7 @@ bool OneSixVersionBuilder::build(const bool onlyVanilla, const QStringList &exte { QLOG_INFO() << "Reading" << fileName; VersionFile file; - ParseFlags flags = fileName.endsWith("pack.json") ? IsFTBPackJson : NoFlags; - if (!read(QFileInfo(fileName), false, &file, flags)) + if (!parseJsonFile(QFileInfo(fileName), false, &file, fileName.endsWith("pack.json") ? IsFTBPackJson : NoFlags)) { return false; } @@ -856,7 +86,7 @@ bool OneSixVersionBuilder::build(const bool onlyVanilla, const QStringList &exte { QLOG_INFO() << "Reading custom.json"; VersionFile file; - if (!read(QFileInfo(root.absoluteFilePath("custom.json")), false, &file)) + if (!parseJsonFile(QFileInfo(root.absoluteFilePath("custom.json")), false, &file)) { return false; } @@ -876,7 +106,7 @@ bool OneSixVersionBuilder::build(const bool onlyVanilla, const QStringList &exte // version.json QLOG_INFO() << "Reading version.json"; VersionFile file; - if (!read(QFileInfo(root.absoluteFilePath("version.json")), false, &file)) + if (!parseJsonFile(QFileInfo(root.absoluteFilePath("version.json")), false, &file)) { return false; } @@ -907,7 +137,7 @@ bool OneSixVersionBuilder::build(const bool onlyVanilla, const QStringList &exte { QLOG_INFO() << "Reading" << info.fileName(); VersionFile file; - if (!read(info, true, &file)) + if (!parseJsonFile(info, true, &file)) { return false; } @@ -968,7 +198,7 @@ bool OneSixVersionBuilder::build(const bool onlyVanilla, const QStringList &exte return true; } -bool OneSixVersionBuilder::read(const QJsonObject &obj) +bool OneSixVersionBuilder::readJsonAndApply(const QJsonObject &obj) { m_version->clear(); @@ -1000,7 +230,7 @@ bool OneSixVersionBuilder::read(const QJsonObject &obj) return true; } -bool OneSixVersionBuilder::read(const QFileInfo &fileInfo, const bool requireOrder, +bool OneSixVersionBuilder::parseJsonFile(const QFileInfo &fileInfo, const bool requireOrder, VersionFile *out, const ParseFlags flags) { QFile file(fileInfo.absoluteFilePath()); @@ -1072,6 +302,7 @@ QMap<QString, int> OneSixVersionBuilder::readOverrideOrders(OneSixInstance *inst } return out; } + bool OneSixVersionBuilder::writeOverrideOrders(const QMap<QString, int> &order, OneSixInstance *instance) { |