remove dependency on guava
Some checks failed
Publish to snapshot maven / build (push) Has been cancelled

This commit is contained in:
moehreag 2024-09-19 12:55:53 +02:00
parent 1ef8b24764
commit cea4e8ea01
3 changed files with 49 additions and 50 deletions

View file

@ -7,7 +7,7 @@ plugins {
}
group = "dev.frogmc"
version = "0.0.1-alpha.30"
version = "0.0.1-alpha.31"
repositories {
maven {
@ -27,7 +27,6 @@ dependencies {
compileOnly("org.apache.logging.log4j:log4j-api:2.22.1")
compileOnly("org.apache.logging.log4j:log4j-core:2.22.1")
compileOnly("com.google.code.gson:gson:2.0")
compileOnly("com.google.guava:guava:21.0") // Lowest possible version for our code
api(libs.mixin) {
exclude(group = "com.google.code.gson")

View file

@ -1,6 +1,6 @@
plugins {
java
id("dev.frogmc.phytotelma") version "0.0.1-alpha.21"
id("dev.frogmc.phytotelma") version "0.0.1-alpha.25"
}
dependencies {

View file

@ -6,9 +6,6 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
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.ModProperties;
import dev.frogmc.frogloader.api.mod.SemVer;
@ -21,16 +18,15 @@ import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@SuppressWarnings("UnstableApiUsage")
public class ModDependencyResolver {
private final static Logger LOGGER = LoggerFactory.getLogger(ModDependencyResolver.class);
private static final Pattern COMPARATOR = Pattern.compile("(=|>=|<=|>|<)?(\\d.*)");
private final Collection<ModProperties> original;
private final Multimap<String, DependencyEntry> dependencies = MultimapBuilder.hashKeys().arrayListValues().build();
private final Multimap<String, DependencyEntry> breakings = MultimapBuilder.hashKeys().arrayListValues().build();
private final Multimap<String, DependencyEntry> suggests = MultimapBuilder.hashKeys().arrayListValues().build();
private final Multimap<String, ProvidedMod> provides = MultimapBuilder.hashKeys().arrayListValues().build();
private final Map<String, Collection<DependencyEntry>> dependencies = new HashMap<>();
private final Map<String, Collection<DependencyEntry>> breakings = new HashMap<>();
private final Map<String, Collection<DependencyEntry>> suggests = new HashMap<>();
private final Map<String, Collection<ProvidedMod>> provides = new HashMap<>();
private final Map<String, ModProperties> presentMods = new HashMap<>();
public ModDependencyResolver(Collection<ModProperties> mods) throws ResolverException {
@ -41,17 +37,17 @@ public class ModDependencyResolver {
private void load() throws ResolverException {
for (ModProperties props : original) {
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)) {
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)) {
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 -> {
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) {
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());
@ -66,26 +62,28 @@ public class ModDependencyResolver {
// Step 1: Combine present and provided mods, always use the latest version available
Map<String, SemVer> presentOrProvided = new HashMap<>();
presentMods.forEach((s, modProperties) -> presentOrProvided.put(s, modProperties.version()));
provides.forEach((s, ver) -> {
if (presentMods.containsKey(s)) {
if (presentMods.get(s).version().compareTo(ver.version()) < 0) {
presentOrProvided.replace(s, ver.version());
}
} else {
presentOrProvided.put(s, ver.version());
}
});
provides.forEach((s, vers) ->
vers.forEach(ver -> {
if (presentMods.containsKey(s)) {
if (presentMods.get(s).version().compareTo(ver.version()) < 0) {
presentOrProvided.replace(s, ver.version());
}
} else {
presentOrProvided.put(s, ver.version());
}
}));
// Step 2: look for breakage declarations
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();
DependencyEntry dependencyEntry = e.getValue();
if (presentOrProvided.containsKey(key) && dependencyEntry.range.versionMatches(presentOrProvided.get(key))) {
breaks.add(new BreakingModException.Entry(dependencyEntry.origin(),
Optional.ofNullable(presentMods.get(key)).orElseGet(() -> provides.get(key).stream().findFirst().map(ProvidedMod::source).orElseThrow()),
dependencyEntry.range));
}
e.getValue().forEach(dependencyEntry -> {
if (presentOrProvided.containsKey(key) && dependencyEntry.range.versionMatches(presentOrProvided.get(key))) {
breaks.add(new BreakingModException.Entry(dependencyEntry.origin(),
Optional.ofNullable(presentMods.get(key)).orElseGet(() -> provides.get(key).stream().findFirst().map(ProvidedMod::source).orElseThrow()),
dependencyEntry.range));
}
});
}
if (!breaks.isEmpty()) {
@ -99,13 +97,14 @@ public class ModDependencyResolver {
// 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();
DependencyEntry v = e.getValue();
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!",
v.origin().id(), v.origin().name(), v.range(), key);
}
e.getValue().forEach(v -> {
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!",
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
@ -118,22 +117,23 @@ public class ModDependencyResolver {
Collection<UnfulfilledDependencyException.Entry> unfulfilled = new HashSet<>();
// 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();
DependencyEntry value = entry.getValue();
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 (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()));
} else {
LOGGER.debug("Skipping optional mod: {} ({})", value.origin().id(), value.origin().name());
continue;
entry.getValue().forEach(value -> {
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 (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()));
} else {
LOGGER.debug("Skipping optional mod: {} ({})", value.origin().id(), value.origin().name());
return;
}
}
}
}
// 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());
result.add(value.origin());
// 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());
result.add(value.origin());
});
}
if (!unfulfilled.isEmpty()) {