From 719f3e863a2bdbaeaba37e837e0f6b75de124e6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Fri, 29 Dec 2017 00:37:14 +0100 Subject: [PATCH] NOISSUE add versioning to component metadata format and use it --- api/logic/meta/JsonFormat.cpp | 73 ++++++++++++++------- api/logic/meta/JsonFormat.h | 10 +++ api/logic/meta/Version.cpp | 10 --- api/logic/meta/Version.h | 6 -- api/logic/meta/VersionList.cpp | 26 ++------ api/logic/meta/VersionList.h | 6 -- api/logic/minecraft/ComponentList.cpp | 34 ++-------- api/logic/minecraft/OneSixVersionFormat.cpp | 25 ++++++- api/logic/minecraft/VersionFile.h | 2 +- application/pages/VersionPage.cpp | 38 ----------- 10 files changed, 94 insertions(+), 136 deletions(-) diff --git a/api/logic/meta/JsonFormat.cpp b/api/logic/meta/JsonFormat.cpp index 832743ed..6e84597c 100644 --- a/api/logic/meta/JsonFormat.cpp +++ b/api/logic/meta/JsonFormat.cpp @@ -28,6 +28,11 @@ using namespace Json; namespace Meta { +MetadataVersion currentFormatVersion() +{ + return MetadataVersion::InitialRelease; +} + // Index static std::shared_ptr parseIndexInternal(const QJsonObject &obj) { @@ -49,7 +54,6 @@ static VersionPtr parseCommonVersion(const QString &uid, const QJsonObject &obj) VersionPtr version = std::make_shared(uid, requireString(obj, "version")); version->setTime(QDateTime::fromString(requireString(obj, "releaseTime"), Qt::ISODate).toMSecsSinceEpoch() / 1000); version->setType(ensureString(obj, "type", QString())); - version->setParentUid(ensureString(obj, "parentUid", QString())); version->setRecommended(ensureBoolean(obj, QString("recommended"), false)); version->setVolatile(ensureBoolean(obj, QString("volatile"), false)); RequireSet requires, conflicts; @@ -86,56 +90,79 @@ static std::shared_ptr parseVersionListInternal(const QJsonObject & VersionListPtr list = std::make_shared(uid); list->setName(ensureString(obj, "name", QString())); - list->setParentUid(ensureString(obj, "parentUid", QString())); list->setVersions(versions); return list; } -static int formatVersion(const QJsonObject &obj) +MetadataVersion parseFormatVersion(const QJsonObject &obj, bool required) { - if (!obj.contains("formatVersion")) { - throw ParseException(QObject::tr("Missing required field: 'formatVersion'")); + if (!obj.contains("formatVersion")) + { + if(required) + { + return MetadataVersion::Invalid; + } + return MetadataVersion::InitialRelease; } - if (!obj.value("formatVersion").isDouble()) { - throw ParseException(QObject::tr("Required field has invalid type: 'formatVersion'")); + if (!obj.value("formatVersion").isDouble()) + { + return MetadataVersion::Invalid; } - return obj.value("formatVersion").toInt(); + switch(obj.value("formatVersion").toInt()) + { + case 0: + return MetadataVersion::InitialRelease; + default: + return MetadataVersion::Invalid; + } +} + +void serializeFormatVersion(QJsonObject& obj, Meta::MetadataVersion version) +{ + if(version == MetadataVersion::Invalid) + { + return; + } + obj.insert("formatVersion", int(version)); } void parseIndex(const QJsonObject &obj, Index *ptr) { - const int version = formatVersion(obj); - switch (version) { - case 0: + const MetadataVersion version = parseFormatVersion(obj); + switch (version) + { + case MetadataVersion::InitialRelease: ptr->merge(parseIndexInternal(obj)); break; - default: - throw ParseException(QObject::tr("Unknown formatVersion: %1").arg(version)); + case MetadataVersion::Invalid: + throw ParseException(QObject::tr("Unknown format version!")); } } void parseVersionList(const QJsonObject &obj, VersionList *ptr) { - const int version = formatVersion(obj); - switch (version) { - case 0: + const MetadataVersion version = parseFormatVersion(obj); + switch (version) + { + case MetadataVersion::InitialRelease: ptr->merge(parseVersionListInternal(obj)); break; - default: - throw ParseException(QObject::tr("Unknown formatVersion: %1").arg(version)); + case MetadataVersion::Invalid: + throw ParseException(QObject::tr("Unknown format version!")); } } void parseVersion(const QJsonObject &obj, Version *ptr) { - const int version = formatVersion(obj); - switch (version) { - case 0: + const MetadataVersion version = parseFormatVersion(obj); + switch (version) + { + case MetadataVersion::InitialRelease: ptr->merge(parseVersionInternal(obj)); break; - default: - throw ParseException(QObject::tr("Unknown formatVersion: %1").arg(version)); + case MetadataVersion::Invalid: + throw ParseException(QObject::tr("Unknown format version!")); } } diff --git a/api/logic/meta/JsonFormat.h b/api/logic/meta/JsonFormat.h index 9b9dcd91..82ab0ce3 100644 --- a/api/logic/meta/JsonFormat.h +++ b/api/logic/meta/JsonFormat.h @@ -28,6 +28,12 @@ class Index; class Version; class VersionList; +enum class MetadataVersion +{ + Invalid = -1, + InitialRelease = 0 +}; + class ParseException : public Exception { public: @@ -65,9 +71,13 @@ void parseIndex(const QJsonObject &obj, Index *ptr); void parseVersion(const QJsonObject &obj, Version *ptr); void parseVersionList(const QJsonObject &obj, VersionList *ptr); +MetadataVersion parseFormatVersion(const QJsonObject &obj, bool required = true); +void serializeFormatVersion(QJsonObject &obj, MetadataVersion version); + // FIXME: this has a different shape than the others...FIX IT!? void parseRequires(const QJsonObject &obj, RequireSet * ptr, const char * keyName = "requires"); void serializeRequires(QJsonObject & objOut, RequireSet* ptr, const char * keyName = "requires"); +MetadataVersion currentFormatVersion(); } Q_DECLARE_METATYPE(std::set); \ No newline at end of file diff --git a/api/logic/meta/Version.cpp b/api/logic/meta/Version.cpp index 55b92966..c9056547 100644 --- a/api/logic/meta/Version.cpp +++ b/api/logic/meta/Version.cpp @@ -79,10 +79,6 @@ void Meta::Version::mergeFromList(const Meta::VersionPtr& other) { m_conflicts = other->m_conflicts; } - if (m_parentUid != other->m_parentUid) - { - setParentUid(other->m_parentUid); - } if(m_volatile != other->m_volatile) { setVolatile(other->m_volatile); @@ -103,12 +99,6 @@ QString Meta::Version::localFilename() const return m_uid + '/' + m_version + ".json"; } -void Meta::Version::setParentUid(const QString& parentUid) -{ - m_parentUid = parentUid; - emit requiresChanged(); -} - void Meta::Version::setType(const QString &type) { m_type = type; diff --git a/api/logic/meta/Version.h b/api/logic/meta/Version.h index debdf20a..d284da69 100644 --- a/api/logic/meta/Version.h +++ b/api/logic/meta/Version.h @@ -50,10 +50,6 @@ public: /* con/des */ { return m_uid; } - QString parentUid() const - { - return m_parentUid; - } QString version() const { return m_version; @@ -91,7 +87,6 @@ public: /* con/des */ QString localFilename() const override; public: // for usage by format parsers only - void setParentUid(const QString &parentUid); void setType(const QString &type); void setTime(const qint64 time); void setRequires(const Meta::RequireSet &requires, const Meta::RequireSet &conflicts); @@ -110,7 +105,6 @@ private: bool m_recommended = false; QString m_name; QString m_uid; - QString m_parentUid; QString m_version; QString m_type; qint64 m_time = 0; diff --git a/api/logic/meta/VersionList.cpp b/api/logic/meta/VersionList.cpp index 4963f235..66dc9fd1 100644 --- a/api/logic/meta/VersionList.cpp +++ b/api/logic/meta/VersionList.cpp @@ -76,20 +76,17 @@ QVariant VersionList::data(const QModelIndex &index, int role) const return version->version(); case ParentVersionRole: { - auto parentUid = this->parentUid(); - if(parentUid.isEmpty()) - { - return QVariant(); - } + // FIXME: HACK: this should be generic and be replaced by something else. Anything that is a hard 'equals' dep is a 'parent uid'. auto & reqs = version->requires(); - auto iter = std::find_if(reqs.begin(), reqs.end(), [&parentUid](const Require & req) + auto iter = std::find_if(reqs.begin(), reqs.end(), [](const Require & req) { - return req.uid == parentUid; + return req.uid == "net.minecraft"; }); if (iter != reqs.end()) { return (*iter).equalsVersion; } + return QVariant(); } case TypeRole: return version->type(); @@ -196,11 +193,6 @@ void VersionList::mergeFromIndex(const VersionListPtr &other) { setName(other->m_name); } - - if(m_parentUid != other->m_parentUid) - { - setParentUid(other->m_parentUid); - } } void VersionList::merge(const VersionListPtr &other) @@ -210,11 +202,6 @@ void VersionList::merge(const VersionListPtr &other) setName(other->m_name); } - if(m_parentUid != other->m_parentUid) - { - setParentUid(other->m_parentUid); - } - // TODO: do not reset the whole model. maybe? beginResetModel(); m_versions.clear(); @@ -256,8 +243,3 @@ BaseVersionPtr VersionList::getRecommended() const } } - -void Meta::VersionList::setParentUid(const QString& parentUid) -{ - m_parentUid = parentUid; -} diff --git a/api/logic/meta/VersionList.h b/api/logic/meta/VersionList.h index c4a2b757..f880c7fd 100644 --- a/api/logic/meta/VersionList.h +++ b/api/logic/meta/VersionList.h @@ -55,10 +55,6 @@ public: QString localFilename() const override; - QString parentUid() const - { - return m_parentUid; - } QString uid() const { return m_uid; @@ -78,7 +74,6 @@ public: public: // for usage only by parsers void setName(const QString &name); - void setParentUid(const QString &parentUid); void setVersions(const QVector &versions); void merge(const VersionListPtr &other); void mergeFromIndex(const VersionListPtr &other); @@ -96,7 +91,6 @@ private: QVector m_versions; QHash m_lookup; QString m_uid; - QString m_parentUid; QString m_name; VersionPtr m_recommended; diff --git a/api/logic/minecraft/ComponentList.cpp b/api/logic/minecraft/ComponentList.cpp index dbf6ee08..3fb04255 100644 --- a/api/logic/minecraft/ComponentList.cpp +++ b/api/logic/minecraft/ComponentList.cpp @@ -450,42 +450,30 @@ bool ComponentList::migratePreComponentConfig() intendedVersion = emptyVersion; } auto file = ProfileUtils::parseJsonFile(QFileInfo(jsonFilePath), false); - bool fileChanged = false; - // if uid is missing or incorrect, fix it - if(file->uid != uid) - { - file->uid = uid; - fileChanged = true; - } + // fix uid + file->uid = uid; // if version is missing, add it from the outside. if(file->version.isEmpty()) { file->version = intendedVersion; - fileChanged = true; } // if this is a dependency (LWJGL), mark it also as volatile if(asDependency) { file->m_volatile = true; - fileChanged = true; } // insert requirements if needed if(!req.uid.isEmpty()) { file->requires.insert(req); - fileChanged = true; } // insert conflicts if needed if(!conflict.uid.isEmpty()) { file->conflicts.insert(conflict); - fileChanged = true; - } - if(fileChanged) - { - // FIXME: @QUALITY do not ignore return value - ProfileUtils::saveJsonFile(OneSixVersionFormat::versionFileToJson(file), jsonFilePath); } + // FIXME: @QUALITY do not ignore return value + ProfileUtils::saveJsonFile(OneSixVersionFormat::versionFileToJson(file), jsonFilePath); component = new Component(this, uid, file); component->m_version = intendedVersion; } @@ -538,17 +526,9 @@ bool ComponentList::migratePreComponentConfig() QFile::remove(info.absoluteFilePath()); continue; } - bool fileChanged = false; - if(file->uid != uid) - { - file->uid = uid; - fileChanged = true; - } - if(fileChanged) - { - // FIXME: @QUALITY do not ignore return value - ProfileUtils::saveJsonFile(OneSixVersionFormat::versionFileToJson(file), info.absoluteFilePath()); - } + file->uid = uid; + // FIXME: @QUALITY do not ignore return value + ProfileUtils::saveJsonFile(OneSixVersionFormat::versionFileToJson(file), info.absoluteFilePath()); auto component = new Component(this, file->uid, file); auto version = d->getOldConfigVersion(file->uid); diff --git a/api/logic/minecraft/OneSixVersionFormat.cpp b/api/logic/minecraft/OneSixVersionFormat.cpp index d91eae58..f7ab25b3 100644 --- a/api/logic/minecraft/OneSixVersionFormat.cpp +++ b/api/logic/minecraft/OneSixVersionFormat.cpp @@ -52,6 +52,15 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc QJsonObject root = doc.object(); + Meta::MetadataVersion formatVersion = Meta::parseFormatVersion(root, false); + switch(formatVersion) + { + case Meta::MetadataVersion::InitialRelease: + break; + case Meta::MetadataVersion::Invalid: + throw JSONValidationError(filename + " does not contain a recognizable version of the metadata format."); + } + if (requireOrder) { if (root.contains("order")) @@ -77,8 +86,6 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc } out->version = root.value("version").toString(); - out->dependsOnMinecraftVersion = root.value("mcVersion").toString(); - // out->filename = filename; MojangVersionFormat::readVersionProperties(root, out.get()); @@ -196,6 +203,17 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc { Meta::parseRequires(root, &out->requires); } + QString dependsOnMinecraftVersion = root.value("mcVersion").toString(); + if(!dependsOnMinecraftVersion.isEmpty()) + { + Meta::Require mcReq; + mcReq.uid = "net.minecraft"; + mcReq.equalsVersion = dependsOnMinecraftVersion; + if (out->requires.count(mcReq) == 0) + { + out->requires.insert(mcReq); + } + } if (root.contains("conflicts")) { Meta::parseRequires(root, &out->conflicts); @@ -237,7 +255,8 @@ QJsonDocument OneSixVersionFormat::versionFileToJson(const VersionFilePtr &patch writeString(root, "uid", patch->uid); writeString(root, "version", patch->version); - writeString(root, "mcVersion", patch->dependsOnMinecraftVersion); + + Meta::serializeFormatVersion(root, Meta::MetadataVersion::InitialRelease); MojangVersionFormat::writeVersionProperties(patch.get(), root); diff --git a/api/logic/minecraft/VersionFile.h b/api/logic/minecraft/VersionFile.h index c032f7ea..5aea7a7a 100644 --- a/api/logic/minecraft/VersionFile.h +++ b/api/logic/minecraft/VersionFile.h @@ -18,7 +18,7 @@ class LaunchProfile; struct MojangDownloadInfo; struct MojangAssetIndexInfo; -typedef std::shared_ptr VersionFilePtr; +using VersionFilePtr = std::shared_ptr; class VersionFile : public ProblemContainer { friend class MojangVersionFormat; diff --git a/application/pages/VersionPage.cpp b/application/pages/VersionPage.cpp index 8673e4bc..c86e76d5 100644 --- a/application/pages/VersionPage.cpp +++ b/application/pages/VersionPage.cpp @@ -402,44 +402,6 @@ void VersionPage::on_forgeBtn_clicked() } } -// TODO: use something like this... except the final decision of what to show has to be deferred until the lists are known -/* -void VersionPage::on_liteloaderBtn_clicked() -{ - QString uid = "com.mumfrey.liteloader"; - auto vlist = ENV.metadataIndex()->get(uid); - if(!vlist) - { - return; - } - VersionSelectDialog vselect(vlist.get(), tr("Select %1 version").arg(vlist->name()), this); - auto parentUid = vlist->parentUid(); - if(!parentUid.isEmpty()) - { - auto parentvlist = ENV.metadataIndex()->get(parentUid); - vselect.setExactFilter(BaseVersionList::ParentVersionRole, m_profile->getComponentVersion(parentUid)); - vselect.setEmptyString( - tr("No %1 versions are currently available for %2 %3") - .arg(vlist->name()) - .arg(parentvlist->name()) - .arg(m_profile->getComponentVersion(parentUid))); - } - else - { - vselect.setEmptyString(tr("No %1 versions are currently available")); - } - vselect.setEmptyErrorString(tr("Couldn't load or download the %1 version lists!").arg(vlist->name())); - if (vselect.exec() && vselect.selectedVersion()) - { - auto vsn = vselect.selectedVersion(); - m_profile->setComponentVersion(uid, vsn->descriptor()); - m_profile->resolve(); - preselect(m_profile->rowCount(QModelIndex())-1); - m_container->refreshContainer(); - } -} -*/ - void VersionPage::on_liteloaderBtn_clicked() { auto vlist = ENV.metadataIndex()->get("com.mumfrey.liteloader");