remove dependency on guava
Some checks failed
Publish to snapshot maven / build (push) Has been cancelled
Some checks failed
Publish to snapshot maven / build (push) Has been cancelled
This commit is contained in:
parent
1ef8b24764
commit
cea4e8ea01
|
@ -7,7 +7,7 @@ plugins {
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "dev.frogmc"
|
group = "dev.frogmc"
|
||||||
version = "0.0.1-alpha.30"
|
version = "0.0.1-alpha.31"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
|
@ -27,7 +27,6 @@ dependencies {
|
||||||
compileOnly("org.apache.logging.log4j:log4j-api:2.22.1")
|
compileOnly("org.apache.logging.log4j:log4j-api:2.22.1")
|
||||||
compileOnly("org.apache.logging.log4j:log4j-core:2.22.1")
|
compileOnly("org.apache.logging.log4j:log4j-core:2.22.1")
|
||||||
compileOnly("com.google.code.gson:gson:2.0")
|
compileOnly("com.google.code.gson:gson:2.0")
|
||||||
compileOnly("com.google.guava:guava:21.0") // Lowest possible version for our code
|
|
||||||
|
|
||||||
api(libs.mixin) {
|
api(libs.mixin) {
|
||||||
exclude(group = "com.google.code.gson")
|
exclude(group = "com.google.code.gson")
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
plugins {
|
plugins {
|
||||||
java
|
java
|
||||||
id("dev.frogmc.phytotelma") version "0.0.1-alpha.21"
|
id("dev.frogmc.phytotelma") version "0.0.1-alpha.25"
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
|
@ -6,9 +6,6 @@ import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import com.google.common.collect.Multimap;
|
|
||||||
import com.google.common.collect.MultimapBuilder;
|
|
||||||
|
|
||||||
import dev.frogmc.frogloader.api.mod.ModDependencies;
|
import dev.frogmc.frogloader.api.mod.ModDependencies;
|
||||||
import dev.frogmc.frogloader.api.mod.ModProperties;
|
import dev.frogmc.frogloader.api.mod.ModProperties;
|
||||||
import dev.frogmc.frogloader.api.mod.SemVer;
|
import dev.frogmc.frogloader.api.mod.SemVer;
|
||||||
|
@ -21,16 +18,15 @@ import org.jetbrains.annotations.Nullable;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@SuppressWarnings("UnstableApiUsage")
|
|
||||||
public class ModDependencyResolver {
|
public class ModDependencyResolver {
|
||||||
|
|
||||||
private final static Logger LOGGER = LoggerFactory.getLogger(ModDependencyResolver.class);
|
private final static Logger LOGGER = LoggerFactory.getLogger(ModDependencyResolver.class);
|
||||||
private static final Pattern COMPARATOR = Pattern.compile("(=|>=|<=|>|<)?(\\d.*)");
|
private static final Pattern COMPARATOR = Pattern.compile("(=|>=|<=|>|<)?(\\d.*)");
|
||||||
private final Collection<ModProperties> original;
|
private final Collection<ModProperties> original;
|
||||||
private final Multimap<String, DependencyEntry> dependencies = MultimapBuilder.hashKeys().arrayListValues().build();
|
private final Map<String, Collection<DependencyEntry>> dependencies = new HashMap<>();
|
||||||
private final Multimap<String, DependencyEntry> breakings = MultimapBuilder.hashKeys().arrayListValues().build();
|
private final Map<String, Collection<DependencyEntry>> breakings = new HashMap<>();
|
||||||
private final Multimap<String, DependencyEntry> suggests = MultimapBuilder.hashKeys().arrayListValues().build();
|
private final Map<String, Collection<DependencyEntry>> suggests = new HashMap<>();
|
||||||
private final Multimap<String, ProvidedMod> provides = MultimapBuilder.hashKeys().arrayListValues().build();
|
private final Map<String, Collection<ProvidedMod>> provides = new HashMap<>();
|
||||||
private final Map<String, ModProperties> presentMods = new HashMap<>();
|
private final Map<String, ModProperties> presentMods = new HashMap<>();
|
||||||
|
|
||||||
public ModDependencyResolver(Collection<ModProperties> mods) throws ResolverException {
|
public ModDependencyResolver(Collection<ModProperties> mods) throws ResolverException {
|
||||||
|
@ -41,17 +37,17 @@ public class ModDependencyResolver {
|
||||||
private void load() throws ResolverException {
|
private void load() throws ResolverException {
|
||||||
for (ModProperties props : original) {
|
for (ModProperties props : original) {
|
||||||
for (ModDependencies.Entry entry : props.dependencies().getForType(ModDependencies.Type.DEPEND)) {
|
for (ModDependencies.Entry entry : props.dependencies().getForType(ModDependencies.Type.DEPEND)) {
|
||||||
dependencies.put(entry.id(), new DependencyEntry(entry.range(), props, entry.link(), entry.name()));
|
dependencies.computeIfAbsent(entry.id(), i -> new HashSet<>()).add(new DependencyEntry(entry.range(), props, entry.link(), entry.name()));
|
||||||
}
|
}
|
||||||
for (ModDependencies.Entry entry : props.dependencies().getForType(ModDependencies.Type.BREAK)) {
|
for (ModDependencies.Entry entry : props.dependencies().getForType(ModDependencies.Type.BREAK)) {
|
||||||
breakings.put(entry.id(), new DependencyEntry(entry.range(), props, entry.link(), entry.name()));
|
breakings.computeIfAbsent(entry.id(), i -> new HashSet<>()).add(new DependencyEntry(entry.range(), props, entry.link(), entry.name()));
|
||||||
}
|
}
|
||||||
for (ModDependencies.Entry entry : props.dependencies().getForType(ModDependencies.Type.SUGGEST)) {
|
for (ModDependencies.Entry entry : props.dependencies().getForType(ModDependencies.Type.SUGGEST)) {
|
||||||
suggests.put(entry.id(), new DependencyEntry(entry.range(), props, entry.link(), entry.name()));
|
suggests.computeIfAbsent(entry.id(), i -> new HashSet<>()).add(new DependencyEntry(entry.range(), props, entry.link(), entry.name()));
|
||||||
}
|
}
|
||||||
props.dependencies().getForType(ModDependencies.Type.PROVIDE).forEach(e -> {
|
props.dependencies().getForType(ModDependencies.Type.PROVIDE).forEach(e -> {
|
||||||
try {
|
try {
|
||||||
provides.put(e.id(), new ProvidedMod(e.id(), SemVerImpl.parse(e.range()), props));
|
provides.computeIfAbsent(e.id(), i -> new HashSet<>()).add(new ProvidedMod(e.id(), SemVerImpl.parse(e.range()), props));
|
||||||
} catch (SemVerParseException ex) {
|
} catch (SemVerParseException ex) {
|
||||||
LOGGER.warn("Version for {} ({}), provided by mod '{}' ({}) does not meet SemVer specifications. Mod will not be provided.",
|
LOGGER.warn("Version for {} ({}), provided by mod '{}' ({}) does not meet SemVer specifications. Mod will not be provided.",
|
||||||
e.id(), e.range(), props.id(), props.name());
|
e.id(), e.range(), props.id(), props.name());
|
||||||
|
@ -66,26 +62,28 @@ public class ModDependencyResolver {
|
||||||
// Step 1: Combine present and provided mods, always use the latest version available
|
// Step 1: Combine present and provided mods, always use the latest version available
|
||||||
Map<String, SemVer> presentOrProvided = new HashMap<>();
|
Map<String, SemVer> presentOrProvided = new HashMap<>();
|
||||||
presentMods.forEach((s, modProperties) -> presentOrProvided.put(s, modProperties.version()));
|
presentMods.forEach((s, modProperties) -> presentOrProvided.put(s, modProperties.version()));
|
||||||
provides.forEach((s, ver) -> {
|
provides.forEach((s, vers) ->
|
||||||
if (presentMods.containsKey(s)) {
|
vers.forEach(ver -> {
|
||||||
if (presentMods.get(s).version().compareTo(ver.version()) < 0) {
|
if (presentMods.containsKey(s)) {
|
||||||
presentOrProvided.replace(s, ver.version());
|
if (presentMods.get(s).version().compareTo(ver.version()) < 0) {
|
||||||
}
|
presentOrProvided.replace(s, ver.version());
|
||||||
} else {
|
}
|
||||||
presentOrProvided.put(s, ver.version());
|
} else {
|
||||||
}
|
presentOrProvided.put(s, ver.version());
|
||||||
});
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
// Step 2: look for breakage declarations
|
// Step 2: look for breakage declarations
|
||||||
Collection<BreakingModException.Entry> breaks = new HashSet<>();
|
Collection<BreakingModException.Entry> breaks = new HashSet<>();
|
||||||
for (Map.Entry<String, DependencyEntry> e : breakings.entries()) {
|
for (Map.Entry<String, Collection<DependencyEntry>> e : breakings.entrySet()) {
|
||||||
String key = e.getKey();
|
String key = e.getKey();
|
||||||
DependencyEntry dependencyEntry = e.getValue();
|
e.getValue().forEach(dependencyEntry -> {
|
||||||
if (presentOrProvided.containsKey(key) && dependencyEntry.range.versionMatches(presentOrProvided.get(key))) {
|
if (presentOrProvided.containsKey(key) && dependencyEntry.range.versionMatches(presentOrProvided.get(key))) {
|
||||||
breaks.add(new BreakingModException.Entry(dependencyEntry.origin(),
|
breaks.add(new BreakingModException.Entry(dependencyEntry.origin(),
|
||||||
Optional.ofNullable(presentMods.get(key)).orElseGet(() -> provides.get(key).stream().findFirst().map(ProvidedMod::source).orElseThrow()),
|
Optional.ofNullable(presentMods.get(key)).orElseGet(() -> provides.get(key).stream().findFirst().map(ProvidedMod::source).orElseThrow()),
|
||||||
dependencyEntry.range));
|
dependencyEntry.range));
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!breaks.isEmpty()) {
|
if (!breaks.isEmpty()) {
|
||||||
|
@ -99,13 +97,14 @@ public class ModDependencyResolver {
|
||||||
|
|
||||||
|
|
||||||
// Step 3: print out information about suggested mods
|
// Step 3: print out information about suggested mods
|
||||||
for (Map.Entry<String, DependencyEntry> e : suggests.entries()) {
|
for (Map.Entry<String, Collection<DependencyEntry>> e : suggests.entrySet()) {
|
||||||
String key = e.getKey();
|
String key = e.getKey();
|
||||||
DependencyEntry v = e.getValue();
|
e.getValue().forEach(v -> {
|
||||||
if (!presentOrProvided.containsKey(key) || !v.range.versionMatches(presentOrProvided.get(key))) {
|
if (!presentOrProvided.containsKey(key) || !v.range.versionMatches(presentOrProvided.get(key))) {
|
||||||
LOGGER.info("Mod '{}' ({}) suggests range {} of {}, you should install a matching version for the optimal experience!",
|
LOGGER.info("Mod '{}' ({}) suggests range {} of {}, you should install a matching version for the optimal experience!",
|
||||||
v.origin().id(), v.origin().name(), v.range(), key);
|
v.origin().id(), v.origin().name(), v.range(), key);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 4.1: Add all mods to the result that do not depend on any other mods
|
// Step 4.1: Add all mods to the result that do not depend on any other mods
|
||||||
|
@ -118,22 +117,23 @@ public class ModDependencyResolver {
|
||||||
|
|
||||||
Collection<UnfulfilledDependencyException.Entry> unfulfilled = new HashSet<>();
|
Collection<UnfulfilledDependencyException.Entry> unfulfilled = new HashSet<>();
|
||||||
// Step 4.2: Check that all dependencies are satisfied by present or provided mods.
|
// Step 4.2: Check that all dependencies are satisfied by present or provided mods.
|
||||||
for (Map.Entry<String, DependencyEntry> entry : dependencies.entries()) {
|
for (Map.Entry<String, Collection<DependencyEntry>> entry : dependencies.entrySet()) {
|
||||||
String s = entry.getKey();
|
String s = entry.getKey();
|
||||||
DependencyEntry value = entry.getValue();
|
entry.getValue().forEach(value -> {
|
||||||
if (!(presentMods.containsKey(s) && value.range.versionMatches(presentOrProvided.get(s)))) { // The dependency isn't fulfilled by any present mods
|
if (!(presentMods.containsKey(s) && value.range.versionMatches(presentOrProvided.get(s)))) { // The dependency isn't fulfilled by any present mods
|
||||||
if (!(provides.containsKey(s) && provides.get(s).stream().map(ProvidedMod::version).allMatch(value.range::versionMatches))) { // The dependency also isn't fulfilled by any provided mods
|
if (!(provides.containsKey(s) && provides.get(s).stream().map(ProvidedMod::version).allMatch(value.range::versionMatches))) { // The dependency also isn't fulfilled by any provided mods
|
||||||
if (value.origin.extensions().getOrDefault(Constants.MOD_ID, Constants.EXTENSION_LOADING_TYPE, "required").equals("required")) {
|
if (value.origin.extensions().getOrDefault(Constants.MOD_ID, Constants.EXTENSION_LOADING_TYPE, "required").equals("required")) {
|
||||||
unfulfilled.add(new UnfulfilledDependencyException.Entry(value.origin, s, value.range, presentOrProvided.get(s), value.link(), value.name()));
|
unfulfilled.add(new UnfulfilledDependencyException.Entry(value.origin, s, value.range, presentOrProvided.get(s), value.link(), value.name()));
|
||||||
} else {
|
} else {
|
||||||
LOGGER.debug("Skipping optional mod: {} ({})", value.origin().id(), value.origin().name());
|
LOGGER.debug("Skipping optional mod: {} ({})", value.origin().id(), value.origin().name());
|
||||||
continue;
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
// as there hasn't been thrown an exception the dependency must have been fulfilled, add the mod that set the dependency
|
||||||
// as there hasn't been thrown an exception the dependency must have been fulfilled, add the mod that set the dependency
|
LOGGER.debug("Adding mod to result: {} ({})", value.origin().id(), value.origin().name());
|
||||||
LOGGER.debug("Adding mod to result: {} ({})", value.origin().id(), value.origin().name());
|
result.add(value.origin());
|
||||||
result.add(value.origin());
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!unfulfilled.isEmpty()) {
|
if (!unfulfilled.isEmpty()) {
|
||||||
|
|
Loading…
Reference in a new issue