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" 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")

View file

@ -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 {

View file

@ -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()) {