NOISSUE add versioning to component metadata format and use it

This commit is contained in:
Petr Mrázek 2017-12-29 00:37:14 +01:00
parent 50ca6cbb4d
commit 719f3e863a
10 changed files with 94 additions and 136 deletions

View File

@ -28,6 +28,11 @@ using namespace Json;
namespace Meta namespace Meta
{ {
MetadataVersion currentFormatVersion()
{
return MetadataVersion::InitialRelease;
}
// Index // Index
static std::shared_ptr<Index> parseIndexInternal(const QJsonObject &obj) static std::shared_ptr<Index> parseIndexInternal(const QJsonObject &obj)
{ {
@ -49,7 +54,6 @@ static VersionPtr parseCommonVersion(const QString &uid, const QJsonObject &obj)
VersionPtr version = std::make_shared<Version>(uid, requireString(obj, "version")); VersionPtr version = std::make_shared<Version>(uid, requireString(obj, "version"));
version->setTime(QDateTime::fromString(requireString(obj, "releaseTime"), Qt::ISODate).toMSecsSinceEpoch() / 1000); version->setTime(QDateTime::fromString(requireString(obj, "releaseTime"), Qt::ISODate).toMSecsSinceEpoch() / 1000);
version->setType(ensureString(obj, "type", QString())); version->setType(ensureString(obj, "type", QString()));
version->setParentUid(ensureString(obj, "parentUid", QString()));
version->setRecommended(ensureBoolean(obj, QString("recommended"), false)); version->setRecommended(ensureBoolean(obj, QString("recommended"), false));
version->setVolatile(ensureBoolean(obj, QString("volatile"), false)); version->setVolatile(ensureBoolean(obj, QString("volatile"), false));
RequireSet requires, conflicts; RequireSet requires, conflicts;
@ -86,56 +90,79 @@ static std::shared_ptr<VersionList> parseVersionListInternal(const QJsonObject &
VersionListPtr list = std::make_shared<VersionList>(uid); VersionListPtr list = std::make_shared<VersionList>(uid);
list->setName(ensureString(obj, "name", QString())); list->setName(ensureString(obj, "name", QString()));
list->setParentUid(ensureString(obj, "parentUid", QString()));
list->setVersions(versions); list->setVersions(versions);
return list; return list;
} }
static int formatVersion(const QJsonObject &obj) MetadataVersion parseFormatVersion(const QJsonObject &obj, bool required)
{ {
if (!obj.contains("formatVersion")) { if (!obj.contains("formatVersion"))
throw ParseException(QObject::tr("Missing required field: 'formatVersion'")); {
if(required)
{
return MetadataVersion::Invalid;
}
return MetadataVersion::InitialRelease;
} }
if (!obj.value("formatVersion").isDouble()) { if (!obj.value("formatVersion").isDouble())
throw ParseException(QObject::tr("Required field has invalid type: 'formatVersion'")); {
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) void parseIndex(const QJsonObject &obj, Index *ptr)
{ {
const int version = formatVersion(obj); const MetadataVersion version = parseFormatVersion(obj);
switch (version) { switch (version)
case 0: {
case MetadataVersion::InitialRelease:
ptr->merge(parseIndexInternal(obj)); ptr->merge(parseIndexInternal(obj));
break; break;
default: case MetadataVersion::Invalid:
throw ParseException(QObject::tr("Unknown formatVersion: %1").arg(version)); throw ParseException(QObject::tr("Unknown format version!"));
} }
} }
void parseVersionList(const QJsonObject &obj, VersionList *ptr) void parseVersionList(const QJsonObject &obj, VersionList *ptr)
{ {
const int version = formatVersion(obj); const MetadataVersion version = parseFormatVersion(obj);
switch (version) { switch (version)
case 0: {
case MetadataVersion::InitialRelease:
ptr->merge(parseVersionListInternal(obj)); ptr->merge(parseVersionListInternal(obj));
break; break;
default: case MetadataVersion::Invalid:
throw ParseException(QObject::tr("Unknown formatVersion: %1").arg(version)); throw ParseException(QObject::tr("Unknown format version!"));
} }
} }
void parseVersion(const QJsonObject &obj, Version *ptr) void parseVersion(const QJsonObject &obj, Version *ptr)
{ {
const int version = formatVersion(obj); const MetadataVersion version = parseFormatVersion(obj);
switch (version) { switch (version)
case 0: {
case MetadataVersion::InitialRelease:
ptr->merge(parseVersionInternal(obj)); ptr->merge(parseVersionInternal(obj));
break; break;
default: case MetadataVersion::Invalid:
throw ParseException(QObject::tr("Unknown formatVersion: %1").arg(version)); throw ParseException(QObject::tr("Unknown format version!"));
} }
} }

View File

@ -28,6 +28,12 @@ class Index;
class Version; class Version;
class VersionList; class VersionList;
enum class MetadataVersion
{
Invalid = -1,
InitialRelease = 0
};
class ParseException : public Exception class ParseException : public Exception
{ {
public: public:
@ -65,9 +71,13 @@ void parseIndex(const QJsonObject &obj, Index *ptr);
void parseVersion(const QJsonObject &obj, Version *ptr); void parseVersion(const QJsonObject &obj, Version *ptr);
void parseVersionList(const QJsonObject &obj, VersionList *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!? // FIXME: this has a different shape than the others...FIX IT!?
void parseRequires(const QJsonObject &obj, RequireSet * ptr, const char * keyName = "requires"); void parseRequires(const QJsonObject &obj, RequireSet * ptr, const char * keyName = "requires");
void serializeRequires(QJsonObject & objOut, RequireSet* ptr, const char * keyName = "requires"); void serializeRequires(QJsonObject & objOut, RequireSet* ptr, const char * keyName = "requires");
MetadataVersion currentFormatVersion();
} }
Q_DECLARE_METATYPE(std::set<Meta::Require>); Q_DECLARE_METATYPE(std::set<Meta::Require>);

View File

@ -79,10 +79,6 @@ void Meta::Version::mergeFromList(const Meta::VersionPtr& other)
{ {
m_conflicts = other->m_conflicts; m_conflicts = other->m_conflicts;
} }
if (m_parentUid != other->m_parentUid)
{
setParentUid(other->m_parentUid);
}
if(m_volatile != other->m_volatile) if(m_volatile != other->m_volatile)
{ {
setVolatile(other->m_volatile); setVolatile(other->m_volatile);
@ -103,12 +99,6 @@ QString Meta::Version::localFilename() const
return m_uid + '/' + m_version + ".json"; 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) void Meta::Version::setType(const QString &type)
{ {
m_type = type; m_type = type;

View File

@ -50,10 +50,6 @@ public: /* con/des */
{ {
return m_uid; return m_uid;
} }
QString parentUid() const
{
return m_parentUid;
}
QString version() const QString version() const
{ {
return m_version; return m_version;
@ -91,7 +87,6 @@ public: /* con/des */
QString localFilename() const override; QString localFilename() const override;
public: // for usage by format parsers only public: // for usage by format parsers only
void setParentUid(const QString &parentUid);
void setType(const QString &type); void setType(const QString &type);
void setTime(const qint64 time); void setTime(const qint64 time);
void setRequires(const Meta::RequireSet &requires, const Meta::RequireSet &conflicts); void setRequires(const Meta::RequireSet &requires, const Meta::RequireSet &conflicts);
@ -110,7 +105,6 @@ private:
bool m_recommended = false; bool m_recommended = false;
QString m_name; QString m_name;
QString m_uid; QString m_uid;
QString m_parentUid;
QString m_version; QString m_version;
QString m_type; QString m_type;
qint64 m_time = 0; qint64 m_time = 0;

View File

@ -76,20 +76,17 @@ QVariant VersionList::data(const QModelIndex &index, int role) const
return version->version(); return version->version();
case ParentVersionRole: case ParentVersionRole:
{ {
auto parentUid = this->parentUid(); // FIXME: HACK: this should be generic and be replaced by something else. Anything that is a hard 'equals' dep is a 'parent uid'.
if(parentUid.isEmpty())
{
return QVariant();
}
auto & reqs = version->requires(); 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()) if (iter != reqs.end())
{ {
return (*iter).equalsVersion; return (*iter).equalsVersion;
} }
return QVariant();
} }
case TypeRole: return version->type(); case TypeRole: return version->type();
@ -196,11 +193,6 @@ void VersionList::mergeFromIndex(const VersionListPtr &other)
{ {
setName(other->m_name); setName(other->m_name);
} }
if(m_parentUid != other->m_parentUid)
{
setParentUid(other->m_parentUid);
}
} }
void VersionList::merge(const VersionListPtr &other) void VersionList::merge(const VersionListPtr &other)
@ -210,11 +202,6 @@ void VersionList::merge(const VersionListPtr &other)
setName(other->m_name); setName(other->m_name);
} }
if(m_parentUid != other->m_parentUid)
{
setParentUid(other->m_parentUid);
}
// TODO: do not reset the whole model. maybe? // TODO: do not reset the whole model. maybe?
beginResetModel(); beginResetModel();
m_versions.clear(); m_versions.clear();
@ -256,8 +243,3 @@ BaseVersionPtr VersionList::getRecommended() const
} }
} }
void Meta::VersionList::setParentUid(const QString& parentUid)
{
m_parentUid = parentUid;
}

View File

@ -55,10 +55,6 @@ public:
QString localFilename() const override; QString localFilename() const override;
QString parentUid() const
{
return m_parentUid;
}
QString uid() const QString uid() const
{ {
return m_uid; return m_uid;
@ -78,7 +74,6 @@ public:
public: // for usage only by parsers public: // for usage only by parsers
void setName(const QString &name); void setName(const QString &name);
void setParentUid(const QString &parentUid);
void setVersions(const QVector<VersionPtr> &versions); void setVersions(const QVector<VersionPtr> &versions);
void merge(const VersionListPtr &other); void merge(const VersionListPtr &other);
void mergeFromIndex(const VersionListPtr &other); void mergeFromIndex(const VersionListPtr &other);
@ -96,7 +91,6 @@ private:
QVector<VersionPtr> m_versions; QVector<VersionPtr> m_versions;
QHash<QString, VersionPtr> m_lookup; QHash<QString, VersionPtr> m_lookup;
QString m_uid; QString m_uid;
QString m_parentUid;
QString m_name; QString m_name;
VersionPtr m_recommended; VersionPtr m_recommended;

View File

@ -450,42 +450,30 @@ bool ComponentList::migratePreComponentConfig()
intendedVersion = emptyVersion; intendedVersion = emptyVersion;
} }
auto file = ProfileUtils::parseJsonFile(QFileInfo(jsonFilePath), false); auto file = ProfileUtils::parseJsonFile(QFileInfo(jsonFilePath), false);
bool fileChanged = false; // fix uid
// if uid is missing or incorrect, fix it file->uid = uid;
if(file->uid != uid)
{
file->uid = uid;
fileChanged = true;
}
// if version is missing, add it from the outside. // if version is missing, add it from the outside.
if(file->version.isEmpty()) if(file->version.isEmpty())
{ {
file->version = intendedVersion; file->version = intendedVersion;
fileChanged = true;
} }
// if this is a dependency (LWJGL), mark it also as volatile // if this is a dependency (LWJGL), mark it also as volatile
if(asDependency) if(asDependency)
{ {
file->m_volatile = true; file->m_volatile = true;
fileChanged = true;
} }
// insert requirements if needed // insert requirements if needed
if(!req.uid.isEmpty()) if(!req.uid.isEmpty())
{ {
file->requires.insert(req); file->requires.insert(req);
fileChanged = true;
} }
// insert conflicts if needed // insert conflicts if needed
if(!conflict.uid.isEmpty()) if(!conflict.uid.isEmpty())
{ {
file->conflicts.insert(conflict); 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 = new Component(this, uid, file);
component->m_version = intendedVersion; component->m_version = intendedVersion;
} }
@ -538,17 +526,9 @@ bool ComponentList::migratePreComponentConfig()
QFile::remove(info.absoluteFilePath()); QFile::remove(info.absoluteFilePath());
continue; continue;
} }
bool fileChanged = false; file->uid = uid;
if(file->uid != uid) // FIXME: @QUALITY do not ignore return value
{ ProfileUtils::saveJsonFile(OneSixVersionFormat::versionFileToJson(file), info.absoluteFilePath());
file->uid = uid;
fileChanged = true;
}
if(fileChanged)
{
// FIXME: @QUALITY do not ignore return value
ProfileUtils::saveJsonFile(OneSixVersionFormat::versionFileToJson(file), info.absoluteFilePath());
}
auto component = new Component(this, file->uid, file); auto component = new Component(this, file->uid, file);
auto version = d->getOldConfigVersion(file->uid); auto version = d->getOldConfigVersion(file->uid);

View File

@ -52,6 +52,15 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc
QJsonObject root = doc.object(); 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 (requireOrder)
{ {
if (root.contains("order")) if (root.contains("order"))
@ -77,8 +86,6 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc
} }
out->version = root.value("version").toString(); out->version = root.value("version").toString();
out->dependsOnMinecraftVersion = root.value("mcVersion").toString();
// out->filename = filename;
MojangVersionFormat::readVersionProperties(root, out.get()); MojangVersionFormat::readVersionProperties(root, out.get());
@ -196,6 +203,17 @@ VersionFilePtr OneSixVersionFormat::versionFileFromJson(const QJsonDocument &doc
{ {
Meta::parseRequires(root, &out->requires); 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")) if (root.contains("conflicts"))
{ {
Meta::parseRequires(root, &out->conflicts); Meta::parseRequires(root, &out->conflicts);
@ -237,7 +255,8 @@ QJsonDocument OneSixVersionFormat::versionFileToJson(const VersionFilePtr &patch
writeString(root, "uid", patch->uid); writeString(root, "uid", patch->uid);
writeString(root, "version", patch->version); writeString(root, "version", patch->version);
writeString(root, "mcVersion", patch->dependsOnMinecraftVersion);
Meta::serializeFormatVersion(root, Meta::MetadataVersion::InitialRelease);
MojangVersionFormat::writeVersionProperties(patch.get(), root); MojangVersionFormat::writeVersionProperties(patch.get(), root);

View File

@ -18,7 +18,7 @@ class LaunchProfile;
struct MojangDownloadInfo; struct MojangDownloadInfo;
struct MojangAssetIndexInfo; struct MojangAssetIndexInfo;
typedef std::shared_ptr<VersionFile> VersionFilePtr; using VersionFilePtr = std::shared_ptr<VersionFile>;
class VersionFile : public ProblemContainer class VersionFile : public ProblemContainer
{ {
friend class MojangVersionFormat; friend class MojangVersionFormat;

View File

@ -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() void VersionPage::on_liteloaderBtn_clicked()
{ {
auto vlist = ENV.metadataIndex()->get("com.mumfrey.liteloader"); auto vlist = ENV.metadataIndex()->get("com.mumfrey.liteloader");