Skip to content

Commit

Permalink
BreaksAll errors
Browse files Browse the repository at this point in the history
  • Loading branch information
OroArmor committed Aug 15, 2024
1 parent 238bff6 commit b93cf5c
Showing 1 changed file with 168 additions and 58 deletions.
226 changes: 168 additions & 58 deletions src/main/java/org/quiltmc/loader/impl/plugin/SolverErrorHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import org.quiltmc.loader.impl.plugin.quilt.MandatoryModIdDefinition;
import org.quiltmc.loader.impl.plugin.quilt.OptionalModIdDefinition;
import org.quiltmc.loader.impl.plugin.quilt.ProvidedModOption;
import org.quiltmc.loader.impl.plugin.quilt.QuiltRuleBreak;
import org.quiltmc.loader.impl.plugin.quilt.QuiltRuleBreakAll;
import org.quiltmc.loader.impl.plugin.quilt.QuiltRuleBreakOnly;
import org.quiltmc.loader.impl.plugin.quilt.QuiltRuleDep;
Expand Down Expand Up @@ -208,26 +209,16 @@ boolean reportNewError(Graph graph) {
if (link instanceof Breaks) {
Breaks breaks = ((Breaks) link);
ModLoadOption from = (ModLoadOption) option;
Set<ModLoadOption> allBreakingOptions = new LinkedHashSet<>();
allBreakingOptions.addAll(breaks.rule.getConflictingOptions());
this.addError(new BreakageError(graph, breaks.rule.publicDep, from, allBreakingOptions, breaks.rule.unless));
this.addError(new BreakageError(graph, from, breaks.rule));
added = true;
} else if (link instanceof BreaksAll) {
}
else if (link instanceof BreaksAll) {
BreaksAll breaksAll = ((BreaksAll) link);
ModLoadOption from = (ModLoadOption) option;
Set<ModLoadOption> allBreakingOptions = new LinkedHashSet<>();
for (QuiltRuleBreakOnly only : breaksAll.rule.options) {
allBreakingOptions.addAll(only.getConflictingOptions());
}

for (ModDependency.Only only : breaksAll.rule.publicDep) {
ModDependencyIdentifier modOn = only.id();
VersionRange versionsOn = only.versionRange();
String reason = only.reason();
// TODO: BreakageAll?
// this.addError(new BreakageError(modOn, versionsOn, from, allBreakingOptions, reason));
}
} else if (link instanceof Missing) {
this.addError(new BreaksAllError(graph, from, breaksAll.rule));
added = true;
}
else if (link instanceof Missing) {
Missing missing = ((Missing) link);
ModLoadOption from = (ModLoadOption) option;
this.addError(new MissingDependencyError(graph, missing.missing, from, new LinkedHashSet<>(missing.rule.getValidOptions()), new LinkedHashSet<>(missing.rule.getWrongOptions()), missing.rule.unless));
Expand Down Expand Up @@ -345,11 +336,9 @@ public void clean() {
boolean modified = false;
do {
modified = false;
// Set<LoadOption> allChildren = new HashSet<>(parents.values());

Set<LoadOption> noLinks = this.parents.values()
.stream()
// .filter(option -> !isMandatory(this, option)) // Redundant?
.filter(option -> this.edgesTo(option).isEmpty())
.collect(Collectors.toCollection(HashSet::new));

Expand Down Expand Up @@ -845,15 +834,27 @@ protected String getModReportLine(QuiltPluginManagerImpl manager, ModLoadOption
return line.append(" mod '").append(option.id()).append("' version '").append(option.version()).append("': ").append(path).toString();
}

protected void addVersionString(ModDependency.Only unless, StringBuilder report, boolean breaks) {
if (VersionRange.ANY.equals(unless.versionRange())) {
if (breaks) {
report.append(" all versions of ");
protected void addVersionString(ModDependency.Only only, StringBuilder report, boolean breaks, boolean start) {
if (start) {
if (VersionRange.ANY.equals(only.versionRange())) {
if (breaks) {
report.append("All versions of ");
} else {
report.append("Any version of ");
}
} else {
report.append(" any version of ");
report.append("A version ").append(only.versionRange()).append(" of ");
}
} else {
report.append(" a version ").append(unless.versionRange()).append(" of ");
if (VersionRange.ANY.equals(only.versionRange())) {
if (breaks) {
report.append(" all versions of ");
} else {
report.append(" any version of ");
}
} else {
report.append(" a version ").append(only.versionRange()).append(" of ");
}
}
}

Expand All @@ -866,7 +867,7 @@ protected String addUnlessClause(ModDependency.Only dep, String rootModName, Set
if (unlessRule.getNodesTo().isEmpty()) {
report.append("However, if");

addVersionString(unless, report, false);
addVersionString(unless, report, false, false);

report.append(unless.id()).append(" is present, ").append(rootModName).append(" do");
if (from.size() == 1) {
Expand All @@ -880,10 +881,10 @@ protected String addUnlessClause(ModDependency.Only dep, String rootModName, Set
}

report.append(dep.id()).append(".");
}else {
} else {
report.append("Normally,");

addVersionString(unless, report, false);
addVersionString(unless, report, false, false);

report.append("of mod ").append(unless.id()).append(" overrides this ");
if (breaks) {
Expand Down Expand Up @@ -929,11 +930,20 @@ static class UnhandledError extends SolverError {

public UnhandledError(Graph graph, Collection<Rule> rules) {
super(graph);
this.rules = rules;
this.rules = new LinkedHashSet<>(rules);
}

@Override
boolean mergeInto(SolverError into) {
if (into instanceof UnhandledError) {
UnhandledError depDst = (UnhandledError) into;
if (depDst.rules.containsAll(rules)) { // If the other error has all the same rules as us, we are just a subset
return true;
} else if (rules.containsAll(depDst.rules)) { // We have the same but more rules than the current error, add ours to it
depDst.rules.addAll(rules);
return true;
}
}
return false;
}

Expand Down Expand Up @@ -1030,7 +1040,7 @@ void report(QuiltPluginManagerImpl manager) {

StringBuilder report = new StringBuilder(rootModName);
report.append(" requires");
addVersionString(dep, report, false);
addVersionString(dep, report, false, false);
report.append(dep.id());// TODO
if (!allValidOptions.isEmpty()) {
report.append(", which is unable to load due to another error!");
Expand Down Expand Up @@ -1072,28 +1082,20 @@ void report(QuiltPluginManagerImpl manager) {
}

static class BreakageError extends SolverError {
// final ModDependencyIdentifier modOn;
// final VersionRange versionsOn;
final Set<ModLoadOption> from = new LinkedHashSet<>();
final Set<ModLoadOption> allBreakingOptions;
// final String reason;
final ModDependency.Only dep;
final QuiltRuleDep unlessDep;
final QuiltRuleBreakOnly breakage;

BreakageError(Graph graph, ModDependency.Only dep, ModLoadOption from, Set<ModLoadOption> allBreakingOptions, QuiltRuleDep unlessDep) {
BreakageError(Graph graph, ModLoadOption from, QuiltRuleBreakOnly breakage) {
super(graph);
this.dep = dep;
// this.versionsOn = versionsOn;
this.from.add(from);
this.allBreakingOptions = allBreakingOptions;
this.unlessDep = unlessDep;
this.breakage = breakage;
}

@Override
boolean mergeInto(SolverError into) {
if (into instanceof BreakageError) {
BreakageError depDst = (BreakageError) into;
if (!dep.id().equals(depDst.dep.id()) || !dep.versionRange().equals(depDst.dep.versionRange())) {
if (!breakage.publicDep.id().equals(depDst.breakage.publicDep.id()) || !breakage.publicDep.versionRange().equals(depDst.breakage.publicDep.versionRange())) {
return false;
}
depDst.from.addAll(from);
Expand All @@ -1116,45 +1118,45 @@ void report(QuiltPluginManagerImpl manager) {
String rootModName = from.size() > 1 ? from.size() + " mods [" + from.stream().map(ModLoadOption::metadata).map(ModMetadataExt::name).collect(Collectors.joining(", ")) + "]" : mandatoryMod.metadata().name();

QuiltLoaderText first = VersionRangeDescriber.describe(
rootModName, dep.versionRange(), dep.id().id(), false, transitive
rootModName, breakage.publicDep.versionRange(), breakage.publicDep.id().id(), false, transitive
);

Object[] secondData = new Object[allBreakingOptions.size() == 1 ? 1 : 0];
Object[] secondData = new Object[breakage.getConflictingOptions().size() == 1 ? 1 : 0];
String secondKey = "error.break.";
if (allBreakingOptions.size() > 1) {
if (breakage.getConflictingOptions().size() > 1) {
secondKey += "multi_conflict";
} else {
secondKey += "single_conflict";
secondData[0] = allBreakingOptions.iterator().next().version().toString();
secondData[0] = breakage.getConflictingOptions().iterator().next().version().toString();
}
QuiltLoaderText second = QuiltLoaderText.translate(secondKey + ".title", secondData);
QuiltLoaderText title = QuiltLoaderText.translate("error.break.join.title", first, second);
QuiltDisplayedError error = manager.theQuiltPluginContext.reportError(title);

setIconFromMod(manager, mandatoryMod, error);

if (!dep.reason().isEmpty()) {
error.appendDescription(QuiltLoaderText.translate("error.reason", dep.reason()));
if (!breakage.publicDep.reason().isEmpty()) {
error.appendDescription(QuiltLoaderText.translate("error.reason", breakage.publicDep.reason()));
// A newline after the reason was desired here, but do you think Swing loves nice things?
}

addFiles(manager, error, from, allBreakingOptions);
addFiles(manager, error, from, breakage.getConflictingOptions());
addIssueLink(mandatoryMod, error);

StringBuilder report = new StringBuilder(rootModName);
report.append(" break");
if (from.size() == 1) {
report.append("s");
}
addVersionString(dep, report, true);
report.append(dep.id());// TODO
addVersionString(breakage.publicDep, report, true, false);
report.append(breakage.publicDep.id());// TODO
report.append(", which is present!");
error.appendReportText(report.toString());
if (dep.unless() != null) {
error.appendReportText(addUnlessClause(dep, rootModName, from, unlessDep, true));
if (breakage.publicDep.unless() != null) {
error.appendReportText(addUnlessClause(breakage.publicDep, rootModName, from, breakage.unless, true));
}
if (!dep.reason().isEmpty()) {
error.appendReportText("Breaking mod's reason: " + dep.reason(), "");
if (!breakage.publicDep.reason().isEmpty()) {
error.appendReportText("Breaking mod's reason: " + breakage.publicDep.reason(), "");
}
error.appendReportText("");

Expand All @@ -1164,13 +1166,13 @@ void report(QuiltPluginManagerImpl manager) {
}

error.appendReportText("", "Broken mods: ");
for (ModLoadOption mod : allBreakingOptions) {
for (ModLoadOption mod : breakage.getConflictingOptions()) {
error.appendReportText(getModReportLine(manager, mod));
}

if (unlessDep != null && !unlessDep.getNodesTo().isEmpty()) {
if (breakage.unless != null && !breakage.unless.getNodesTo().isEmpty()) {
error.appendReportText("", "Overriding mods: ");
for (LoadOption option : unlessDep.getNodesTo()) {
for (LoadOption option : breakage.unless.getNodesTo()) {
if (option instanceof ModLoadOption) {
error.appendReportText(getModReportLine(manager, ((ModLoadOption) option)));
} else {
Expand All @@ -1181,6 +1183,114 @@ void report(QuiltPluginManagerImpl manager) {
}
}

static class BreaksAllError extends SolverError {
final Set<ModLoadOption> from = new LinkedHashSet<>();
final QuiltRuleBreakAll breakage;

BreaksAllError(Graph graph, ModLoadOption from, QuiltRuleBreakAll breakage) {
super(graph);
this.from.add(from);
this.breakage = breakage;
}

@Override
boolean mergeInto(SolverError into) {
// BreaksAll are rare and there probably wont be duplicates.
// Plus collection equals are difficult
// We will just make sure we dont have multiple errors for the same rule

if (into instanceof BreaksAllError) {
BreaksAllError depDst = (BreaksAllError) into;
return breakage == depDst.breakage;
}
return false;
}

@Override
void report(QuiltPluginManagerImpl manager) {

boolean transitive = false;

// Title:
// "BuildCraft" breaks with [version 1.5.1] of "Quilt Standard Libraries", but it's present!

// Description:
// BuildCraft is loaded from '<mods>/buildcraft-9.0.0.jar'
ModLoadOption mandatoryMod = from.iterator().next();
String rootModName = from.size() > 1 ? from.size() + " mods [" + from.stream().map(ModLoadOption::metadata).map(ModMetadataExt::name).collect(Collectors.joining(", ")) + "]" : mandatoryMod.metadata().name();

// TODO: add UI stuff
// QuiltLoaderText first = VersionRangeDescriber.describe(
// rootModName, breakage.publicDep, breakage.publicDep, false, transitive
// );

// Object[] secondData = new Object[breakage.getConflictingOptions().size() == 1 ? 1 : 0];
// String secondKey = "error.break.";
// if (breakage.getConflictingOptions().size() > 1) {
// secondKey += "multi_conflict";
// } else {
// secondKey += "single_conflict";
// secondData[0] = breakage.getConflictingOptions().iterator().next().version().toString();
// }
// QuiltLoaderText second = QuiltLoaderText.translate(secondKey + ".title", secondData);
// QuiltLoaderText title = QuiltLoaderText.translate("error.break.join.title", first, second);
QuiltDisplayedError error = manager.theQuiltPluginContext.reportError(QuiltLoaderText.of("BREAKS ALL TEMP"));

// setIconFromMod(manager, mandatoryMod, error);

// if (!breakage.publicDep.reason().isEmpty()) {
// error.appendDescription(QuiltLoaderText.translate("error.reason", breakage.publicDep.reason()));
// // A newline after the reason was desired here, but do you think Swing loves nice things?
// }

// addFiles(manager, error, from, breakage.getConflictingOptions());
// addIssueLink(mandatoryMod, error);

StringBuilder report = new StringBuilder(rootModName);
report.append(" break");
if (from.size() == 1) {
report.append("s");
}
report.append(" because all of the following are present:");
error.appendReportText(report.toString());
for (QuiltRuleBreakOnly breakOnly: breakage.options) {
report = new StringBuilder("- ");
addVersionString(breakOnly.publicDep, report, false, true);
report.append(breakOnly.publicDep.id()); // TODO
report.append(":");
error.appendReportText(report.toString());
if (breakOnly.publicDep.unless() != null) {
error.appendReportText(" " + addUnlessClause(breakOnly.publicDep, rootModName, from, breakOnly.unless, true));
}
if (!breakOnly.publicDep.reason().isEmpty()) {
error.appendReportText(" Breaking reason: " + breakOnly.publicDep.reason());
}

error.appendReportText(" Matching mods: ");
for (ModLoadOption mod : breakOnly.getConflictingOptions()) {
error.appendReportText(" " + getModReportLine(manager, mod));
}

if (breakOnly.unless != null && !breakOnly.unless.getNodesTo().isEmpty()) {
error.appendReportText(" Overriding mods: ");
for (LoadOption option : breakOnly.unless.getNodesTo()) {
if (option instanceof ModLoadOption) {
error.appendReportText(" " + getModReportLine(manager, ((ModLoadOption) option)));
} else {
error.appendReportText(" - " + option.describe().toString());
}
}
}
error.appendReportText("");
}

error.appendReportText("Breaking mods: ");
for (ModLoadOption mod : from) {
error.appendReportText(getModReportLine(manager, mod));
}
}
}

static class DuplicatesError extends SolverError {
final String id;
final Set<LoadOption> duplicates = new LinkedHashSet<>();
Expand Down

0 comments on commit b93cf5c

Please sign in to comment.