mirror of
https://github.com/architectury/architectury-loom.git
synced 2026-04-02 05:27:43 -05:00
Fix and test jar processor caching.
This commit is contained in:
@@ -42,5 +42,7 @@ public interface AccessWidenerEntry {
|
||||
@Nullable
|
||||
String mappingId();
|
||||
|
||||
String getSortKey();
|
||||
|
||||
void read(AccessWidenerVisitor visitor, LazyCloseable<TinyRemapper> remapper) throws IOException;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,16 +26,12 @@ package net.fabricmc.loom.test.unit
|
||||
|
||||
import net.fabricmc.loom.configuration.mods.ArtifactMetadata
|
||||
import net.fabricmc.loom.configuration.mods.ArtifactRef
|
||||
import net.fabricmc.loom.util.FileSystemUtil
|
||||
import spock.lang.Specification
|
||||
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.util.jar.Attributes
|
||||
import java.util.jar.Manifest
|
||||
|
||||
import static net.fabricmc.loom.configuration.mods.ArtifactMetadata.RemapRequirements.*
|
||||
import static net.fabricmc.loom.test.util.ZipTestUtils.*
|
||||
|
||||
class ArtifactMetadataTest extends Specification {
|
||||
def "is fabric mod"() {
|
||||
@@ -111,30 +107,4 @@ class ArtifactMetadataTest extends Specification {
|
||||
private static ArtifactRef createArtifact(Path zip) {
|
||||
return new ArtifactRef.FileArtifactRef(zip, "net.fabric", "loom-test", "1.0")
|
||||
}
|
||||
|
||||
private static Path createZip(Map<String, String> entries) {
|
||||
def file = Files.createTempFile("loom-test", ".zip")
|
||||
Files.delete(file)
|
||||
|
||||
FileSystemUtil.getJarFileSystem(file, true).withCloseable { zip ->
|
||||
entries.forEach { path, value ->
|
||||
def fsPath = zip.getPath(path)
|
||||
def fsPathParent = fsPath.getParent()
|
||||
if (fsPathParent != null) Files.createDirectories(fsPathParent)
|
||||
Files.writeString(fsPath, value, StandardCharsets.UTF_8)
|
||||
}
|
||||
}
|
||||
|
||||
return file
|
||||
}
|
||||
|
||||
private String manifest(String key, String value) {
|
||||
def manifest = new Manifest()
|
||||
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0")
|
||||
manifest.getMainAttributes().putValue(key, value)
|
||||
|
||||
def out = new ByteArrayOutputStream()
|
||||
manifest.write(out)
|
||||
return out.toString(StandardCharsets.UTF_8)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,4 +101,13 @@ class FabricModJsonV0Test extends Specification {
|
||||
then:
|
||||
fmj.getClassTweakers() == [:]
|
||||
}
|
||||
|
||||
def "hash code"() {
|
||||
given:
|
||||
def mockSource = Mock(FabricModJsonSource)
|
||||
when:
|
||||
def fmj = FabricModJsonFactory.create(JSON_OBJECT, mockSource)
|
||||
then:
|
||||
fmj.hashCode() == 930565976
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,4 +107,13 @@ class FabricModJsonV1Test extends Specification {
|
||||
then:
|
||||
fmj.getClassTweakers() == ["modid.accesswidener": ModEnvironment.UNIVERSAL]
|
||||
}
|
||||
|
||||
def "hash code"() {
|
||||
given:
|
||||
def mockSource = Mock(FabricModJsonSource)
|
||||
when:
|
||||
def fmj = FabricModJsonFactory.create(JSON_OBJECT, mockSource)
|
||||
then:
|
||||
fmj.hashCode() == 930565977
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,4 +125,13 @@ class FabricModJsonV2Test extends Specification {
|
||||
"universal.ct": ModEnvironment.UNIVERSAL
|
||||
]
|
||||
}
|
||||
|
||||
def "hash code"() {
|
||||
given:
|
||||
def mockSource = Mock(FabricModJsonSource)
|
||||
when:
|
||||
def fmj = FabricModJsonFactory.create(JSON_OBJECT, mockSource)
|
||||
then:
|
||||
fmj.hashCode() == 930565978
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2023 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.test.unit.processor
|
||||
|
||||
import net.fabricmc.loom.api.processor.SpecContext
|
||||
import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor
|
||||
import net.fabricmc.loom.test.util.GradleTestUtil
|
||||
import net.fabricmc.loom.util.fmj.FabricModJson
|
||||
import net.fabricmc.loom.util.fmj.ModEnvironment
|
||||
import spock.lang.Specification
|
||||
|
||||
class AccessWidenerJarProcessorTest extends Specification {
|
||||
def "Local AW"() {
|
||||
given:
|
||||
def specContext = Mock(SpecContext)
|
||||
def file = new File("src/test/resources/accesswidener/AccessWidenerJarProcessorTest.accesswidener")
|
||||
def localAccessWidenerProperty = GradleTestUtil.mockRegularFileProperty(file)
|
||||
|
||||
def processor = new AccessWidenerJarProcessor("AccessWidener", true, localAccessWidenerProperty)
|
||||
specContext.modDependencies() >> []
|
||||
|
||||
when:
|
||||
def spec = processor.buildSpec(specContext)
|
||||
|
||||
then:
|
||||
spec != null
|
||||
spec.hashCode() == 1205905061
|
||||
}
|
||||
|
||||
def "Dep AW"() {
|
||||
given:
|
||||
def specContext = Mock(SpecContext)
|
||||
|
||||
def mod1 = Mock(FabricModJson.Mockable)
|
||||
mod1.getClassTweakers() >> ["test.accesswidener": ModEnvironment.UNIVERSAL]
|
||||
mod1.getId() >> "modid1"
|
||||
|
||||
def mod2 = Mock(FabricModJson.Mockable)
|
||||
mod2.getClassTweakers() >> ["test2.accesswidener": ModEnvironment.UNIVERSAL]
|
||||
mod2.getId() >> "modid2"
|
||||
|
||||
specContext.modDependencies() >> [
|
||||
mod1,
|
||||
mod2
|
||||
].shuffled()
|
||||
|
||||
def processor = new AccessWidenerJarProcessor("AccessWidener", true, GradleTestUtil.mockRegularFileProperty(null))
|
||||
|
||||
when:
|
||||
def spec = processor.buildSpec(specContext)
|
||||
|
||||
then:
|
||||
spec != null
|
||||
spec.hashCode() == 1534839952
|
||||
}
|
||||
|
||||
def "No AWs"() {
|
||||
given:
|
||||
def specContext = Mock(SpecContext)
|
||||
specContext.modDependencies() >> []
|
||||
|
||||
def processor = new AccessWidenerJarProcessor("AccessWidener", true, GradleTestUtil.mockRegularFileProperty(null))
|
||||
|
||||
when:
|
||||
def spec = processor.buildSpec(specContext)
|
||||
|
||||
then:
|
||||
spec == null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2023 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.test.unit.processor
|
||||
|
||||
import net.fabricmc.loom.api.processor.ProcessorContext
|
||||
import net.fabricmc.loom.api.processor.SpecContext
|
||||
import net.fabricmc.loom.configuration.processors.MinecraftJarProcessorManager
|
||||
import net.fabricmc.loom.test.util.processor.TestMinecraftJarProcessor
|
||||
import spock.lang.Specification
|
||||
|
||||
import static net.fabricmc.loom.test.util.ZipTestUtils.createZip
|
||||
|
||||
class MinecraftJarProcessorManagerTest extends Specification {
|
||||
def "Does not require re-processing"() {
|
||||
given:
|
||||
def specContext = Mock(SpecContext)
|
||||
def processorContext = Mock(ProcessorContext)
|
||||
|
||||
def processor1 = new TestMinecraftJarProcessor(input: "Test1")
|
||||
def processor2 = new TestMinecraftJarProcessor(input: "Test2")
|
||||
def manager = MinecraftJarProcessorManager.create([processor1, processor2], specContext)
|
||||
|
||||
when:
|
||||
def jar = createZip(["fabric.mod.json": "{}"])
|
||||
manager.processJar(jar, processorContext)
|
||||
|
||||
then:
|
||||
!manager.requiresProcessingJar(jar)
|
||||
}
|
||||
|
||||
def "Requires re-processing"() {
|
||||
given:
|
||||
def specContext = Mock(SpecContext)
|
||||
def processorContext = Mock(ProcessorContext)
|
||||
|
||||
def processor1 = new TestMinecraftJarProcessor(input: "Test1")
|
||||
def processor2 = new TestMinecraftJarProcessor(input: "Test2")
|
||||
def manager1 = MinecraftJarProcessorManager.create([processor1], specContext)
|
||||
def manager2 = MinecraftJarProcessorManager.create([processor1, processor2], specContext)
|
||||
|
||||
when:
|
||||
def jar = createZip(["fabric.mod.json": "{}"])
|
||||
manager1.processJar(jar, processorContext)
|
||||
|
||||
then:
|
||||
manager2.requiresProcessingJar(jar)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2023 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.test.unit.processor
|
||||
|
||||
import net.fabricmc.loom.configuration.accesswidener.ModAccessWidenerEntry
|
||||
import net.fabricmc.loom.util.fmj.FabricModJson
|
||||
import net.fabricmc.loom.util.fmj.ModEnvironment
|
||||
import spock.lang.Specification
|
||||
|
||||
class ModAccessWidenerEntryTest extends Specification {
|
||||
def "read local mod"() {
|
||||
given:
|
||||
def mod = Mock(FabricModJson.Mockable)
|
||||
mod.getClassTweakers() >> ["test.accesswidener": ModEnvironment.UNIVERSAL]
|
||||
mod.hashCode() >> 0
|
||||
|
||||
when:
|
||||
def entries = ModAccessWidenerEntry.readAll(mod, true)
|
||||
then:
|
||||
entries.size() == 1
|
||||
def entry = entries[0]
|
||||
|
||||
entry.path() == "test.accesswidener"
|
||||
entry.environment() == ModEnvironment.UNIVERSAL
|
||||
entry.transitiveOnly()
|
||||
entry.hashCode() == -1218981396
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,8 @@ package net.fabricmc.loom.test.util
|
||||
|
||||
import net.fabricmc.loom.LoomGradleExtension
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.RegularFile
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.file.SourceDirectorySet
|
||||
import org.gradle.api.internal.tasks.DefaultSourceSet
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
@@ -33,6 +35,7 @@ import org.gradle.api.plugins.ExtensionContainer
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.SourceSet
|
||||
import org.gradle.api.tasks.util.PatternFilterable
|
||||
import org.jetbrains.annotations.Nullable
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any
|
||||
import static org.mockito.Mockito.mock
|
||||
@@ -90,4 +93,25 @@ class GradleTestUtil {
|
||||
def mock = mock(PatternFilterable.class)
|
||||
return mock
|
||||
}
|
||||
|
||||
static RegularFile mockRegularFile(File file) {
|
||||
def mock = mock(RegularFile.class)
|
||||
when(mock.getAsFile()).thenReturn(file)
|
||||
return mock
|
||||
}
|
||||
|
||||
static RegularFileProperty mockRegularFileProperty(@Nullable File file) {
|
||||
if (file == null) {
|
||||
def mock = mock(RegularFileProperty.class)
|
||||
when(mock.isPresent()).thenReturn(false)
|
||||
return mock
|
||||
}
|
||||
|
||||
def regularFile = mockRegularFile(file.getAbsoluteFile())
|
||||
|
||||
def mock = mock(RegularFileProperty.class)
|
||||
when(mock.get()).thenReturn(regularFile)
|
||||
when(mock.isPresent()).thenReturn(true)
|
||||
return mock
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2023 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.test.util
|
||||
|
||||
import net.fabricmc.loom.util.FileSystemUtil
|
||||
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.util.jar.Attributes
|
||||
import java.util.jar.Manifest
|
||||
|
||||
class ZipTestUtils {
|
||||
static Path createZip(Map<String, String> entries) {
|
||||
def file = Files.createTempFile("loom-test", ".zip")
|
||||
Files.delete(file)
|
||||
|
||||
FileSystemUtil.getJarFileSystem(file, true).withCloseable { zip ->
|
||||
entries.forEach { path, value ->
|
||||
def fsPath = zip.getPath(path)
|
||||
def fsPathParent = fsPath.getParent()
|
||||
if (fsPathParent != null) Files.createDirectories(fsPathParent)
|
||||
Files.writeString(fsPath, value, StandardCharsets.UTF_8)
|
||||
}
|
||||
}
|
||||
|
||||
return file
|
||||
}
|
||||
|
||||
static String manifest(String key, String value) {
|
||||
def manifest = new Manifest()
|
||||
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0")
|
||||
manifest.getMainAttributes().putValue(key, value)
|
||||
|
||||
def out = new ByteArrayOutputStream()
|
||||
manifest.write(out)
|
||||
return out.toString(StandardCharsets.UTF_8)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* This file is part of fabric-loom, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) 2023 FabricMC
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package net.fabricmc.loom.test.util.processor
|
||||
|
||||
import groovy.transform.Immutable
|
||||
import net.fabricmc.loom.api.processor.MinecraftJarProcessor
|
||||
import net.fabricmc.loom.api.processor.ProcessorContext
|
||||
import net.fabricmc.loom.api.processor.SpecContext
|
||||
|
||||
import java.nio.file.Path
|
||||
|
||||
@Immutable
|
||||
class TestMinecraftJarProcessor implements MinecraftJarProcessor<Spec> {
|
||||
String input
|
||||
|
||||
final String name = "TestProcessor"
|
||||
|
||||
@Override
|
||||
Spec buildSpec(SpecContext context) {
|
||||
if (input == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
return new Spec(input)
|
||||
}
|
||||
|
||||
@Immutable
|
||||
class Spec implements MinecraftJarProcessor.Spec {
|
||||
String input
|
||||
}
|
||||
|
||||
@Override
|
||||
void processJar(Path jar, Spec spec, ProcessorContext context) throws IOException {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
accessWidener v2 named
|
||||
|
||||
transitive-accessible method net/minecraft/recipe/BrewingRecipeRegistry registerPotionType (Lnet/minecraft/item/Item;)V
|
||||
Reference in New Issue
Block a user