Fix and test jar processor caching.

This commit is contained in:
modmuss50
2023-01-23 22:06:05 +00:00
parent bab447ffe1
commit a1e671b719
19 changed files with 501 additions and 43 deletions

View File

@@ -42,5 +42,7 @@ public interface AccessWidenerEntry {
@Nullable
String mappingId();
String getSortKey();
void read(AccessWidenerVisitor visitor, LazyCloseable<TinyRemapper> remapper) throws IOException;
}

View File

@@ -24,10 +24,13 @@
package net.fabricmc.loom.configuration.accesswidener;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.inject.Inject;
@@ -62,8 +65,14 @@ public class AccessWidenerJarProcessor implements MinecraftJarProcessor<AccessWi
List<AccessWidenerEntry> accessWideners = new ArrayList<>();
if (localAccessWidenerProperty.isPresent()) {
Path path = localAccessWidenerProperty.get().getAsFile().toPath();
if (Files.notExists(path)) {
throw new UncheckedIOException(new FileNotFoundException("Could not find access widener file at {%s}".formatted(path)));
}
// Add the access widener specified in the extension
accessWideners.add(new LocalAccessWidenerEntry(localAccessWidenerProperty.get().getAsFile().toPath()));
accessWideners.add(LocalAccessWidenerEntry.create(path));
}
/* Uncomment to read all access wideners from local mods.
@@ -84,7 +93,7 @@ public class AccessWidenerJarProcessor implements MinecraftJarProcessor<AccessWi
return null;
}
return new Spec(Collections.unmodifiableList(accessWideners));
return new Spec(accessWideners.stream().sorted(Comparator.comparing(AccessWidenerEntry::getSortKey)).toList());
}
@Override

View File

@@ -25,6 +25,7 @@
package net.fabricmc.loom.configuration.accesswidener;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -32,11 +33,20 @@ import org.jetbrains.annotations.Nullable;
import net.fabricmc.accesswidener.AccessWidenerReader;
import net.fabricmc.accesswidener.AccessWidenerVisitor;
import net.fabricmc.loom.util.Checksum;
import net.fabricmc.loom.util.LazyCloseable;
import net.fabricmc.loom.util.fmj.ModEnvironment;
import net.fabricmc.tinyremapper.TinyRemapper;
public record LocalAccessWidenerEntry(Path path) implements AccessWidenerEntry {
public record LocalAccessWidenerEntry(Path path, String hash) implements AccessWidenerEntry {
public static LocalAccessWidenerEntry create(Path path) {
try {
return new LocalAccessWidenerEntry(path, Checksum.sha1Hex(path));
} catch (IOException e) {
throw new UncheckedIOException("Failed to create LocalAccessWidenerEntry", e);
}
}
@Override
public void read(AccessWidenerVisitor visitor, LazyCloseable<TinyRemapper> remapper) throws IOException {
var reader = new AccessWidenerReader(visitor);
@@ -52,4 +62,14 @@ public record LocalAccessWidenerEntry(Path path) implements AccessWidenerEntry {
public @Nullable String mappingId() {
return null;
}
@Override
public String getSortKey() {
return "local";
}
@Override
public int hashCode() {
return hash.hashCode();
}
}

View File

@@ -61,6 +61,11 @@ public record ModAccessWidenerEntry(FabricModJson mod, String path, ModEnvironme
return transitiveOnly ? mod.getId() : null;
}
@Override
public String getSortKey() {
return mod.getId() + ":" + path;
}
@Override
public void read(AccessWidenerVisitor visitor, LazyCloseable<TinyRemapper> remapper) throws IOException {
if (transitiveOnly) {

View File

@@ -34,10 +34,13 @@ import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.StringJoiner;
import java.util.stream.Collectors;
import org.gradle.api.Project;
import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.processor.MappingProcessorContext;
@@ -49,6 +52,7 @@ import net.fabricmc.mappingio.tree.MemoryMappingTree;
public final class MinecraftJarProcessorManager {
private static final String CACHE_VALUE_FILE_PATH = "META-INF/Loom-Jar-Processor-Cache";
private static final Logger LOGGER = LoggerFactory.getLogger(MinecraftJarProcessorManager.class);
private final List<ProcessorEntry<?>> jarProcessors;
@@ -73,14 +77,17 @@ public final class MinecraftJarProcessorManager {
List<ProcessorEntry<?>> entries = new ArrayList<>();
for (MinecraftJarProcessor<?> processor : processors) {
LOGGER.debug("Building processor spec for {}", processor.getName());
MinecraftJarProcessor.Spec spec = processor.buildSpec(context);
if (spec != null) {
LOGGER.debug("Adding processor entry for {}", processor.getName());
entries.add(new ProcessorEntry<>(processor, spec));
}
}
if (entries.isEmpty()) {
LOGGER.debug("No processor entries");
return null;
}
@@ -94,10 +101,23 @@ public final class MinecraftJarProcessorManager {
.collect(Collectors.joining("::"));
}
private String getDebugString() {
final StringJoiner sj = new StringJoiner("\n");
for (ProcessorEntry<?> jarProcessor : jarProcessors) {
sj.add(jarProcessor.name() + ":");
sj.add("\tHash: " + jarProcessor.hashCode());
sj.add("\tStr: " + jarProcessor.toString());
}
return sj.toString();
}
public boolean requiresProcessingJar(Path jar) {
Objects.requireNonNull(jar);
if (Files.notExists(jar)) {
LOGGER.debug("{} does not exist, generating", jar);
return true;
}
@@ -110,11 +130,23 @@ public final class MinecraftJarProcessorManager {
}
if (existingCache == null) {
LOGGER.info("{} does not contain a processor cache value, regenerating", jar);
return true;
}
final String existingCacheValue = new String(existingCache, StandardCharsets.UTF_8);
return !existingCacheValue.equals(getCacheValue());
final String expectedCacheValue = getCacheValue();
final boolean matches = existingCacheValue.equals(expectedCacheValue);
if (!matches) {
LOGGER.info("{} has an invalid cache, got {} expected {}", jar, existingCacheValue, expectedCacheValue);
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Expected state: {}", getDebugString());
}
}
return !matches;
}
public void processJar(Path jar, ProcessorContext context) throws IOException {

View File

@@ -62,7 +62,7 @@ public class Checksum {
HashCode hash = Files.asByteSource(file).hash(Hashing.sha256());
return hash.asBytes();
} catch (IOException e) {
throw new RuntimeException("Failed to get file hash");
throw new UncheckedIOException("Failed to get file hash", e);
}
}

View File

@@ -33,8 +33,9 @@ import java.util.Objects;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.VisibleForTesting;
public abstract sealed class FabricModJson permits FabricModJsonV0, FabricModJsonV1, FabricModJsonV2 {
public abstract sealed class FabricModJson permits FabricModJsonV0, FabricModJsonV1, FabricModJsonV2, FabricModJson.Mockable {
protected final JsonObject jsonObject;
private final FabricModJsonSource source;
@@ -59,4 +60,22 @@ public abstract sealed class FabricModJson permits FabricModJsonV0, FabricModJso
public final FabricModJsonSource getSource() {
return source;
}
@Override
public final String toString() {
return getClass().getName() + "[id=%s, version=%s, classTweakers=%s]".formatted(getId(), getVersion(), getClassTweakers());
}
@Override
public final int hashCode() {
return Objects.hash(getId(), getVersion());
}
@VisibleForTesting
public abstract non-sealed class Mockable extends FabricModJson {
private Mockable() {
super(null, null);
throw new AssertionError();
}
}
}

View File

@@ -24,17 +24,21 @@
package net.fabricmc.loom.util.fmj;
public enum ModEnvironment {
UNIVERSAL(true, true),
CLIENT(true, false),
SERVER(false, true);
import java.util.Objects;
public final class ModEnvironment {
public static final ModEnvironment UNIVERSAL = new ModEnvironment(true, true, "universal");
public static final ModEnvironment CLIENT = new ModEnvironment(true, false, "client");
public static final ModEnvironment SERVER = new ModEnvironment(false, true, "server");
private final boolean client;
private final boolean server;
private final String name;
ModEnvironment(boolean client, boolean server) {
private ModEnvironment(boolean client, boolean server, String name) {
this.client = client;
this.server = server;
this.name = name;
}
public boolean isClient() {
@@ -44,4 +48,17 @@ public enum ModEnvironment {
public boolean isServer() {
return server;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ModEnvironment that = (ModEnvironment) o;
return name.equals(that.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}