fix segfaults consistently set component problems

Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
This commit is contained in:
Rachel Powers 2024-06-27 17:28:09 -07:00
parent a85d6cb1f2
commit 4ed92a95c2
No known key found for this signature in database
GPG Key ID: E10E321EB160949B
3 changed files with 131 additions and 74 deletions

View File

@ -45,6 +45,7 @@
#include "OneSixVersionFormat.h" #include "OneSixVersionFormat.h"
#include "VersionFile.h" #include "VersionFile.h"
#include "meta/Version.h" #include "meta/Version.h"
#include "minecraft/Component.h"
#include "minecraft/PackProfile.h" #include "minecraft/PackProfile.h"
#include <assert.h> #include <assert.h>
@ -438,14 +439,14 @@ void Component::setUpdateAction(UpdateAction action)
m_updateAction = action; m_updateAction = action;
} }
std::optional<UpdateAction> Component::getUpdateAction() UpdateAction Component::getUpdateAction()
{ {
return m_updateAction; return m_updateAction;
} }
void Component::clearUpdateAction() void Component::clearUpdateAction()
{ {
m_updateAction.reset(); m_updateAction = UpdateAction{ UpdateActionNone{} };
} }
QDebug operator<<(QDebug d, const Component& comp) QDebug operator<<(QDebug d, const Component& comp)

View File

@ -5,6 +5,7 @@
#include <QList> #include <QList>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <variant>
#include "ProblemProvider.h" #include "ProblemProvider.h"
#include "QObjectPtr.h" #include "QObjectPtr.h"
#include "meta/JsonFormat.h" #include "meta/JsonFormat.h"
@ -17,7 +18,7 @@ class VersionList;
} // namespace Meta } // namespace Meta
class VersionFile; class VersionFile;
struct UpdateActionChangeVerison { struct UpdateActionChangeVersion {
/// version to change to /// version to change to
QString targetVersion; QString targetVersion;
}; };
@ -34,8 +35,13 @@ struct UpdateActionImportantChanged {
QString oldVersion; QString oldVersion;
}; };
using UpdateAction = using UpdateActionNone = std::monostate;
std::variant<UpdateActionChangeVerison, UpdateActionLatestRecommendedCompatable, UpdateActionRemove, UpdateActionImportantChanged>;
using UpdateAction = std::variant<UpdateActionNone,
UpdateActionChangeVersion,
UpdateActionLatestRecommendedCompatable,
UpdateActionRemove,
UpdateActionImportantChanged>;
class Component : public QObject, public ProblemProvider { class Component : public QObject, public ProblemProvider {
Q_OBJECT Q_OBJECT
@ -92,8 +98,7 @@ class Component : public QObject, public ProblemProvider {
void setUpdateAction(UpdateAction action); void setUpdateAction(UpdateAction action);
void clearUpdateAction(); void clearUpdateAction();
std::optional<UpdateAction> getUpdateAction(); UpdateAction getUpdateAction();
std::optional<UpdateAction> takeUpdateAction();
signals: signals:
void dataChanged(); void dataChanged();
@ -136,7 +141,7 @@ class Component : public QObject, public ProblemProvider {
private: private:
QList<PatchProblem> m_componentProblems; QList<PatchProblem> m_componentProblems;
ProblemSeverity m_componentProblemSeverity = ProblemSeverity::None; ProblemSeverity m_componentProblemSeverity = ProblemSeverity::None;
std::optional<UpdateAction> m_updateAction = std::nullopt; UpdateAction m_updateAction = UpdateAction{ UpdateActionNone{} };
}; };
using ComponentPtr = shared_qobject_ptr<Component>; using ComponentPtr = shared_qobject_ptr<Component>;

View File

@ -153,6 +153,7 @@ void ComponentUpdateTask::loadComponents()
Task::Ptr loadTask; Task::Ptr loadTask;
LoadResult singleResult; LoadResult singleResult;
RemoteLoadStatus::Type loadType; RemoteLoadStatus::Type loadType;
component->resetComponentProblems();
// FIXME: to do this right, we need to load the lists and decide on which versions to use during dependency resolution. For now, // FIXME: to do this right, we need to load the lists and decide on which versions to use during dependency resolution. For now,
// ignore all that... // ignore all that...
#if 0 #if 0
@ -445,6 +446,7 @@ void ComponentUpdateTask::resolveDependencies(bool checkOnly)
allRequires.clear(); allRequires.clear();
toRemove.clear(); toRemove.clear();
if (!gatherRequirementsFromComponents(components, allRequires)) { if (!gatherRequirementsFromComponents(components, allRequires)) {
finalizeComponents();
emitFailed(tr("Conflicting requirements detected during dependency checking!")); emitFailed(tr("Conflicting requirements detected during dependency checking!"));
return; return;
} }
@ -461,10 +463,12 @@ void ComponentUpdateTask::resolveDependencies(bool checkOnly)
RequireExSet toChange; RequireExSet toChange;
bool succeeded = getTrivialComponentChanges(componentIndex, allRequires, toAdd, toChange); bool succeeded = getTrivialComponentChanges(componentIndex, allRequires, toAdd, toChange);
if (!succeeded) { if (!succeeded) {
finalizeComponents();
emitFailed(tr("Instance has conflicting dependencies.")); emitFailed(tr("Instance has conflicting dependencies."));
return; return;
} }
if (checkOnly) { if (checkOnly) {
finalizeComponents();
if (toAdd.size() || toChange.size()) { if (toAdd.size() || toChange.size()) {
emitFailed(tr("Instance has unresolved dependencies while loading/checking for launch.")); emitFailed(tr("Instance has unresolved dependencies while loading/checking for launch."));
} else { } else {
@ -542,77 +546,115 @@ overload(Ts...) -> overload<Ts...>;
void ComponentUpdateTask::performUpdateActions() void ComponentUpdateTask::performUpdateActions()
{ {
auto& components = d->m_profile->d->components; auto& instance = d->m_profile->d->m_instance;
bool addedActions; bool addedActions;
QStringList toRemove;
do { do {
addedActions = false; addedActions = false;
toRemove.clear();
auto& components = d->m_profile->d->components;
auto& componentIndex = d->m_profile->d->componentIndex;
for (auto component : components) { for (auto component : components) {
if (auto action = component->getUpdateAction()) { if (!component) {
auto visitor = overload{ continue;
[&component](const UpdateActionChangeVerison& cv) { }
component->setVersion(cv.targetVersion); auto action = component->getUpdateAction();
component->waitLoadMeta(); auto visitor =
}, overload{ [](const UpdateActionNone&) {
[&component](const UpdateActionLatestRecommendedCompatable lrc) { // noop
auto versionList = APPLICATION->metadataIndex()->get(component->getID()); },
versionList->waitToLoad(); [&component, &instance](const UpdateActionChangeVersion& cv) {
if (versionList) { qCDebug(instanceProfileResolveC) << instance->name() << "|"
auto recommended = versionList->getRecommendedForParent(lrc.parentUid, lrc.version); << "UpdateActionChangeVersion" << component->getID() << ":"
if (recommended) { << component->getVersion() << "change to" << cv.targetVersion;
component->setVersion(recommended->version()); component->setVersion(cv.targetVersion);
component->waitLoadMeta(); component->waitLoadMeta();
return; },
} [&component, &instance](const UpdateActionLatestRecommendedCompatable lrc) {
qCDebug(instanceProfileResolveC)
<< instance->name() << "|"
<< "UpdateActionLatestRecommendedCompatable" << component->getID() << ":" << component->getVersion()
<< "updating to latest recommend or compatible with" << lrc.parentUid << lrc.version;
auto versionList = APPLICATION->metadataIndex()->get(component->getID());
versionList->waitToLoad();
if (versionList) {
auto recommended = versionList->getRecommendedForParent(lrc.parentUid, lrc.version);
if (recommended) {
component->setVersion(recommended->version());
component->waitLoadMeta();
return;
}
auto latest = versionList->getLatestForParent(lrc.parentUid, lrc.version); auto latest = versionList->getLatestForParent(lrc.parentUid, lrc.version);
if (latest) { if (latest) {
component->setVersion(latest->version()); component->setVersion(latest->version());
component->waitLoadMeta(); component->waitLoadMeta();
} else { } else {
component->addComponentProblem(ProblemSeverity::Error, component->addComponentProblem(ProblemSeverity::Error,
QObject::tr("No compatible version of %1 found for %2 %3") QObject::tr("No compatible version of %1 found for %2 %3")
.arg(component->getName(), lrc.parentName, lrc.version)); .arg(component->getName(), lrc.parentName, lrc.version));
} }
} else { } else {
component->addComponentProblem(ProblemSeverity::Error, component->addComponentProblem(
QObject::tr("No version list in metadata index for %1").arg(component->getID())); ProblemSeverity::Error,
} QObject::tr("No version list in metadata index for %1").arg(component->getID()));
}, }
[this, &component](const UpdateActionRemove&) { d->m_profile->remove(component->getID()); }, },
[this, &component, &addedActions](const UpdateActionImportantChanged&) { [&component, &instance, &toRemove](const UpdateActionRemove&) {
auto linked = collectTreeLinked(component->getID()); qCDebug(instanceProfileResolveC)
for (auto comp : linked) { << instance->name() << "|"
if (comp->isCustom()) { << "UpdateActionRemove" << component->getID() << ":" << component->getVersion() << "removing";
continue; toRemove.append(component->getID());
} },
auto compUid = comp->getID(); [this, &component, &instance, &addedActions, &componentIndex](const UpdateActionImportantChanged& ic) {
auto parentReq = std::find_if(component->m_cachedRequires.begin(), component->m_cachedRequires.end(), qCDebug(instanceProfileResolveC)
[compUid](const Meta::Require& req) { return req.uid == compUid; }); << instance->name() << "|"
if (parentReq != component->m_cachedRequires.end()) { << "UpdateImportantChanged" << component->getID() << ":" << component->getVersion() << "was changed from"
auto newVersion = parentReq->equalsVersion.isEmpty() ? parentReq->suggests : parentReq->equalsVersion; << ic.oldVersion << "updating linked components";
if (!newVersion.isEmpty()) { auto oldVersion = APPLICATION->metadataIndex()->getLoadedVersion(component->getID(), ic.oldVersion);
comp->setUpdateAction(UpdateAction{ UpdateActionChangeVerison{ newVersion } }); for (auto oldReq : oldVersion->requiredSet()) {
} else { auto currentlyRequired = component->m_cachedRequires.find(oldReq);
comp->setUpdateAction(UpdateAction{ UpdateActionLatestRecommendedCompatable{ if (currentlyRequired == component->m_cachedRequires.cend()) {
component->getID(), auto oldReqComp = componentIndex.find(oldReq.uid);
component->getName(), if (oldReqComp != componentIndex.cend()) {
component->getVersion(), (*oldReqComp)->setUpdateAction(UpdateAction{ UpdateActionRemove{} });
} }); addedActions = true;
} }
} else { }
comp->setUpdateAction(UpdateAction{ UpdateActionLatestRecommendedCompatable{ }
component->getID(), auto linked = collectTreeLinked(component->getID());
component->getName(), for (auto comp : linked) {
component->getVersion(), if (comp->isCustom()) {
} }); continue;
} }
addedActions = true; auto compUid = comp->getID();
} auto parentReq = std::find_if(component->m_cachedRequires.begin(), component->m_cachedRequires.end(),
} [compUid](const Meta::Require& req) { return req.uid == compUid; });
}; if (parentReq != component->m_cachedRequires.end()) {
std::visit(visitor, *action); auto newVersion = parentReq->equalsVersion.isEmpty() ? parentReq->suggests : parentReq->equalsVersion;
component->clearUpdateAction(); if (!newVersion.isEmpty()) {
comp->setUpdateAction(UpdateAction{ UpdateActionChangeVersion{ newVersion } });
} else {
comp->setUpdateAction(UpdateAction{ UpdateActionLatestRecommendedCompatable{
component->getID(),
component->getName(),
component->getVersion(),
} });
}
} else {
comp->setUpdateAction(UpdateAction{ UpdateActionLatestRecommendedCompatable{
component->getID(),
component->getName(),
component->getVersion(),
} });
}
addedActions = true;
}
} };
std::visit(visitor, action);
component->clearUpdateAction();
for (auto uid : toRemove) {
d->m_profile->remove(uid);
} }
} }
} while (addedActions); } while (addedActions);
@ -637,6 +679,15 @@ void ComponentUpdateTask::finalizeComponents()
reqComp->getProblemSeverity(), reqComp->getProblemSeverity(),
QObject::tr("%1, a dependency of this component, has reported issues").arg(reqComp->getName())); QObject::tr("%1, a dependency of this component, has reported issues").arg(reqComp->getName()));
} }
if (!req.equalsVersion.isEmpty() && req.equalsVersion != reqComp->getVersion()) {
component->addComponentProblem(ProblemSeverity::Error,
QObject::tr("%1, a dependency of this component, is not the required version %2")
.arg(reqComp->getName(), req.equalsVersion));
} else if (!req.suggests.isEmpty() && req.suggests != reqComp->getVersion()) {
component->addComponentProblem(ProblemSeverity::Warning,
QObject::tr("%1, a dependency of this component, is not the suggested version %2")
.arg(reqComp->getName(), req.suggests));
}
} }
} }
} }