From da4b01427fcbff703b071b0d6f5cd72d1370806a Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Tue, 10 Jan 2023 23:19:21 +0000 Subject: [PATCH 1/9] Move access widener jar processor for new processor API. (#787) --- .../loom/api/LoomGradleExtensionAPI.java | 2 +- .../processor/MappingProcessorContext.java | 7 +- .../loom/api/processor/ProcessorContext.java | 5 +- .../configuration/CompileConfiguration.java | 16 +- .../accesswidener/AccessWidenerEntry.java | 46 ++++ .../AccessWidenerJarProcessor.java | 145 ++++++++---- .../AccessWidenerTransformer.java | 17 +- .../LocalAccessWidenerEntry.java | 55 +++++ .../accesswidener/ModAccessWidenerEntry.java | 95 ++++++++ .../TransitiveAccessWidenerJarProcessor.java | 221 ------------------ ...nsitiveAccessWidenerMappingsProcessor.java | 54 +++-- .../InterfaceInjectionProcessor.java | 11 +- .../processors/ContextImplHelper.java | 57 +++++ .../MappingProcessorContextImpl.java | 38 +++ .../processors/ProcessorContextImpl.java | 23 +- .../processors/SpecContextImpl.java | 36 +-- .../extension/LoomGradleExtensionApiImpl.java | 4 - .../loom/task/GenerateSourcesTask.java | 19 +- .../fabricmc/loom/util/DeprecationHelper.java | 10 +- .../net/fabricmc/loom/util/LazyCloseable.java | 58 +++++ .../loom/util/fmj/FabricModJsonHelpers.java | 62 +++++ .../loom/util/fmj/FabricModJsonSource.java | 6 +- 22 files changed, 598 insertions(+), 389 deletions(-) create mode 100644 src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerEntry.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/accesswidener/LocalAccessWidenerEntry.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/accesswidener/ModAccessWidenerEntry.java delete mode 100644 src/main/java/net/fabricmc/loom/configuration/accesswidener/TransitiveAccessWidenerJarProcessor.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/processors/ContextImplHelper.java create mode 100644 src/main/java/net/fabricmc/loom/configuration/processors/MappingProcessorContextImpl.java create mode 100644 src/main/java/net/fabricmc/loom/util/LazyCloseable.java create mode 100644 src/main/java/net/fabricmc/loom/util/fmj/FabricModJsonHelpers.java diff --git a/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java b/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java index 432b5dc9..45587d96 100644 --- a/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java +++ b/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2021-2022 FabricMC + * Copyright (c) 2021-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 diff --git a/src/main/java/net/fabricmc/loom/api/processor/MappingProcessorContext.java b/src/main/java/net/fabricmc/loom/api/processor/MappingProcessorContext.java index 3c4aad66..ff2d3fca 100644 --- a/src/main/java/net/fabricmc/loom/api/processor/MappingProcessorContext.java +++ b/src/main/java/net/fabricmc/loom/api/processor/MappingProcessorContext.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2022 FabricMC + * Copyright (c) 2022-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 @@ -24,5 +24,10 @@ package net.fabricmc.loom.api.processor; +import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; +import net.fabricmc.loom.util.LazyCloseable; +import net.fabricmc.tinyremapper.TinyRemapper; + public interface MappingProcessorContext { + LazyCloseable createRemapper(MappingsNamespace from, MappingsNamespace to); } diff --git a/src/main/java/net/fabricmc/loom/api/processor/ProcessorContext.java b/src/main/java/net/fabricmc/loom/api/processor/ProcessorContext.java index 5f934e65..a5152f9b 100644 --- a/src/main/java/net/fabricmc/loom/api/processor/ProcessorContext.java +++ b/src/main/java/net/fabricmc/loom/api/processor/ProcessorContext.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2022 FabricMC + * Copyright (c) 2022-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 @@ -26,6 +26,7 @@ package net.fabricmc.loom.api.processor; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration; +import net.fabricmc.loom.util.LazyCloseable; import net.fabricmc.tinyremapper.TinyRemapper; public interface ProcessorContext { @@ -37,5 +38,5 @@ public interface ProcessorContext { boolean includesServer(); - TinyRemapper createRemapper(MappingsNamespace from, MappingsNamespace to); + LazyCloseable createRemapper(MappingsNamespace from, MappingsNamespace to); } diff --git a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java index 7cdb5846..2548d62e 100644 --- a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java +++ b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2016-2022 FabricMC + * Copyright (c) 2016-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 @@ -49,7 +49,6 @@ import net.fabricmc.loom.build.mixin.JavaApInvoker; import net.fabricmc.loom.build.mixin.KaptApInvoker; import net.fabricmc.loom.build.mixin.ScalaApInvoker; import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor; -import net.fabricmc.loom.configuration.accesswidener.TransitiveAccessWidenerJarProcessor; import net.fabricmc.loom.configuration.ifaceinject.InterfaceInjectionProcessor; import net.fabricmc.loom.configuration.processors.MinecraftJarProcessorManager; import net.fabricmc.loom.configuration.processors.ModJavadocProcessor; @@ -221,17 +220,8 @@ public final class CompileConfiguration { private static void registerGameProcessors(ConfigContext configContext) { final LoomGradleExtension extension = configContext.extension(); - if (extension.getAccessWidenerPath().isPresent()) { - extension.getGameJarProcessors().add(new AccessWidenerJarProcessor(configContext)); - } - - if (extension.getEnableTransitiveAccessWideners().get()) { - TransitiveAccessWidenerJarProcessor transitiveAccessWidenerJarProcessor = new TransitiveAccessWidenerJarProcessor(configContext); - - if (!transitiveAccessWidenerJarProcessor.isEmpty()) { - extension.getGameJarProcessors().add(transitiveAccessWidenerJarProcessor); - } - } + final boolean enableTransitiveAccessWideners = extension.getEnableTransitiveAccessWideners().get(); + extension.addMinecraftJarProcessor(AccessWidenerJarProcessor.class, "fabric-loom:access-widener", enableTransitiveAccessWideners, extension.getAccessWidenerPath()); if (extension.getEnableModProvidedJavadoc().get()) { extension.addMinecraftJarProcessor(ModJavadocProcessor.class, "fabric-loom:mod-javadoc"); diff --git a/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerEntry.java b/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerEntry.java new file mode 100644 index 00000000..7dd2d2d1 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerEntry.java @@ -0,0 +1,46 @@ +/* + * 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.configuration.accesswidener; + +import java.io.IOException; + +import org.jetbrains.annotations.Nullable; + +import net.fabricmc.accesswidener.AccessWidenerVisitor; +import net.fabricmc.loom.util.LazyCloseable; +import net.fabricmc.loom.util.fmj.ModEnvironment; +import net.fabricmc.tinyremapper.TinyRemapper; + +public interface AccessWidenerEntry { + ModEnvironment environment(); + + /** + * @return The mod id to be used in {@link TransitiveAccessWidenerMappingsProcessor} or null when this entry does not contain transitive entries. + */ + @Nullable + String mappingId(); + + void read(AccessWidenerVisitor visitor, LazyCloseable remapper) throws IOException; +} diff --git a/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerJarProcessor.java b/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerJarProcessor.java index daacaf4b..b56cb9d5 100644 --- a/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerJarProcessor.java +++ b/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerJarProcessor.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2020-2021 FabricMC + * 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 @@ -24,73 +24,118 @@ package net.fabricmc.loom.configuration.accesswidener; -import java.io.File; import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.NoSuchFileException; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; -import com.google.common.hash.Hashing; -import org.gradle.api.Project; +import javax.inject.Inject; + +import org.gradle.api.file.RegularFileProperty; +import org.jetbrains.annotations.Nullable; import net.fabricmc.accesswidener.AccessWidener; -import net.fabricmc.accesswidener.AccessWidenerReader; -import net.fabricmc.loom.LoomGradleExtension; -import net.fabricmc.loom.configuration.ConfigContext; -import net.fabricmc.loom.configuration.processors.JarProcessor; -import net.fabricmc.loom.util.Checksum; -import net.fabricmc.loom.util.ZipUtils; +import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; +import net.fabricmc.loom.api.processor.MinecraftJarProcessor; +import net.fabricmc.loom.api.processor.ProcessorContext; +import net.fabricmc.loom.api.processor.SpecContext; +import net.fabricmc.loom.util.LazyCloseable; +import net.fabricmc.loom.util.fmj.FabricModJson; +import net.fabricmc.loom.util.fmj.ModEnvironment; +import net.fabricmc.tinyremapper.TinyRemapper; -public class AccessWidenerJarProcessor implements JarProcessor { - // Filename used to store hash of input access widener in processed jar file - private static final String HASH_FILENAME = "aw.sha256"; - private final AccessWidener accessWidener = new AccessWidener(); - private final Project project; - // This is a SHA256 hash across the mod's and all transitive AWs - private byte[] inputHash; +public class AccessWidenerJarProcessor implements MinecraftJarProcessor { + private final String name; + private final boolean includeTransitive; + private final RegularFileProperty localAccessWidenerProperty; - public AccessWidenerJarProcessor(ConfigContext configContext) { - this.project = configContext.project(); + @Inject + public AccessWidenerJarProcessor(String name, boolean includeTransitive, RegularFileProperty localAccessWidenerProperty) { + this.name = name; + this.includeTransitive = includeTransitive; + this.localAccessWidenerProperty = localAccessWidenerProperty; } @Override - public String getId() { - return "loom:access_widener:" + Checksum.toHex(inputHash); - } + public @Nullable AccessWidenerJarProcessor.Spec buildSpec(SpecContext context) { + List accessWideners = new ArrayList<>(); - @Override - public void setup() { - LoomGradleExtension extension = LoomGradleExtension.get(project); - Path awPath = extension.getAccessWidenerPath().get().getAsFile().toPath(); - - // Read our own mod's access widener, used later for producing a version remapped to intermediary - // The mod's own access widener file - byte[] modAccessWidener; - - try { - modAccessWidener = Files.readAllBytes(awPath); - } catch (NoSuchFileException e) { - throw new RuntimeException("Could not find access widener file @ " + awPath.toAbsolutePath()); - } catch (IOException e) { - throw new RuntimeException("Failed to read access widener: " + awPath); + if (localAccessWidenerProperty.isPresent()) { + // Add the access widener specified in the extension + accessWideners.add(new LocalAccessWidenerEntry(localAccessWidenerProperty.get().getAsFile().toPath())); } - AccessWidenerReader reader = new AccessWidenerReader(accessWidener); - reader.read(modAccessWidener); + /* Uncomment to read all access wideners from local mods. - inputHash = Hashing.sha256().hashBytes(modAccessWidener).asBytes(); + for (FabricModJson fabricModJson : context.localMods()) { + accessWideners.addAll(ModAccessWidenerEntry.readAll(fabricModJson, false)); + } + + */ + + if (includeTransitive) { + for (FabricModJson fabricModJson : context.modDependencies()) { + accessWideners.addAll(ModAccessWidenerEntry.readAll(fabricModJson, true)); + } + } + + if (accessWideners.isEmpty()) { + return null; + } + + return new Spec(Collections.unmodifiableList(accessWideners)); } @Override - public void process(File file) { - AccessWidenerTransformer applier = new AccessWidenerTransformer(project.getLogger(), accessWidener); - applier.apply(file); + public String getName() { + return name; + } - try { - ZipUtils.add(file.toPath(), HASH_FILENAME, inputHash); - } catch (IOException e) { - throw new UncheckedIOException("Failed to write aw jar hash", e); + public record Spec(List accessWideners) implements MinecraftJarProcessor.Spec { + List accessWidenersForContext(ProcessorContext context) { + return accessWideners.stream() + .filter(entry -> isSupported(entry.environment(), context)) + .toList(); } + + private static boolean isSupported(ModEnvironment modEnvironment, ProcessorContext context) { + if (context.isMerged()) { + // All envs are supported wth a merged jar + return true; + } + + if (context.includesClient() && modEnvironment.isClient()) { + return true; + } + + if (context.includesServer() && modEnvironment.isServer()) { + return true; + } + + // Universal supports all jars + return modEnvironment == ModEnvironment.UNIVERSAL; + } + } + + @Override + public void processJar(Path jar, AccessWidenerJarProcessor.Spec spec, ProcessorContext context) throws IOException { + final List accessWideners = spec.accessWidenersForContext(context); + + final var accessWidener = new AccessWidener(); + + try (LazyCloseable remapper = context.createRemapper(MappingsNamespace.INTERMEDIARY, MappingsNamespace.NAMED)) { + for (AccessWidenerEntry widener : accessWideners) { + widener.read(accessWidener, remapper); + } + } + + AccessWidenerTransformer transformer = new AccessWidenerTransformer(accessWidener); + transformer.apply(jar); + } + + @Override + public @Nullable MappingsProcessor processMappings() { + return TransitiveAccessWidenerMappingsProcessor.INSTANCE; } } diff --git a/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerTransformer.java b/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerTransformer.java index 69376e0a..0eb195af 100644 --- a/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerTransformer.java +++ b/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerTransformer.java @@ -24,17 +24,18 @@ package net.fabricmc.loom.configuration.accesswidener; -import java.io.File; import java.io.IOException; import java.io.UncheckedIOException; +import java.nio.file.Path; import java.util.List; import java.util.Set; import java.util.stream.Collectors; -import org.gradle.api.logging.Logger; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import net.fabricmc.accesswidener.AccessWidener; import net.fabricmc.accesswidener.AccessWidenerClassVisitor; @@ -43,20 +44,20 @@ import net.fabricmc.loom.util.Pair; import net.fabricmc.loom.util.ZipUtils; final class AccessWidenerTransformer { - private final Logger logger; + private static final Logger LOGGER = LoggerFactory.getLogger(AccessWidenerTransformer.class); + private final AccessWidener accessWidener; - AccessWidenerTransformer(Logger logger, AccessWidener accessWidener) { - this.logger = logger; + AccessWidenerTransformer(AccessWidener accessWidener) { this.accessWidener = accessWidener; } /** * Apply the rules from an access-widener to the given jar or zip file. */ - void apply(File jarFile) { + void apply(Path jarFile) { try { - ZipUtils.transform(jarFile.toPath(), getTransformers(accessWidener.getTargets())); + ZipUtils.transform(jarFile, getTransformers(accessWidener.getTargets())); } catch (IOException e) { throw new UncheckedIOException("Failed to apply access wideners to %s".formatted(jarFile), e); } @@ -74,7 +75,7 @@ final class AccessWidenerTransformer { ClassWriter writer = new ClassWriter(0); ClassVisitor classVisitor = AccessWidenerClassVisitor.createClassVisitor(Constants.ASM_VERSION, writer, accessWidener); - logger.info("Applying access widener to " + className); + LOGGER.debug("Applying access widener to " + className); reader.accept(classVisitor, 0); return writer.toByteArray(); diff --git a/src/main/java/net/fabricmc/loom/configuration/accesswidener/LocalAccessWidenerEntry.java b/src/main/java/net/fabricmc/loom/configuration/accesswidener/LocalAccessWidenerEntry.java new file mode 100644 index 00000000..01546046 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/accesswidener/LocalAccessWidenerEntry.java @@ -0,0 +1,55 @@ +/* + * 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.configuration.accesswidener; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.jetbrains.annotations.Nullable; + +import net.fabricmc.accesswidener.AccessWidenerReader; +import net.fabricmc.accesswidener.AccessWidenerVisitor; +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 { + @Override + public void read(AccessWidenerVisitor visitor, LazyCloseable remapper) throws IOException { + var reader = new AccessWidenerReader(visitor); + reader.read(Files.readAllBytes(path)); + } + + @Override + public ModEnvironment environment() { + return ModEnvironment.UNIVERSAL; + } + + @Override + public @Nullable String mappingId() { + return null; + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/accesswidener/ModAccessWidenerEntry.java b/src/main/java/net/fabricmc/loom/configuration/accesswidener/ModAccessWidenerEntry.java new file mode 100644 index 00000000..14e84872 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/accesswidener/ModAccessWidenerEntry.java @@ -0,0 +1,95 @@ +/* + * 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.configuration.accesswidener; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.jetbrains.annotations.Nullable; + +import net.fabricmc.accesswidener.AccessWidenerReader; +import net.fabricmc.accesswidener.AccessWidenerRemapper; +import net.fabricmc.accesswidener.AccessWidenerVisitor; +import net.fabricmc.accesswidener.TransitiveOnlyFilter; +import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; +import net.fabricmc.loom.util.LazyCloseable; +import net.fabricmc.loom.util.fmj.FabricModJson; +import net.fabricmc.loom.util.fmj.ModEnvironment; +import net.fabricmc.tinyremapper.TinyRemapper; + +/** + * {@link AccessWidenerEntry} implementation for a {@link FabricModJson}. + */ +public record ModAccessWidenerEntry(FabricModJson mod, String path, ModEnvironment environment, boolean transitiveOnly) implements AccessWidenerEntry { + public static List readAll(FabricModJson modJson, boolean transitiveOnly) { + var entries = new ArrayList(); + + for (Map.Entry entry : modJson.getClassTweakers().entrySet()) { + entries.add(new ModAccessWidenerEntry(modJson, entry.getKey(), entry.getValue(), transitiveOnly)); + } + + return Collections.unmodifiableList(entries); + } + + @Override + public @Nullable String mappingId() { + return transitiveOnly ? mod.getId() : null; + } + + @Override + public void read(AccessWidenerVisitor visitor, LazyCloseable remapper) throws IOException { + if (transitiveOnly) { + // Filter for only transitive rules + visitor = new TransitiveOnlyFilter(visitor); + } + + final byte[] data = readRaw(); + final AccessWidenerReader.Header header = AccessWidenerReader.readHeader(data); + + if (!header.getNamespace().equals(MappingsNamespace.NAMED.toString())) { + // Remap the AW if needed + visitor = getRemapper(visitor, remapper.get()); + } + + var reader = new AccessWidenerReader(visitor); + reader.read(data); + } + + private static AccessWidenerRemapper getRemapper(AccessWidenerVisitor visitor, TinyRemapper tinyRemapper) { + return new AccessWidenerRemapper( + visitor, + tinyRemapper.getEnvironment().getRemapper(), + MappingsNamespace.INTERMEDIARY.toString(), + MappingsNamespace.NAMED.toString() + ); + } + + private byte[] readRaw() throws IOException { + return mod.getSource().read(path); + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/accesswidener/TransitiveAccessWidenerJarProcessor.java b/src/main/java/net/fabricmc/loom/configuration/accesswidener/TransitiveAccessWidenerJarProcessor.java deleted file mode 100644 index 21b1fd74..00000000 --- a/src/main/java/net/fabricmc/loom/configuration/accesswidener/TransitiveAccessWidenerJarProcessor.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * This file is part of fabric-loom, licensed under the MIT License (MIT). - * - * Copyright (c) 2020-2021 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.configuration.accesswidener; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import com.google.common.base.Preconditions; -import org.gradle.api.Project; -import org.gradle.api.artifacts.Configuration; -import org.gradle.api.artifacts.FileCollectionDependency; -import org.gradle.api.artifacts.ResolvedArtifact; -import org.gradle.api.file.FileCollection; - -import net.fabricmc.accesswidener.AccessWidener; -import net.fabricmc.accesswidener.AccessWidenerReader; -import net.fabricmc.accesswidener.AccessWidenerRemapper; -import net.fabricmc.accesswidener.AccessWidenerVisitor; -import net.fabricmc.accesswidener.TransitiveOnlyFilter; -import net.fabricmc.loom.LoomGradleExtension; -import net.fabricmc.loom.api.RemapConfigurationSettings; -import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; -import net.fabricmc.loom.configuration.ConfigContext; -import net.fabricmc.loom.configuration.processors.JarProcessor; -import net.fabricmc.loom.util.TinyRemapperHelper; -import net.fabricmc.tinyremapper.TinyRemapper; - -/** - * Applies transitive access wideners that are inherited from mod and api dependencies. - */ -public class TransitiveAccessWidenerJarProcessor implements JarProcessor { - private final ConfigContext configContext; - private final Project project; - private final LoomGradleExtension extension; - - private final List transitiveAccessWideners; - - public TransitiveAccessWidenerJarProcessor(ConfigContext configContext) { - this.configContext = configContext; - this.project = configContext.project(); - this.extension = configContext.extension(); - - transitiveAccessWideners = getTransitiveAccessWideners(); - - extension.addTransitiveAccessWideners(transitiveAccessWideners); - } - - @Override - public void setup() { - } - - public boolean isEmpty() { - return transitiveAccessWideners.isEmpty(); - } - - @Override - public String getId() { - Preconditions.checkArgument(!isEmpty()); - - return "loom:transitive_access_wideners:" + transitiveAccessWideners.hashCode(); - } - - private List getTransitiveAccessWideners() { - final List accessWideners = new ArrayList<>(); - final Set possibleModJars = new HashSet<>(); - - // Only apply global AWs from mods that are part of the compile classpath - for (RemapConfigurationSettings entry : extension.getCompileRemapConfigurations()) { - final Configuration configuration = entry.getSourceConfiguration().get(); - - // Based off the logic in ModCompileRemapper. - for (ResolvedArtifact artifact : configuration.getResolvedConfiguration().getResolvedArtifacts()) { - possibleModJars.add(artifact.getFile().toPath()); - } - - for (FileCollectionDependency dependency : configuration.getAllDependencies().withType(FileCollectionDependency.class)) { - FileCollection files = dependency.getFiles(); - - for (File artifact : files) { - possibleModJars.add(artifact.toPath()); - } - } - } - - for (Path path : possibleModJars) { - if (!Files.exists(path)) { - project.getLogger().debug("Could not find transitive access widener in {} as it does not exist", path.toAbsolutePath()); - continue; - } - - AccessWidenerFile accessWidener = AccessWidenerFile.fromModJar(path); - - if (accessWidener == null) { - continue; - } - - if (!TransitiveDetectorVisitor.isTransitive(accessWidener.content())) { - // AW does not contain anything transitive, skip over it - continue; - } - - accessWideners.add(accessWidener); - } - - return accessWideners; - } - - @Override - public void process(File file) { - Preconditions.checkArgument(!isEmpty()); - - AccessWidener accessWidener = createAccessWidener(); - AccessWidenerTransformer transformer = new AccessWidenerTransformer(project.getLogger(), accessWidener); - transformer.apply(file); - } - - private AccessWidener createAccessWidener() { - AccessWidener accessWidener = new AccessWidener(); - // For other mods, only consider transitive AWs and remap from intermediary->named - TinyRemapper tinyRemapper = createTinyRemapper(); - - try { - AccessWidenerRemapper remappingVisitor = new AccessWidenerRemapper( - accessWidener, - tinyRemapper.getEnvironment().getRemapper(), - MappingsNamespace.INTERMEDIARY.toString(), - MappingsNamespace.NAMED.toString() - ); - AccessWidenerReader transitiveReader = new AccessWidenerReader(new TransitiveOnlyFilter(remappingVisitor)); - - for (AccessWidenerFile accessWidenerFile : transitiveAccessWideners) { - project.getLogger().info("Reading transitive access widener from {}", accessWidenerFile.modId()); - transitiveReader.read(accessWidenerFile.content()); - } - } finally { - tinyRemapper.finish(); - } - - return accessWidener; - } - - private TinyRemapper createTinyRemapper() { - try { - TinyRemapper tinyRemapper = TinyRemapperHelper.getTinyRemapper(project, configContext.serviceManager(), "intermediary", "named"); - - tinyRemapper.readClassPath(TinyRemapperHelper.getMinecraftDependencies(project)); - - for (Path minecraftJar : extension.getMinecraftJars(MappingsNamespace.INTERMEDIARY)) { - tinyRemapper.readClassPath(minecraftJar); - } - - return tinyRemapper; - } catch (IOException e) { - throw new RuntimeException("Failed to create tiny remapper for intermediary->named", e); - } - } - - private static class TransitiveDetectorVisitor implements AccessWidenerVisitor { - private boolean transitive = false; - - @Override - public void visitClass(String name, AccessWidenerReader.AccessType access, boolean transitive) { - if (transitive) { - this.transitive = true; - } - } - - @Override - public void visitMethod(String owner, String name, String descriptor, AccessWidenerReader.AccessType access, boolean transitive) { - if (transitive) { - this.transitive = true; - } - } - - @Override - public void visitField(String owner, String name, String descriptor, AccessWidenerReader.AccessType access, boolean transitive) { - if (transitive) { - this.transitive = true; - } - } - - public static boolean isTransitive(byte[] content) { - if (AccessWidenerReader.readVersion(content) < 2) { - // Transitive AWs are only in v2 or higher, so we can save parsing the file to find out... - return false; - } - - TransitiveDetectorVisitor transitiveDetector = new TransitiveDetectorVisitor(); - new AccessWidenerReader(transitiveDetector).read(content); - return transitiveDetector.transitive; - } - } -} diff --git a/src/main/java/net/fabricmc/loom/configuration/accesswidener/TransitiveAccessWidenerMappingsProcessor.java b/src/main/java/net/fabricmc/loom/configuration/accesswidener/TransitiveAccessWidenerMappingsProcessor.java index da82d8f1..e7197b7b 100644 --- a/src/main/java/net/fabricmc/loom/configuration/accesswidener/TransitiveAccessWidenerMappingsProcessor.java +++ b/src/main/java/net/fabricmc/loom/configuration/accesswidener/TransitiveAccessWidenerMappingsProcessor.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2021-2022 FabricMC + * Copyright (c) 2021-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 @@ -24,25 +24,34 @@ package net.fabricmc.loom.configuration.accesswidener; +import java.io.IOException; +import java.io.UncheckedIOException; import java.util.List; -import org.gradle.api.Project; -import org.gradle.api.logging.Logger; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import net.fabricmc.accesswidener.AccessWidenerReader; import net.fabricmc.accesswidener.AccessWidenerVisitor; -import net.fabricmc.accesswidener.TransitiveOnlyFilter; -import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; -import net.fabricmc.loom.task.GenerateSourcesTask; +import net.fabricmc.loom.api.processor.MappingProcessorContext; +import net.fabricmc.loom.api.processor.MinecraftJarProcessor; +import net.fabricmc.loom.util.LazyCloseable; import net.fabricmc.mappingio.tree.MappingTree; import net.fabricmc.mappingio.tree.MemoryMappingTree; +import net.fabricmc.tinyremapper.TinyRemapper; + +public final class TransitiveAccessWidenerMappingsProcessor implements MinecraftJarProcessor.MappingsProcessor { + public static final TransitiveAccessWidenerMappingsProcessor INSTANCE = new TransitiveAccessWidenerMappingsProcessor(); + + private TransitiveAccessWidenerMappingsProcessor() { + } -public record TransitiveAccessWidenerMappingsProcessor(Project project) implements GenerateSourcesTask.MappingsProcessor { @Override - public boolean transform(MemoryMappingTree mappings) { - final LoomGradleExtension extension = LoomGradleExtension.get(project); - List accessWideners = extension.getTransitiveAccessWideners(); + public boolean transform(MemoryMappingTree mappings, AccessWidenerJarProcessor.Spec spec, MappingProcessorContext context) { + final List accessWideners = spec.accessWideners().stream() + .filter(entry -> entry.mappingId() != null) + .toList(); if (accessWideners.isEmpty()) { return false; @@ -52,22 +61,27 @@ public record TransitiveAccessWidenerMappingsProcessor(Project project) implemen throw new IllegalStateException("Mapping tree must have intermediary src mappings not " + mappings.getSrcNamespace()); } - for (AccessWidenerFile accessWidener : accessWideners) { - MappingCommentVisitor mappingCommentVisitor = new MappingCommentVisitor(accessWidener.modId(), mappings, project.getLogger()); - AccessWidenerReader accessWidenerReader = new AccessWidenerReader(new TransitiveOnlyFilter(mappingCommentVisitor)); - accessWidenerReader.read(accessWidener.content()); + try (LazyCloseable remapper = context.createRemapper(MappingsNamespace.INTERMEDIARY, MappingsNamespace.NAMED)) { + for (AccessWidenerEntry accessWidener : accessWideners) { + var visitor = new MappingCommentVisitor(accessWidener.mappingId(), mappings); + accessWidener.read(visitor, remapper); + } + } catch (IOException e) { + throw new UncheckedIOException("Failed to transform access widener mappings", e); } return true; } - private record MappingCommentVisitor(String modId, MemoryMappingTree mappingTree, Logger logger) implements AccessWidenerVisitor { + private record MappingCommentVisitor(String modId, MemoryMappingTree mappingTree) implements AccessWidenerVisitor { + private static final Logger LOGGER = LoggerFactory.getLogger(MappingCommentVisitor.class); + @Override public void visitClass(String name, AccessWidenerReader.AccessType access, boolean transitive) { MappingTree.ClassMapping classMapping = mappingTree.getClass(name); if (classMapping == null) { - logger.info("Failed to find class ({}) to mark access widened by mod ({})", name, modId()); + LOGGER.info("Failed to find class ({}) to mark access widened by mod ({})", name, modId()); return; } @@ -82,14 +96,14 @@ public record TransitiveAccessWidenerMappingsProcessor(Project project) implemen MappingTree.ClassMapping classMapping = mappingTree.getClass(owner); if (classMapping == null) { - logger.info("Failed to find class ({}) to mark access widened by mod ({})", owner, modId()); + LOGGER.info("Failed to find class ({}) to mark access widened by mod ({})", owner, modId()); return; } MappingTree.MethodMapping methodMapping = classMapping.getMethod(name, descriptor); if (methodMapping == null) { - logger.info("Failed to find method ({}) in ({}) to mark access widened by mod ({})", name, owner, modId()); + LOGGER.info("Failed to find method ({}) in ({}) to mark access widened by mod ({})", name, owner, modId()); return; } @@ -104,14 +118,14 @@ public record TransitiveAccessWidenerMappingsProcessor(Project project) implemen MappingTree.ClassMapping classMapping = mappingTree.getClass(owner); if (classMapping == null) { - logger.info("Failed to find class ({}) to mark access widened by mod ({})", name, modId()); + LOGGER.info("Failed to find class ({}) to mark access widened by mod ({})", name, modId()); return; } MappingTree.FieldMapping fieldMapping = classMapping.getField(name, descriptor); if (fieldMapping == null) { - logger.info("Failed to find field ({}) in ({}) to mark access widened by mod ({})", name, owner, modId()); + LOGGER.info("Failed to find field ({}) in ({}) to mark access widened by mod ({})", name, owner, modId()); return; } diff --git a/src/main/java/net/fabricmc/loom/configuration/ifaceinject/InterfaceInjectionProcessor.java b/src/main/java/net/fabricmc/loom/configuration/ifaceinject/InterfaceInjectionProcessor.java index 585e2c1f..77ba7403 100644 --- a/src/main/java/net/fabricmc/loom/configuration/ifaceinject/InterfaceInjectionProcessor.java +++ b/src/main/java/net/fabricmc/loom/configuration/ifaceinject/InterfaceInjectionProcessor.java @@ -56,7 +56,6 @@ import net.fabricmc.loom.util.Pair; import net.fabricmc.loom.util.ZipUtils; import net.fabricmc.loom.util.fmj.FabricModJson; import net.fabricmc.mappingio.tree.MappingTree; -import net.fabricmc.tinyremapper.TinyRemapper; public abstract class InterfaceInjectionProcessor implements MinecraftJarProcessor { private static final Logger LOGGER = LoggerFactory.getLogger(InterfaceInjectionProcessor.class); @@ -99,17 +98,15 @@ public abstract class InterfaceInjectionProcessor implements MinecraftJarProcess @Override public void processJar(Path jar, Spec spec, ProcessorContext context) throws IOException { - // Remap from intermediary->named - final TinyRemapper tinyRemapper = context.createRemapper(MappingsNamespace.INTERMEDIARY, MappingsNamespace.NAMED); - final Remapper remapper = tinyRemapper.getEnvironment().getRemapper(); final List remappedInjectedInterfaces; - try { + // Remap from intermediary->named + try (var tinyRemapper = context.createRemapper(MappingsNamespace.INTERMEDIARY, MappingsNamespace.NAMED)) { + final Remapper remapper = tinyRemapper.get().getEnvironment().getRemapper(); + remappedInjectedInterfaces = spec.injectedInterfaces().stream() .map(injectedInterface -> remap(injectedInterface, remapper)) .toList(); - } finally { - tinyRemapper.finish(); } try { diff --git a/src/main/java/net/fabricmc/loom/configuration/processors/ContextImplHelper.java b/src/main/java/net/fabricmc/loom/configuration/processors/ContextImplHelper.java new file mode 100644 index 00000000..37fe9c26 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/processors/ContextImplHelper.java @@ -0,0 +1,57 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2022-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.configuration.processors; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Path; + +import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; +import net.fabricmc.loom.configuration.ConfigContext; +import net.fabricmc.loom.util.LazyCloseable; +import net.fabricmc.loom.util.TinyRemapperHelper; +import net.fabricmc.tinyremapper.TinyRemapper; + +public final class ContextImplHelper { + private ContextImplHelper() { + } + + public static LazyCloseable createRemapper(ConfigContext configContext, MappingsNamespace from, MappingsNamespace to) { + return new LazyCloseable<>(() -> { + try { + TinyRemapper tinyRemapper = TinyRemapperHelper.getTinyRemapper(configContext.project(), configContext.serviceManager(), from.toString(), to.toString()); + tinyRemapper.readClassPath(TinyRemapperHelper.getMinecraftDependencies(configContext.project())); + + for (Path minecraftJar : configContext.extension().getMinecraftJars(MappingsNamespace.INTERMEDIARY)) { + tinyRemapper.readClassPath(minecraftJar); + } + + return tinyRemapper; + } catch (IOException e) { + throw new UncheckedIOException("Failed to create tiny remapper", e); + } + }, TinyRemapper::finish); + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/processors/MappingProcessorContextImpl.java b/src/main/java/net/fabricmc/loom/configuration/processors/MappingProcessorContextImpl.java new file mode 100644 index 00000000..6a1ba3a5 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/processors/MappingProcessorContextImpl.java @@ -0,0 +1,38 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2022-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.configuration.processors; + +import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; +import net.fabricmc.loom.api.processor.MappingProcessorContext; +import net.fabricmc.loom.configuration.ConfigContext; +import net.fabricmc.loom.util.LazyCloseable; +import net.fabricmc.tinyremapper.TinyRemapper; + +public record MappingProcessorContextImpl(ConfigContext configContext) implements MappingProcessorContext { + @Override + public LazyCloseable createRemapper(MappingsNamespace from, MappingsNamespace to) { + return ContextImplHelper.createRemapper(configContext, from, to); + } +} diff --git a/src/main/java/net/fabricmc/loom/configuration/processors/ProcessorContextImpl.java b/src/main/java/net/fabricmc/loom/configuration/processors/ProcessorContextImpl.java index f8a2e116..15f2d3ca 100644 --- a/src/main/java/net/fabricmc/loom/configuration/processors/ProcessorContextImpl.java +++ b/src/main/java/net/fabricmc/loom/configuration/processors/ProcessorContextImpl.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2022 FabricMC + * Copyright (c) 2022-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 @@ -24,16 +24,12 @@ package net.fabricmc.loom.configuration.processors; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Path; - import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; import net.fabricmc.loom.api.processor.ProcessorContext; import net.fabricmc.loom.configuration.ConfigContext; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJar; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration; -import net.fabricmc.loom.util.TinyRemapperHelper; +import net.fabricmc.loom.util.LazyCloseable; import net.fabricmc.tinyremapper.TinyRemapper; public record ProcessorContextImpl(ConfigContext configContext, MinecraftJar minecraftJar) implements ProcessorContext { @@ -58,18 +54,7 @@ public record ProcessorContextImpl(ConfigContext configContext, MinecraftJar min } @Override - public TinyRemapper createRemapper(MappingsNamespace from, MappingsNamespace to) { - try { - TinyRemapper tinyRemapper = TinyRemapperHelper.getTinyRemapper(configContext().project(), configContext().serviceManager(), from.toString(), to.toString()); - tinyRemapper.readClassPath(TinyRemapperHelper.getMinecraftDependencies(configContext.project())); - - for (Path minecraftJar : configContext.extension().getMinecraftJars(MappingsNamespace.INTERMEDIARY)) { - tinyRemapper.readClassPath(minecraftJar); - } - - return tinyRemapper; - } catch (IOException e) { - throw new UncheckedIOException("Failed to create tiny remapper", e); - } + public LazyCloseable createRemapper(MappingsNamespace from, MappingsNamespace to) { + return ContextImplHelper.createRemapper(configContext, from, to); } } diff --git a/src/main/java/net/fabricmc/loom/configuration/processors/SpecContextImpl.java b/src/main/java/net/fabricmc/loom/configuration/processors/SpecContextImpl.java index 1ad69b72..cc23c801 100644 --- a/src/main/java/net/fabricmc/loom/configuration/processors/SpecContextImpl.java +++ b/src/main/java/net/fabricmc/loom/configuration/processors/SpecContextImpl.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2022 FabricMC + * Copyright (c) 2022-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 @@ -25,8 +25,6 @@ package net.fabricmc.loom.configuration.processors; import java.io.File; -import java.io.IOException; -import java.io.UncheckedIOException; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; @@ -41,7 +39,6 @@ import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.ProjectDependency; import org.gradle.api.plugins.JavaPlugin; -import org.gradle.api.tasks.SourceSet; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.api.RemapConfigurationSettings; @@ -49,8 +46,8 @@ import net.fabricmc.loom.api.processor.SpecContext; import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.fmj.FabricModJson; import net.fabricmc.loom.util.fmj.FabricModJsonFactory; +import net.fabricmc.loom.util.fmj.FabricModJsonHelpers; import net.fabricmc.loom.util.gradle.GradleUtils; -import net.fabricmc.loom.util.gradle.SourceSetHelper; /** * @param modDependencies External mods that are depended on @@ -59,7 +56,7 @@ import net.fabricmc.loom.util.gradle.SourceSetHelper; */ public record SpecContextImpl(List modDependencies, List localMods, List compileRuntimeMods) implements SpecContext { public static SpecContextImpl create(Project project) { - return new SpecContextImpl(getDependentMods(project), getModsInProject(project), getCompileRuntimeMods(project)); + return new SpecContextImpl(getDependentMods(project), FabricModJsonHelpers.getModsInProject(project), getCompileRuntimeMods(project)); } // Reruns a list of mods found on both the compile and/or runtime classpaths @@ -82,7 +79,7 @@ public record SpecContextImpl(List modDependencies, List modDependencies, List getModsInProject(Project project) { - final LoomGradleExtension extension = LoomGradleExtension.get(project); - var sourceSets = new ArrayList(); - sourceSets.add(SourceSetHelper.getMainSourceSet(project)); - - if (extension.areEnvironmentSourceSetsSplit()) { - sourceSets.add(SourceSetHelper.getSourceSetByName("client", project)); - } - - try { - final FabricModJson fabricModJson = FabricModJsonFactory.createFromSourceSetsNullable(sourceSets.toArray(SourceSet[]::new)); - - if (fabricModJson != null) { - return List.of(fabricModJson); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - - return Collections.emptyList(); - } - // Returns a list of mods that are on both to compile and runtime classpath private static List getCompileRuntimeMods(Project project) { var mods = new ArrayList<>(getCompileRuntimeModsFromRemapConfigs(project).toList()); for (Project dependentProject : getCompileRuntimeProjectDependencies(project).toList()) { - mods.addAll(getModsInProject(dependentProject)); + mods.addAll(FabricModJsonHelpers.getModsInProject(dependentProject)); } return Collections.unmodifiableList(mods); diff --git a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java index cebfaf08..847fd3b5 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java @@ -143,10 +143,6 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA // Add main source set by default interfaceInjection(interfaceInjection -> { - final SourceSet main = SourceSetHelper.getMainSourceSet(project); - interfaceInjection.getInterfaceInjectionSourceSets().add(main); - - interfaceInjection.getInterfaceInjectionSourceSets().finalizeValueOnRead(); interfaceInjection.getEnableDependencyInterfaceInjection().convention(true).finalizeValueOnRead(); }); } diff --git a/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java b/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java index 45a60488..1c2fec3c 100644 --- a/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java +++ b/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java @@ -64,8 +64,8 @@ import net.fabricmc.loom.api.decompilers.DecompilationMetadata; import net.fabricmc.loom.api.decompilers.DecompilerOptions; import net.fabricmc.loom.api.decompilers.LoomDecompiler; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; -import net.fabricmc.loom.api.processor.MappingProcessorContext; -import net.fabricmc.loom.configuration.accesswidener.TransitiveAccessWidenerMappingsProcessor; +import net.fabricmc.loom.configuration.ConfigContextImpl; +import net.fabricmc.loom.configuration.processors.MappingProcessorContextImpl; import net.fabricmc.loom.configuration.processors.MinecraftJarProcessorManager; import net.fabricmc.loom.decompilers.LineNumberRemapper; import net.fabricmc.loom.util.Constants; @@ -77,6 +77,7 @@ import net.fabricmc.loom.util.gradle.ThreadedSimpleProgressLogger; import net.fabricmc.loom.util.gradle.WorkerDaemonClientsManagerHelper; import net.fabricmc.loom.util.ipc.IPCClient; import net.fabricmc.loom.util.ipc.IPCServer; +import net.fabricmc.loom.util.service.ScopedSharedServiceManager; import net.fabricmc.mappingio.MappingReader; import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch; import net.fabricmc.mappingio.format.Tiny2Writer; @@ -330,14 +331,15 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask { final List mappingsProcessors = new ArrayList<>(); - if (getExtension().getEnableTransitiveAccessWideners().get()) { - mappingsProcessors.add(new TransitiveAccessWidenerMappingsProcessor(getProject())); - } - MinecraftJarProcessorManager minecraftJarProcessorManager = MinecraftJarProcessorManager.create(getProject()); if (minecraftJarProcessorManager != null) { - mappingsProcessors.add(mappings -> minecraftJarProcessorManager.processMappings(mappings, new MappingProcessorContextImpl())); + mappingsProcessors.add(mappings -> { + try (var serviceManager = new ScopedSharedServiceManager()) { + final var configContext = new ConfigContextImpl(getProject(), serviceManager, getExtension()); + return minecraftJarProcessorManager.processMappings(mappings, new MappingProcessorContextImpl(configContext)); + } + }); } if (mappingsProcessors.isEmpty()) { @@ -388,7 +390,4 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask { throw new RuntimeException(e); } } - - private static class MappingProcessorContextImpl implements MappingProcessorContext { - } } diff --git a/src/main/java/net/fabricmc/loom/util/DeprecationHelper.java b/src/main/java/net/fabricmc/loom/util/DeprecationHelper.java index 9ddbfb69..ea1f8f46 100644 --- a/src/main/java/net/fabricmc/loom/util/DeprecationHelper.java +++ b/src/main/java/net/fabricmc/loom/util/DeprecationHelper.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2021 FabricMC + * Copyright (c) 2021-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 @@ -35,10 +35,18 @@ public interface DeprecationHelper { toBeRemovedIn(currentName, newName, "Loom 2.0"); } + default void removedInLoom2_0(String currentName) { + toBeRemovedIn(currentName, "Loom 2.0"); + } + default void toBeRemovedIn(String currentName, String newName, String removalVersion) { warn("The '%s' property has been deprecated, and has been replaced with '%s'. This is scheduled to be removed in %s.".formatted(currentName, newName, removalVersion)); } + default void toBeRemovedIn(String currentName, String removalVersion) { + warn("The '%s' property has been deprecated, and can be removed. This is scheduled to be removed in %s.".formatted(currentName, removalVersion)); + } + Project getProject(); void warn(String warning); diff --git a/src/main/java/net/fabricmc/loom/util/LazyCloseable.java b/src/main/java/net/fabricmc/loom/util/LazyCloseable.java new file mode 100644 index 00000000..50c7f7e8 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/util/LazyCloseable.java @@ -0,0 +1,58 @@ +/* + * 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.util; + +import java.io.Closeable; +import java.io.IOException; +import java.util.function.Consumer; +import java.util.function.Supplier; + +// Not thread safe +public class LazyCloseable implements Closeable { + private final Supplier valueSupplier; + private final Consumer closeConsumer; + private T value; + + public LazyCloseable(Supplier valueSupplier, Consumer closeConsumer) { + this.valueSupplier = valueSupplier; + this.closeConsumer = closeConsumer; + } + + public T get() { + if (value == null) { + value = valueSupplier.get(); + } + + return value; + } + + @Override + public void close() throws IOException { + if (value != null) { + closeConsumer.accept(value); + value = null; + } + } +} diff --git a/src/main/java/net/fabricmc/loom/util/fmj/FabricModJsonHelpers.java b/src/main/java/net/fabricmc/loom/util/fmj/FabricModJsonHelpers.java new file mode 100644 index 00000000..923c7a30 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/util/fmj/FabricModJsonHelpers.java @@ -0,0 +1,62 @@ +/* + * 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.util.fmj; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.gradle.api.Project; +import org.gradle.api.tasks.SourceSet; + +import net.fabricmc.loom.LoomGradleExtension; +import net.fabricmc.loom.util.gradle.SourceSetHelper; + +public class FabricModJsonHelpers { + // Returns a list of Mods found in the provided project's main or client sourcesets + public static List getModsInProject(Project project) { + final LoomGradleExtension extension = LoomGradleExtension.get(project); + var sourceSets = new ArrayList(); + sourceSets.add(SourceSetHelper.getMainSourceSet(project)); + + if (extension.areEnvironmentSourceSetsSplit()) { + sourceSets.add(SourceSetHelper.getSourceSetByName("client", project)); + } + + try { + final FabricModJson fabricModJson = FabricModJsonFactory.createFromSourceSetsNullable(sourceSets.toArray(SourceSet[]::new)); + + if (fabricModJson != null) { + return List.of(fabricModJson); + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + + return Collections.emptyList(); + } +} diff --git a/src/main/java/net/fabricmc/loom/util/fmj/FabricModJsonSource.java b/src/main/java/net/fabricmc/loom/util/fmj/FabricModJsonSource.java index 0da5fe98..9ff5a7d6 100644 --- a/src/main/java/net/fabricmc/loom/util/fmj/FabricModJsonSource.java +++ b/src/main/java/net/fabricmc/loom/util/fmj/FabricModJsonSource.java @@ -59,13 +59,17 @@ public interface FabricModJsonSource { record SourceSetSource(SourceSet... sourceSets) implements FabricModJsonSource { @Override public byte[] read(String path) throws IOException { + return Files.readAllBytes(findFile(path).toPath()); + } + + private File findFile(String path) throws IOException { final File file = SourceSetHelper.findFirstFileInResource(path, sourceSets); if (file == null) { throw new FileNotFoundException("Could not find: " + path); } - return Files.readAllBytes(file.toPath()); + return file; } } } From 60d4dac6ca28dfb163f6c4baebad24f6f33ea422 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Wed, 11 Jan 2023 10:54:03 +0000 Subject: [PATCH 2/9] Support MinimalExternalModuleDependency's as a FileSpec input (#785) --- .../api/mappings/layered/MappingContext.java | 3 ++ .../api/mappings/layered/spec/FileSpec.java | 11 +++- .../mappings/GradleMappingContext.java | 6 +++ ...nimalExternalModuleDependencyFileSpec.java | 54 +++++++++++++++++++ .../LayeredMappingsSpecification.groovy | 8 ++- .../resources/projects/parchment/build.gradle | 8 +-- .../parchment/gradle/libs.versions.toml | 9 ++++ 7 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 src/main/java/net/fabricmc/loom/configuration/providers/mappings/utils/MinimalExternalModuleDependencyFileSpec.java create mode 100644 src/test/resources/projects/parchment/gradle/libs.versions.toml diff --git a/src/main/java/net/fabricmc/loom/api/mappings/layered/MappingContext.java b/src/main/java/net/fabricmc/loom/api/mappings/layered/MappingContext.java index 6c5c0157..ebb1c394 100644 --- a/src/main/java/net/fabricmc/loom/api/mappings/layered/MappingContext.java +++ b/src/main/java/net/fabricmc/loom/api/mappings/layered/MappingContext.java @@ -28,6 +28,7 @@ import java.nio.file.Path; import java.util.function.Supplier; import org.gradle.api.artifacts.Dependency; +import org.gradle.api.artifacts.MinimalExternalModuleDependency; import org.gradle.api.logging.Logger; import org.jetbrains.annotations.ApiStatus; @@ -39,6 +40,8 @@ import net.fabricmc.mappingio.tree.MemoryMappingTree; public interface MappingContext { Path resolveDependency(Dependency dependency); + Path resolveDependency(MinimalExternalModuleDependency dependency); + Path resolveMavenDependency(String mavenNotation); Supplier intermediaryTree(); diff --git a/src/main/java/net/fabricmc/loom/api/mappings/layered/spec/FileSpec.java b/src/main/java/net/fabricmc/loom/api/mappings/layered/spec/FileSpec.java index c8b6157e..bbc5d587 100644 --- a/src/main/java/net/fabricmc/loom/api/mappings/layered/spec/FileSpec.java +++ b/src/main/java/net/fabricmc/loom/api/mappings/layered/spec/FileSpec.java @@ -31,6 +31,7 @@ import java.nio.file.Path; import java.util.Objects; import org.gradle.api.artifacts.Dependency; +import org.gradle.api.artifacts.MinimalExternalModuleDependency; import org.gradle.api.file.FileSystemLocation; import org.gradle.api.file.RegularFileProperty; import org.gradle.api.provider.Provider; @@ -38,9 +39,10 @@ import org.jetbrains.annotations.ApiStatus; import net.fabricmc.loom.api.mappings.layered.MappingContext; import net.fabricmc.loom.configuration.providers.mappings.utils.DependencyFileSpec; -import net.fabricmc.loom.configuration.providers.mappings.utils.URLFileSpec; import net.fabricmc.loom.configuration.providers.mappings.utils.LocalFileSpec; import net.fabricmc.loom.configuration.providers.mappings.utils.MavenFileSpec; +import net.fabricmc.loom.configuration.providers.mappings.utils.MinimalExternalModuleDependencyFileSpec; +import net.fabricmc.loom.configuration.providers.mappings.utils.URLFileSpec; /** * FileSpec should be used in MappingsSpec's that take an input file. The input file can either be a local file or a gradle dep. @@ -56,6 +58,7 @@ public interface FileSpec { *
  • {@link Provider} (including {@link org.gradle.api.provider.Property}) will recursively be resolved as its current value
  • *
  • {@link CharSequence} (including {@link String} and {@link groovy.lang.GString}) will be resolved as Maven dependencies
  • *
  • {@link Dependency} will be resolved as any dependency
  • + *
  • {@link MinimalExternalModuleDependency} will be resolved as any dependency
  • *
  • {@code FileSpec} will just return the spec itself
  • * * @@ -75,6 +78,8 @@ public interface FileSpec { } return createFromMavenDependency(s.toString()); + } else if (o instanceof MinimalExternalModuleDependency d) { + return createFromMinimalExternalModuleDependency(d); } else if (o instanceof Dependency d) { return createFromDependency(d); } else if (o instanceof Provider p) { @@ -123,5 +128,9 @@ public interface FileSpec { return createFromFile(regularFileProperty.get()); } + static FileSpec createFromMinimalExternalModuleDependency(MinimalExternalModuleDependency externalModuleDependency) { + return new MinimalExternalModuleDependencyFileSpec(externalModuleDependency); + } + Path get(MappingContext context); } diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/GradleMappingContext.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/GradleMappingContext.java index 88ede35c..4fd53a3a 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/GradleMappingContext.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/GradleMappingContext.java @@ -31,6 +31,7 @@ import java.util.function.Supplier; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.Dependency; +import org.gradle.api.artifacts.MinimalExternalModuleDependency; import org.gradle.api.artifacts.ResolutionStrategy; import org.gradle.api.logging.Logger; @@ -65,6 +66,11 @@ public class GradleMappingContext implements MappingContext { return resolveDependency(project.getDependencies().create(mavenNotation)); } + @Override + public Path resolveDependency(MinimalExternalModuleDependency dependency) { + return resolveDependency(project.getDependencies().create(dependency)); + } + @Override public Supplier intermediaryTree() { return () -> { diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/utils/MinimalExternalModuleDependencyFileSpec.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/utils/MinimalExternalModuleDependencyFileSpec.java new file mode 100644 index 00000000..8e772a06 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/utils/MinimalExternalModuleDependencyFileSpec.java @@ -0,0 +1,54 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2022 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.configuration.providers.mappings.utils; + +import java.nio.file.Path; +import java.util.Objects; + +import org.gradle.api.artifacts.MinimalExternalModuleDependency; + +import net.fabricmc.loom.api.mappings.layered.MappingContext; +import net.fabricmc.loom.api.mappings.layered.spec.FileSpec; + +public record MinimalExternalModuleDependencyFileSpec(MinimalExternalModuleDependency dependency) implements FileSpec { + @Override + public Path get(MappingContext context) { + return context.resolveDependency(dependency); + } + + @Override + public int hashCode() { + return Objects.hash(dependency.getModule().getGroup(), dependency.getModule().getName(), dependency.getVersionConstraint()); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof MinimalExternalModuleDependencyFileSpec other) { + return other.dependency().equals(this.dependency()); + } + + return false; + } +} diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingsSpecification.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingsSpecification.groovy index da3d5b56..b5069bf0 100644 --- a/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingsSpecification.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/unit/layeredmappings/LayeredMappingsSpecification.groovy @@ -41,6 +41,7 @@ import net.fabricmc.mappingio.adapter.MappingSourceNsSwitch import net.fabricmc.mappingio.format.Tiny2Writer import net.fabricmc.mappingio.tree.MemoryMappingTree import org.gradle.api.artifacts.Dependency +import org.gradle.api.artifacts.MinimalExternalModuleDependency import org.gradle.api.logging.Logger import spock.lang.Specification @@ -123,7 +124,12 @@ abstract class LayeredMappingsSpecification extends Specification implements Lay throw new UnsupportedOperationException("TODO") } - @Override + @Override + Path resolveDependency(MinimalExternalModuleDependency dependency) { + throw new UnsupportedOperationException("TODO") + } + + @Override Path resolveMavenDependency(String mavenNotation) { assert mavenFiles.containsKey(mavenNotation) return mavenFiles.get(mavenNotation).toPath() diff --git a/src/test/resources/projects/parchment/build.gradle b/src/test/resources/projects/parchment/build.gradle index 21432d4e..5fee81c5 100644 --- a/src/test/resources/projects/parchment/build.gradle +++ b/src/test/resources/projects/parchment/build.gradle @@ -10,11 +10,13 @@ repositories { } dependencies { - minecraft "com.mojang:minecraft:1.16.5" + minecraft libs.minecraft mappings loom.layered() { officialMojangMappings() - parchment("org.parchmentmc.data:parchment-1.16.5:2021.10.10@zip") + parchment variantOf(libs.parchment) { + artifactType("zip") + } } - modImplementation "net.fabricmc:fabric-loader:0.11.3" + modImplementation libs.fabricLoader } diff --git a/src/test/resources/projects/parchment/gradle/libs.versions.toml b/src/test/resources/projects/parchment/gradle/libs.versions.toml new file mode 100644 index 00000000..40c22f78 --- /dev/null +++ b/src/test/resources/projects/parchment/gradle/libs.versions.toml @@ -0,0 +1,9 @@ +[versions] +minecraft = "1.16.5" +fabricLoader = "0.11.3" +parchment = "2021.10.10" + +[libraries] +minecraft = { module = "com.mojang:minecraft", version.ref = "minecraft" } +fabricLoader = { module = "net.fabricmc:fabric-loader", version.ref = "fabricLoader" } +parchment = { module = "org.parchmentmc.data:parchment-1.16.5", version.ref = "parchment" } \ No newline at end of file From 7586911af85ed3ed572d700ecde8d2bbb0668894 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Wed, 11 Jan 2023 19:36:02 +0000 Subject: [PATCH 3/9] Fix #789 --- src/main/java/net/fabricmc/loom/task/UnpickJarTask.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/net/fabricmc/loom/task/UnpickJarTask.java b/src/main/java/net/fabricmc/loom/task/UnpickJarTask.java index 3ac72fec..22825794 100644 --- a/src/main/java/net/fabricmc/loom/task/UnpickJarTask.java +++ b/src/main/java/net/fabricmc/loom/task/UnpickJarTask.java @@ -69,6 +69,7 @@ public abstract class UnpickJarTask extends JavaExec { getConstantJar().setFrom(getProject().getConfigurations().getByName(Constants.Configurations.MAPPING_CONSTANTS)); getUnpickClasspath().setFrom(getProject().getConfigurations().getByName(Constants.Configurations.MINECRAFT_DEPENDENCIES)); + getUnpickClasspath().from(getProject().getConfigurations().getByName(Constants.Configurations.MOD_COMPILE_CLASSPATH_MAPPED)); } @Override From 2b9072f37d8d20595a778dd2da89fbb0892340bd Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Mon, 16 Jan 2023 18:19:48 +0000 Subject: [PATCH 4/9] Add RemapConfigurationSettings.getApplyDependencyTransforms to close #797 (#799) --- .../fabricmc/loom/api/RemapConfigurationSettings.java | 10 ++++++++++ .../loom/configuration/processors/SpecContextImpl.java | 2 ++ 2 files changed, 12 insertions(+) diff --git a/src/main/java/net/fabricmc/loom/api/RemapConfigurationSettings.java b/src/main/java/net/fabricmc/loom/api/RemapConfigurationSettings.java index cd88e5a9..b1b00e0b 100644 --- a/src/main/java/net/fabricmc/loom/api/RemapConfigurationSettings.java +++ b/src/main/java/net/fabricmc/loom/api/RemapConfigurationSettings.java @@ -60,6 +60,7 @@ public abstract class RemapConfigurationSettings implements Named { getOnCompileClasspath().finalizeValueOnRead(); getOnRuntimeClasspath().finalizeValueOnRead(); getPublishingMode().convention(PublishingMode.NONE).finalizeValueOnRead(); + getApplyDependencyTransforms().convention(defaultDependencyTransforms()).finalizeValueOnRead(); } @Override @@ -100,6 +101,11 @@ public abstract class RemapConfigurationSettings implements Named { */ public abstract Property getPublishingMode(); + /** + * @return true when dependencies should be evaluated for minecraft jar transforms such as transitive Access Wideners or Injected interfaces. + */ + public abstract Property getApplyDependencyTransforms(); + public enum PublishingMode { NONE, COMPILE_ONLY(JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME), @@ -174,4 +180,8 @@ public abstract class RemapConfigurationSettings implements Named { private NamedDomainObjectProvider getConfigurationByName(String name) { return getProject().getConfigurations().named(name); } + + private Provider defaultDependencyTransforms() { + return getSourceSet().map(sourceSet -> sourceSet.getName().equals(SourceSet.MAIN_SOURCE_SET_NAME) || sourceSet.getName().equals("client")); + } } diff --git a/src/main/java/net/fabricmc/loom/configuration/processors/SpecContextImpl.java b/src/main/java/net/fabricmc/loom/configuration/processors/SpecContextImpl.java index cc23c801..bc26a01b 100644 --- a/src/main/java/net/fabricmc/loom/configuration/processors/SpecContextImpl.java +++ b/src/main/java/net/fabricmc/loom/configuration/processors/SpecContextImpl.java @@ -113,10 +113,12 @@ public record SpecContextImpl(List modDependencies, List runtimeEntries = extension.getRuntimeRemapConfigurations().stream() + .filter(settings -> settings.getApplyDependencyTransforms().get()) .flatMap(resolve) .toList(); return extension.getCompileRemapConfigurations().stream() + .filter(settings -> settings.getApplyDependencyTransforms().get()) .flatMap(resolve) .filter(runtimeEntries::contains) // Use the intersection of the two configurations. .map(FabricModJsonFactory::createFromZipOptional) From 2d10e42f4dd3e8e1becb8885a17f261313d9e76e Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Mon, 16 Jan 2023 18:25:59 +0000 Subject: [PATCH 5/9] Fix broken etag handling. Maybe fixes #802 --- .../net/fabricmc/loom/util/download/Download.java | 14 +++++++------- .../test/unit/download/DownloadFileTest.groovy | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/net/fabricmc/loom/util/download/Download.java b/src/main/java/net/fabricmc/loom/util/download/Download.java index ad643bc7..a1f3158a 100644 --- a/src/main/java/net/fabricmc/loom/util/download/Download.java +++ b/src/main/java/net/fabricmc/loom/util/download/Download.java @@ -161,13 +161,6 @@ public class Download { eTag = readEtag(output); } - try { - createParentDirs(output.toFile()); - Files.deleteIfExists(output); - } catch (IOException e) { - throw error(e, "Failed to prepare path for download"); - } - final HttpRequest httpRequest = eTag .map(this::getETagRequest) .orElseGet(this::getRequest); @@ -186,6 +179,13 @@ public class Download { } if (success) { + try { + createParentDirs(output.toFile()); + Files.deleteIfExists(output); + } catch (IOException e) { + throw error(e, "Failed to prepare path for download"); + } + final long length = Long.parseLong(response.headers().firstValue("Content-Length").orElse("-1")); AtomicLong totalBytes = new AtomicLong(0); diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/download/DownloadFileTest.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/download/DownloadFileTest.groovy index e3ee8d08..f0b39f69 100644 --- a/src/test/groovy/net/fabricmc/loom/test/unit/download/DownloadFileTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/unit/download/DownloadFileTest.groovy @@ -203,7 +203,7 @@ class DownloadFileTest extends DownloadTest { def output = new File(File.createTempDir(), "etag.txt").toPath() when: - for (i in 0..<2) { + for (i in 0..<3) { Download.create("$PATH/etag") .etag(true) .downloadPath(output) From 0c68994aa60a79790fcb20f921d04d135b319e8a Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Mon, 16 Jan 2023 18:38:16 +0000 Subject: [PATCH 6/9] Fix #755 --- .../configuration/CompileConfiguration.java | 2 +- .../java/net/fabricmc/loom/util/Checksum.java | 7 +++ .../loom/test/unit/ChecksumTest.groovy | 49 +++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 src/test/groovy/net/fabricmc/loom/test/unit/ChecksumTest.groovy diff --git a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java index 2548d62e..36b1f028 100644 --- a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java +++ b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java @@ -272,7 +272,7 @@ public final class CompileConfiguration { private static Path getLockFile(Project project) { final LoomGradleExtension extension = LoomGradleExtension.get(project); final Path cacheDirectory = extension.getFiles().getUserCache().toPath(); - final String pathHash = Checksum.toHex(project.getProjectDir().getAbsolutePath().getBytes(StandardCharsets.UTF_8)).substring(0, 16); + final String pathHash = Checksum.projectHash(project); return cacheDirectory.resolve("." + pathHash + ".lock"); } diff --git a/src/main/java/net/fabricmc/loom/util/Checksum.java b/src/main/java/net/fabricmc/loom/util/Checksum.java index 5b2348d2..bfeff16f 100644 --- a/src/main/java/net/fabricmc/loom/util/Checksum.java +++ b/src/main/java/net/fabricmc/loom/util/Checksum.java @@ -27,12 +27,14 @@ package net.fabricmc.loom.util; import java.io.File; import java.io.IOException; import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Path; import com.google.common.hash.HashCode; import com.google.common.hash.Hashing; import com.google.common.io.BaseEncoding; import com.google.common.io.Files; +import org.gradle.api.Project; import org.gradle.api.logging.Logger; import org.gradle.api.logging.Logging; @@ -81,4 +83,9 @@ public class Checksum { public static String toHex(byte[] bytes) { return BaseEncoding.base16().lowerCase().encode(bytes); } + + public static String projectHash(Project project) { + String str = project.getProjectDir().getAbsolutePath() + ":" + project.getPath(); + return toHex(str.getBytes(StandardCharsets.UTF_8)).substring(0, 16); + } } diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/ChecksumTest.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/ChecksumTest.groovy new file mode 100644 index 00000000..a5b64b63 --- /dev/null +++ b/src/test/groovy/net/fabricmc/loom/test/unit/ChecksumTest.groovy @@ -0,0 +1,49 @@ +/* + * 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 + +import net.fabricmc.loom.util.Checksum +import org.gradle.api.Project +import spock.lang.Specification + +class ChecksumTest extends Specification { + def "project hash"() { + given: + def project = Mock(Project) + project.getPath() >> path + project.getProjectDir() >> new File(dir) + + when: + def hash = Checksum.projectHash(project) + + then: + hash == expected + + where: + path | dir | expected + ":" | "C://mod" | "2f55736572732f6d" + ":sub" | "/Users/test/Documents/modding/fabric-loom" | "2f55736572732f74" + } +} From 63ecb88082f2e32c75d7854401cb1f52fd143955 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Mon, 16 Jan 2023 18:39:26 +0000 Subject: [PATCH 7/9] Gradle 8 tests, perf/memory optimisations (#796) * Add gradle 8 tests Reuse gradle home between tests Misc perf and mem optimisations * Fix build warning. * Added multi mc version test * Use server launcher in ServerRunner Co-authored-by: Luna <62033805+Luna5ama@users.noreply.github.com> --- build.gradle | 2 +- .../fabricmc/loom/LoomGradleExtension.java | 7 -- .../loom/api/processor/ProcessorContext.java | 3 + .../InterfaceInjectionProcessor.java | 24 +++---- .../processors/ProcessorContextImpl.java | 8 +++ .../extension/LoomGradleExtensionApiImpl.java | 2 +- .../extension/LoomGradleExtensionImpl.java | 15 ---- .../loom/task/PrepareJarRemapTask.java | 14 ++-- .../net/fabricmc/loom/task/RemapJarTask.java | 8 +-- .../task/service/LorenzMappingService.java | 69 +++++++++++++++++++ .../task/service/TinyRemapperService.java | 3 +- .../fabricmc/loom/util/SourceRemapper.java | 69 ++++++++----------- .../loom/test/LoomTestConstants.groovy | 10 ++- .../test/benchmark/FabricAPIBenchmark.groovy | 8 ++- .../test/integration/FabricAPITest.groovy | 11 +-- .../integration/MultiMcVersionTest.groovy | 61 ++++++++++++++++ .../test/util/GradleProjectTestTrait.groovy | 13 +--- .../loom/test/util/ServerRunner.groovy | 20 ++---- .../projects/multi-mc-versions/build.gradle | 56 +++++++++++++++ .../multi-mc-versions/gradle.properties | 9 +++ .../multi-mc-versions/settings.gradle | 9 +++ .../com/example/examplemod/ExampleMod.java | 19 +++++ .../src/main/resources/fabric.mod.json | 25 +++++++ 23 files changed, 339 insertions(+), 126 deletions(-) create mode 100644 src/main/java/net/fabricmc/loom/task/service/LorenzMappingService.java create mode 100644 src/test/groovy/net/fabricmc/loom/test/integration/MultiMcVersionTest.groovy create mode 100644 src/test/resources/projects/multi-mc-versions/build.gradle create mode 100644 src/test/resources/projects/multi-mc-versions/gradle.properties create mode 100644 src/test/resources/projects/multi-mc-versions/settings.gradle create mode 100644 src/test/resources/projects/multi-mc-versions/src/main/java/com/example/examplemod/ExampleMod.java create mode 100644 src/test/resources/projects/multi-mc-versions/src/main/resources/fabric.mod.json diff --git a/build.gradle b/build.gradle index ab444c93..e9b73af3 100644 --- a/build.gradle +++ b/build.gradle @@ -111,7 +111,6 @@ dependencies { testImplementation ('io.javalin:javalin:5.1.2') { exclude group: 'org.jetbrains.kotlin' } - testImplementation 'net.fabricmc:fabric-installer:0.9.0' testImplementation 'org.mockito:mockito-core:4.8.0' compileOnly 'org.jetbrains:annotations:23.0.0' @@ -194,6 +193,7 @@ jacocoTestReport { test { maxHeapSize = "2560m" + jvmArgs "-XX:+HeapDumpOnOutOfMemoryError" useJUnitPlatform() // Forward system prop onto tests. diff --git a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java index aa74bab0..10ac4db9 100644 --- a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java +++ b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java @@ -26,10 +26,7 @@ package net.fabricmc.loom; import java.nio.file.Path; import java.util.List; -import java.util.function.Supplier; -import org.cadixdev.lorenz.MappingSet; -import org.cadixdev.mercury.Mercury; import org.gradle.api.Project; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.FileCollection; @@ -54,10 +51,6 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI { LoomFiles getFiles(); - MappingSet getOrCreateSrcMappingCache(int id, Supplier factory); - - Mercury getOrCreateSrcMercuryCache(int id, Supplier factory); - ConfigurableFileCollection getUnmappedModCollection(); void setInstallerData(InstallerData data); diff --git a/src/main/java/net/fabricmc/loom/api/processor/ProcessorContext.java b/src/main/java/net/fabricmc/loom/api/processor/ProcessorContext.java index a5152f9b..282dbf2f 100644 --- a/src/main/java/net/fabricmc/loom/api/processor/ProcessorContext.java +++ b/src/main/java/net/fabricmc/loom/api/processor/ProcessorContext.java @@ -27,6 +27,7 @@ package net.fabricmc.loom.api.processor; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration; import net.fabricmc.loom.util.LazyCloseable; +import net.fabricmc.mappingio.tree.MemoryMappingTree; import net.fabricmc.tinyremapper.TinyRemapper; public interface ProcessorContext { @@ -39,4 +40,6 @@ public interface ProcessorContext { boolean includesServer(); LazyCloseable createRemapper(MappingsNamespace from, MappingsNamespace to); + + MemoryMappingTree getMappings(); } diff --git a/src/main/java/net/fabricmc/loom/configuration/ifaceinject/InterfaceInjectionProcessor.java b/src/main/java/net/fabricmc/loom/configuration/ifaceinject/InterfaceInjectionProcessor.java index 77ba7403..ea0a7327 100644 --- a/src/main/java/net/fabricmc/loom/configuration/ifaceinject/InterfaceInjectionProcessor.java +++ b/src/main/java/net/fabricmc/loom/configuration/ifaceinject/InterfaceInjectionProcessor.java @@ -32,6 +32,7 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; import javax.inject.Inject; @@ -43,7 +44,6 @@ import org.jetbrains.annotations.Nullable; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.commons.Remapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -56,6 +56,7 @@ import net.fabricmc.loom.util.Pair; import net.fabricmc.loom.util.ZipUtils; import net.fabricmc.loom.util.fmj.FabricModJson; import net.fabricmc.mappingio.tree.MappingTree; +import net.fabricmc.mappingio.tree.MemoryMappingTree; public abstract class InterfaceInjectionProcessor implements MinecraftJarProcessor { private static final Logger LOGGER = LoggerFactory.getLogger(InterfaceInjectionProcessor.class); @@ -98,16 +99,13 @@ public abstract class InterfaceInjectionProcessor implements MinecraftJarProcess @Override public void processJar(Path jar, Spec spec, ProcessorContext context) throws IOException { - final List remappedInjectedInterfaces; - // Remap from intermediary->named - try (var tinyRemapper = context.createRemapper(MappingsNamespace.INTERMEDIARY, MappingsNamespace.NAMED)) { - final Remapper remapper = tinyRemapper.get().getEnvironment().getRemapper(); - - remappedInjectedInterfaces = spec.injectedInterfaces().stream() - .map(injectedInterface -> remap(injectedInterface, remapper)) - .toList(); - } + final MemoryMappingTree mappings = context.getMappings(); + final int intermediaryIndex = mappings.getNamespaceId(MappingsNamespace.INTERMEDIARY.toString()); + final int namedIndex = mappings.getNamespaceId(MappingsNamespace.NAMED.toString()); + final List remappedInjectedInterfaces = spec.injectedInterfaces().stream() + .map(injectedInterface -> remap(injectedInterface, s -> mappings.mapClassName(s, intermediaryIndex, namedIndex))) + .toList(); try { ZipUtils.transform(jar, getTransformers(remappedInjectedInterfaces)); @@ -116,11 +114,11 @@ public abstract class InterfaceInjectionProcessor implements MinecraftJarProcess } } - private InjectedInterface remap(InjectedInterface in, Remapper remapper) { + private InjectedInterface remap(InjectedInterface in, Function remapper) { return new InjectedInterface( in.modId(), - remapper.map(in.className()), - remapper.map(in.ifaceName()) + remapper.apply(in.className()), + remapper.apply(in.ifaceName()) ); } diff --git a/src/main/java/net/fabricmc/loom/configuration/processors/ProcessorContextImpl.java b/src/main/java/net/fabricmc/loom/configuration/processors/ProcessorContextImpl.java index 15f2d3ca..484dc57e 100644 --- a/src/main/java/net/fabricmc/loom/configuration/processors/ProcessorContextImpl.java +++ b/src/main/java/net/fabricmc/loom/configuration/processors/ProcessorContextImpl.java @@ -24,12 +24,14 @@ package net.fabricmc.loom.configuration.processors; +import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; import net.fabricmc.loom.api.processor.ProcessorContext; import net.fabricmc.loom.configuration.ConfigContext; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJar; import net.fabricmc.loom.configuration.providers.minecraft.MinecraftJarConfiguration; import net.fabricmc.loom.util.LazyCloseable; +import net.fabricmc.mappingio.tree.MemoryMappingTree; import net.fabricmc.tinyremapper.TinyRemapper; public record ProcessorContextImpl(ConfigContext configContext, MinecraftJar minecraftJar) implements ProcessorContext { @@ -57,4 +59,10 @@ public record ProcessorContextImpl(ConfigContext configContext, MinecraftJar min public LazyCloseable createRemapper(MappingsNamespace from, MappingsNamespace to) { return ContextImplHelper.createRemapper(configContext, from, to); } + + @Override + public MemoryMappingTree getMappings() { + LoomGradleExtension extension = LoomGradleExtension.get(configContext().project()); + return extension.getMappingConfiguration().getMappingsService(configContext().serviceManager()).getMappingTree(); + } } diff --git a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java index 847fd3b5..17e54ec3 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java @@ -141,7 +141,7 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA this.splitEnvironmentalSourceSet = project.getObjects().property(Boolean.class).convention(false); this.splitEnvironmentalSourceSet.finalizeValueOnRead(); - // Add main source set by default + // Enable dep iface injection by default interfaceInjection(interfaceInjection -> { interfaceInjection.getEnableDependencyInterfaceInjection().convention(true).finalizeValueOnRead(); }); diff --git a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java index 0c2d7c8e..3748c043 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java @@ -29,10 +29,7 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Objects; -import java.util.function.Supplier; -import org.cadixdev.lorenz.MappingSet; -import org.cadixdev.mercury.Mercury; import org.gradle.api.Project; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.FileCollection; @@ -60,8 +57,6 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen private final LoomFiles loomFiles; private final ConfigurableFileCollection unmappedMods; - private final MappingSet[] srcMappingCache = new MappingSet[2]; - private final Mercury[] srcMercuryCache = new Mercury[2]; private final List transitiveAccessWideners = new ArrayList<>(); private LoomDependencyManager dependencyManager; @@ -167,16 +162,6 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen ); } - @Override - public MappingSet getOrCreateSrcMappingCache(int id, Supplier factory) { - return srcMappingCache[id] != null ? srcMappingCache[id] : (srcMappingCache[id] = factory.get()); - } - - @Override - public Mercury getOrCreateSrcMercuryCache(int id, Supplier factory) { - return srcMercuryCache[id] != null ? srcMercuryCache[id] : (srcMercuryCache[id] = factory.get()); - } - @Override public ConfigurableFileCollection getUnmappedModCollection() { return unmappedMods; diff --git a/src/main/java/net/fabricmc/loom/task/PrepareJarRemapTask.java b/src/main/java/net/fabricmc/loom/task/PrepareJarRemapTask.java index ab4c69c0..9569968a 100644 --- a/src/main/java/net/fabricmc/loom/task/PrepareJarRemapTask.java +++ b/src/main/java/net/fabricmc/loom/task/PrepareJarRemapTask.java @@ -57,14 +57,12 @@ public abstract class PrepareJarRemapTask extends AbstractLoomTask { getOutputs().upToDateWhen((o) -> false); getProject().getGradle().allprojects(project -> { - project.getTasks().configureEach(task -> { - if (task instanceof PrepareJarRemapTask otherTask) { - if (otherTask == this) return; + project.getTasks().withType(PrepareJarRemapTask.class, otherTask -> { + if (otherTask == this) return; - // Ensure that all other prepare tasks inputs have completed - dependsOn(otherTask.getInputs()); - mustRunAfter(otherTask.getInputs()); - } + // Ensure that all other prepare tasks inputs have completed + dependsOn(otherTask.getInputs()); + mustRunAfter(otherTask.getInputs()); }); }); } @@ -102,6 +100,6 @@ public abstract class PrepareJarRemapTask extends AbstractLoomTask { } static void prepare(TinyRemapperService tinyRemapperService, Path inputFile) { - tinyRemapperService.getTinyRemapperForInputs().readInputsAsync(tinyRemapperService.getOrCreateTag(inputFile), inputFile); + tinyRemapperService.getTinyRemapperForInputs().readInputs(tinyRemapperService.getOrCreateTag(inputFile), inputFile); } } diff --git a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java index 6c52130b..872ce42e 100644 --- a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java +++ b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java @@ -33,13 +33,11 @@ import java.util.Collection; import java.util.List; import java.util.Objects; import java.util.Set; -import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.inject.Inject; -import com.google.common.base.Suppliers; import com.google.gson.JsonObject; import org.gradle.api.artifacts.Configuration; import org.gradle.api.file.ConfigurableFileCollection; @@ -90,13 +88,11 @@ public abstract class RemapJarTask extends AbstractRemapJarTask { public abstract Property getUseMixinAP(); private final Provider serviceManagerProvider; - private final Supplier tinyRemapperService; @Inject public RemapJarTask() { super(); serviceManagerProvider = BuildSharedServiceManager.createForTask(this, getBuildEventsListenerRegistry()); - tinyRemapperService = Suppliers.memoize(() -> TinyRemapperService.getOrCreate(serviceManagerProvider.get().get(), this)); getClasspath().from(getProject().getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME)); getAddNestedDependencies().convention(true).finalizeValueOnRead(); @@ -134,7 +130,7 @@ public abstract class RemapJarTask extends AbstractRemapJarTask { params.getNestedJars().from(getNestedJars()); } - params.getTinyRemapperBuildServiceUuid().set(UnsafeWorkQueueHelper.create(tinyRemapperService.get())); + params.getTinyRemapperBuildServiceUuid().set(UnsafeWorkQueueHelper.create(getTinyRemapperService())); params.getRemapClasspath().from(getClasspath()); params.getMultiProjectOptimisation().set(getLoomExtension().multiProjectOptimisation()); @@ -337,6 +333,6 @@ public abstract class RemapJarTask extends AbstractRemapJarTask { @Internal public TinyRemapperService getTinyRemapperService() { - return tinyRemapperService.get(); + return TinyRemapperService.getOrCreate(serviceManagerProvider.get().get(), this); } } diff --git a/src/main/java/net/fabricmc/loom/task/service/LorenzMappingService.java b/src/main/java/net/fabricmc/loom/task/service/LorenzMappingService.java new file mode 100644 index 00000000..953211c0 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/task/service/LorenzMappingService.java @@ -0,0 +1,69 @@ +/* + * 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.task.service; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.util.Objects; + +import org.cadixdev.lorenz.MappingSet; + +import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; +import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration; +import net.fabricmc.loom.util.service.SharedService; +import net.fabricmc.loom.util.service.SharedServiceManager; +import net.fabricmc.lorenztiny.TinyMappingsReader; +import net.fabricmc.mappingio.tree.MemoryMappingTree; + +public final class LorenzMappingService implements SharedService { + private MappingSet mappings; + + public LorenzMappingService(MappingSet mappings) { + this.mappings = mappings; + } + + public static synchronized LorenzMappingService create(SharedServiceManager sharedServiceManager, MappingConfiguration mappingConfiguration, MappingsNamespace from, MappingsNamespace to) { + return sharedServiceManager.getOrCreateService(mappingConfiguration.getBuildServiceName("LorenzMappingService", from.toString(), to.toString()), () -> { + MemoryMappingTree m = mappingConfiguration.getMappingsService(sharedServiceManager).getMappingTree(); + + try { + try (var reader = new TinyMappingsReader(m, from.toString(), to.toString())) { + return new LorenzMappingService(reader.read()); + } + } catch (IOException e) { + throw new UncheckedIOException("Failed to read lorenz mappings", e); + } + }); + } + + @Override + public void close() throws IOException { + this.mappings = null; + } + + public MappingSet mappings() { + return Objects.requireNonNull(mappings); + } +} diff --git a/src/main/java/net/fabricmc/loom/task/service/TinyRemapperService.java b/src/main/java/net/fabricmc/loom/task/service/TinyRemapperService.java index ced8f239..38f7ad7d 100644 --- a/src/main/java/net/fabricmc/loom/task/service/TinyRemapperService.java +++ b/src/main/java/net/fabricmc/loom/task/service/TinyRemapperService.java @@ -181,12 +181,13 @@ public class TinyRemapperService implements SharedService { classpath.addAll(paths); } - tinyRemapper.readClassPathAsync(toRead.toArray(Path[]::new)); + tinyRemapper.readClassPath(toRead.toArray(Path[]::new)); } @Override public void close() throws IOException { if (tinyRemapper != null) { + tinyRemapper.getEnvironment(); tinyRemapper.finish(); tinyRemapper = null; } diff --git a/src/main/java/net/fabricmc/loom/util/SourceRemapper.java b/src/main/java/net/fabricmc/loom/util/SourceRemapper.java index 7812dd58..e3348689 100644 --- a/src/main/java/net/fabricmc/loom/util/SourceRemapper.java +++ b/src/main/java/net/fabricmc/loom/util/SourceRemapper.java @@ -50,9 +50,8 @@ import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.api.RemapConfigurationSettings; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration; +import net.fabricmc.loom.task.service.LorenzMappingService; import net.fabricmc.loom.util.service.SharedServiceManager; -import net.fabricmc.lorenztiny.TinyMappingsReader; -import net.fabricmc.mappingio.tree.MemoryMappingTree; public class SourceRemapper { private final Project project; @@ -167,51 +166,43 @@ public class SourceRemapper { LoomGradleExtension extension = LoomGradleExtension.get(project); MappingConfiguration mappingConfiguration = extension.getMappingConfiguration(); - MappingSet mappings = extension.getOrCreateSrcMappingCache(toNamed ? 1 : 0, () -> { - try { - MemoryMappingTree m = mappingConfiguration.getMappingsService(serviceManager).getMappingTree(); - project.getLogger().info(":loading " + (toNamed ? "intermediary -> named" : "named -> intermediary") + " source mappings"); - return new TinyMappingsReader(m, toNamed ? MappingsNamespace.INTERMEDIARY.toString() : MappingsNamespace.NAMED.toString(), toNamed ? MappingsNamespace.NAMED.toString() : MappingsNamespace.INTERMEDIARY.toString()).read(); - } catch (Exception e) { - throw new RuntimeException(e); + MappingSet mappings = LorenzMappingService.create(serviceManager, + mappingConfiguration, + toNamed ? MappingsNamespace.INTERMEDIARY : MappingsNamespace.NAMED, + toNamed ? MappingsNamespace.NAMED : MappingsNamespace.INTERMEDIARY + ).mappings(); + + Mercury mercury = createMercuryWithClassPath(project, toNamed); + mercury.setSourceCompatibilityFromRelease(getJavaCompileRelease(project)); + + for (File file : extension.getUnmappedModCollection()) { + Path path = file.toPath(); + + if (Files.isRegularFile(path)) { + mercury.getClassPath().add(path); } - }); + } - Mercury mercury = extension.getOrCreateSrcMercuryCache(toNamed ? 1 : 0, () -> { - Mercury m = createMercuryWithClassPath(project, toNamed); - m.setSourceCompatibilityFromRelease(getJavaCompileRelease(project)); + for (Path intermediaryJar : extension.getMinecraftJars(MappingsNamespace.INTERMEDIARY)) { + mercury.getClassPath().add(intermediaryJar); + } - for (File file : extension.getUnmappedModCollection()) { - Path path = file.toPath(); + for (Path intermediaryJar : extension.getMinecraftJars(MappingsNamespace.NAMED)) { + mercury.getClassPath().add(intermediaryJar); + } - if (Files.isRegularFile(path)) { - m.getClassPath().add(path); - } - } + Set files = project.getConfigurations() + .detachedConfiguration(project.getDependencies().create(Constants.Dependencies.JETBRAINS_ANNOTATIONS + Constants.Dependencies.Versions.JETBRAINS_ANNOTATIONS)) + .resolve(); - for (Path intermediaryJar : extension.getMinecraftJars(MappingsNamespace.INTERMEDIARY)) { - m.getClassPath().add(intermediaryJar); - } + for (File file : files) { + mercury.getClassPath().add(file.toPath()); + } - for (Path intermediaryJar : extension.getMinecraftJars(MappingsNamespace.NAMED)) { - m.getClassPath().add(intermediaryJar); - } - - Set files = project.getConfigurations() - .detachedConfiguration(project.getDependencies().create(Constants.Dependencies.JETBRAINS_ANNOTATIONS + Constants.Dependencies.Versions.JETBRAINS_ANNOTATIONS)) - .resolve(); - - for (File file : files) { - m.getClassPath().add(file.toPath()); - } - - m.getProcessors().add(MercuryRemapper.create(mappings)); - - return m; - }); + mercury.getProcessors().add(MercuryRemapper.create(mappings)); this.mercury = mercury; - return mercury; + return this.mercury; } public static int getJavaCompileRelease(Project project) { diff --git a/src/test/groovy/net/fabricmc/loom/test/LoomTestConstants.groovy b/src/test/groovy/net/fabricmc/loom/test/LoomTestConstants.groovy index 4e004e03..83e23162 100644 --- a/src/test/groovy/net/fabricmc/loom/test/LoomTestConstants.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/LoomTestConstants.groovy @@ -27,13 +27,19 @@ package net.fabricmc.loom.test import org.gradle.util.GradleVersion class LoomTestConstants { - private final static String NIGHTLY_VERSION = "8.1-20221229234322+0000" + private final static String NIGHTLY_VERSION = "8.1-20230109232704+0000" private final static boolean NIGHTLY_EXISTS = nightlyExists(NIGHTLY_VERSION) + // Test against the version of Gradle being used to build loom public final static String DEFAULT_GRADLE = GradleVersion.current().getVersion() + // Test against Gradle 8 + public final static String GRADLE_8 = "8.0-rc-1" // Tests that depend specifically on the nightly will run on the current version when the nightly is not available. public final static String PRE_RELEASE_GRADLE = NIGHTLY_EXISTS ? NIGHTLY_VERSION : DEFAULT_GRADLE - public final static String[] STANDARD_TEST_VERSIONS = NIGHTLY_EXISTS ? [DEFAULT_GRADLE, PRE_RELEASE_GRADLE] : [DEFAULT_GRADLE] + // Randomly sorted to ensure that all versions can run with a clean gradle home. + public final static String[] STANDARD_TEST_VERSIONS = (NIGHTLY_EXISTS ? [DEFAULT_GRADLE, GRADLE_8, PRE_RELEASE_GRADLE] : [DEFAULT_GRADLE, GRADLE_8]).shuffled().toArray() + + public static final File TEST_DIR = new File("./.gradle/test-files") /** * Nightly gradle versions get removed after a certain amount of time, lets check to see if its still online before running the tests. diff --git a/src/test/groovy/net/fabricmc/loom/test/benchmark/FabricAPIBenchmark.groovy b/src/test/groovy/net/fabricmc/loom/test/benchmark/FabricAPIBenchmark.groovy index 5acf17ee..1ede9916 100644 --- a/src/test/groovy/net/fabricmc/loom/test/benchmark/FabricAPIBenchmark.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/benchmark/FabricAPIBenchmark.groovy @@ -37,19 +37,21 @@ import net.fabricmc.loom.test.util.GradleProjectTestTrait class FabricAPIBenchmark implements GradleProjectTestTrait { def run(File dir) { def gradle = gradleProject( - version: LoomTestConstants.PRE_RELEASE_GRADLE, + version: LoomTestConstants.DEFAULT_GRADLE, projectDir: new File(dir, "project"), gradleHomeDir: new File(dir, "gradlehome"), allowExistingRepo: true, repo: "https://github.com/FabricMC/fabric.git", - commit: "5f243a8b7849eac4b30cd876a22a127797a1c406", + commit: "2facd446984085376bd23245410ebf2dc0881b02", patch: "fabric_api" ) + gradle.enableMultiProjectOptimisation() + def timeStart = new Date() - def result = gradle.run(tasks: ["clean"], args: []) + def result = gradle.run(tasks: ["clean", "build", "-x", "test", "-x", "check", "-x", ":fabric-data-generation-api-v1:runDatagen"], args: []) def timeStop = new Date() TimeDuration duration = TimeCategory.minus(timeStop, timeStart) diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/FabricAPITest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/FabricAPITest.groovy index f5be694f..d67a1159 100644 --- a/src/test/groovy/net/fabricmc/loom/test/integration/FabricAPITest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/integration/FabricAPITest.groovy @@ -44,7 +44,7 @@ class FabricAPITest extends Specification implements GradleProjectTestTrait { setup: def gradle = gradleProject( repo: "https://github.com/FabricMC/fabric.git", - commit: "5f243a8b7849eac4b30cd876a22a127797a1c406", + commit: "2facd446984085376bd23245410ebf2dc0881b02", version: version, patch: "fabric_api" ) @@ -54,7 +54,7 @@ class FabricAPITest extends Specification implements GradleProjectTestTrait { // Set the version to something constant gradle.buildGradle.text = gradle.buildGradle.text.replace('project.version + "+" + (ENV.GITHUB_RUN_NUMBER ? "" : "local-") + getBranch()', "\"$API_VERSION\"") - def server = ServerRunner.create(gradle.projectDir, "1.19.2") + def server = ServerRunner.create(gradle.projectDir, "1.19.3") .withMod(gradle.getOutputFile("fabric-api-${API_VERSION}.jar")) when: def result = gradle.run(tasks: ["build", "publishToMavenLocal"], args: ["--parallel", "-x", "check", "-x", "runDatagen", "-x", "runGametest"]) // Note: checkstyle does not appear to like being ran in a test runner @@ -65,12 +65,13 @@ class FabricAPITest extends Specification implements GradleProjectTestTrait { result.task(":build").outcome == SUCCESS result.task(":prepareRemapJar").outcome == SUCCESS - new File(gradle.mavenLocalDir, "net/fabricmc/fabric-api/fabric-biome-api-v1/9.0.17/fabric-biome-api-v1-9.0.17.jar").exists() - new File(gradle.mavenLocalDir, "net/fabricmc/fabric-api/fabric-biome-api-v1/9.0.17/fabric-biome-api-v1-9.0.17-sources.jar").exists() + new File(gradle.mavenLocalDir, "net/fabricmc/fabric-api/fabric-biome-api-v1/12.1.0/fabric-biome-api-v1-12.1.0.jar").exists() + new File(gradle.mavenLocalDir, "net/fabricmc/fabric-api/fabric-biome-api-v1/12.1.0/fabric-biome-api-v1-12.1.0-sources.jar").exists() serverResult.successful() serverResult.output.contains("- fabric-api $API_VERSION") where: - version << STANDARD_TEST_VERSIONS + //version << STANDARD_TEST_VERSIONS + version << [DEFAULT_GRADLE] } } diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/MultiMcVersionTest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/MultiMcVersionTest.groovy new file mode 100644 index 00000000..c27db1df --- /dev/null +++ b/src/test/groovy/net/fabricmc/loom/test/integration/MultiMcVersionTest.groovy @@ -0,0 +1,61 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2016-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.integration + +import net.fabricmc.loom.test.util.GradleProjectTestTrait +import spock.lang.Specification +import spock.lang.Unroll + +import static net.fabricmc.loom.test.LoomTestConstants.STANDARD_TEST_VERSIONS +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS + +class MultiMcVersionTest extends Specification implements GradleProjectTestTrait { + @Unroll + def "build (gradle #version)"() { + setup: + def gradle = gradleProject(project: "multi-mc-versions", version: version) + + when: + def result = gradle.run(tasks: "build") + + then: + def versions = [ + 'fabric-1.14.4', + 'fabric-1.15', 'fabric-1.15.2', + 'fabric-1.16', 'fabric-1.16.5', + 'fabric-1.17', 'fabric-1.17.1', + 'fabric-1.18', 'fabric-1.18.2', + 'fabric-1.19', 'fabric-1.19.3' + ] + + result.task(":build").outcome == SUCCESS + versions.forEach { + result.task(":$it:build").outcome == SUCCESS + } + + where: + version << STANDARD_TEST_VERSIONS + } +} diff --git a/src/test/groovy/net/fabricmc/loom/test/util/GradleProjectTestTrait.groovy b/src/test/groovy/net/fabricmc/loom/test/util/GradleProjectTestTrait.groovy index 01d4e5b5..ad590af4 100644 --- a/src/test/groovy/net/fabricmc/loom/test/util/GradleProjectTestTrait.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/util/GradleProjectTestTrait.groovy @@ -37,22 +37,13 @@ trait GradleProjectTestTrait { @Lazy @Shared private static File sharedProjectDir = File.createTempDir() - @Lazy - @Shared - private static File sharedGradleHomeDir = File.createTempDir() + private static File gradleHomeDir = new File(LoomTestConstants.TEST_DIR, "integration/gradle_home") GradleProject gradleProject(Map options) { String gradleVersion = options.version as String ?: LoomTestConstants.DEFAULT_GRADLE String warningMode = options.warningMode as String ?: "fail" File projectDir = options.projectDir as File ?: options.sharedFiles ? sharedProjectDir : File.createTempDir() - File gradleHomeDir = options.gradleHomeDir as File ?: options.sharedFiles ? sharedGradleHomeDir : File.createTempDir() - - // Useful for faster local testing. - def homeDirOverride = System.getProperty("fabric.loom.test.homeDir") - - if (homeDirOverride) { - gradleHomeDir = new File(homeDirOverride) - } + File gradleHomeDir = gradleHomeDir setupProject(options, projectDir) diff --git a/src/test/groovy/net/fabricmc/loom/test/util/ServerRunner.groovy b/src/test/groovy/net/fabricmc/loom/test/util/ServerRunner.groovy index b2883abe..37862bf4 100644 --- a/src/test/groovy/net/fabricmc/loom/test/util/ServerRunner.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/util/ServerRunner.groovy @@ -25,11 +25,13 @@ package net.fabricmc.loom.test.util import groovy.transform.Immutable +import net.fabricmc.loom.util.download.Download import java.util.concurrent.TimeUnit class ServerRunner { - static final String LOADER_VERSION = "0.14.9" + static final String LOADER_VERSION = "0.14.12" + static final String INSTALLER_VERSION = "0.11.1" static final Map FABRIC_API_URLS = [ "1.16.5": "https://github.com/FabricMC/fabric/releases/download/0.37.1%2B1.16/fabric-api-0.37.1+1.16.jar", "1.17.1": "https://github.com/FabricMC/fabric/releases/download/0.37.1%2B1.17/fabric-api-0.37.1+1.17.jar" @@ -53,19 +55,9 @@ class ServerRunner { } def install() { - def args = [ - "server", - "-dir", - serverDir.absolutePath, - "-mcversion", - minecraftVersion, - "-loader", - LOADER_VERSION, - "-downloadMinecraft" - ] - - //noinspection UnnecessaryQualifiedReference - net.fabricmc.installer.Main.main(args as String[]) + def url = "https://meta.fabricmc.net/v2/versions/loader/${minecraftVersion}/${LOADER_VERSION}/${INSTALLER_VERSION}/server/jar" + Download.create(url) + .downloadPath(serverDir.toPath().resolve("fabric-server-launch.jar")) def eulaFile = new File(serverDir, "eula.txt") eulaFile << "eula=true" diff --git a/src/test/resources/projects/multi-mc-versions/build.gradle b/src/test/resources/projects/multi-mc-versions/build.gradle new file mode 100644 index 00000000..7d271f97 --- /dev/null +++ b/src/test/resources/projects/multi-mc-versions/build.gradle @@ -0,0 +1,56 @@ +import groovy.json.JsonSlurper + +plugins { + id "java" + id 'fabric-loom' apply false +} + +allprojects { + group = project.maven_group + version = project.mod_version +} + +ext { + yarnMeta = new JsonSlurper().parse(new URL("https://meta.fabricmc.net/v2/versions/yarn")) +} + +def getMappingVersion(String mcVersion) { + return rootProject.yarnMeta.find { it.gameVersion == mcVersion }.version +} + +subprojects { + apply plugin: "fabric-loom" + + archivesBaseName = rootProject.name + "-" + project.name + + def minecraft_version = project.name.substring(7) + def yarn_mappings = getMappingVersion(minecraft_version) + + dependencies { + // To change the versions see the gradle.properties files + minecraft "com.mojang:minecraft:$minecraft_version" + mappings "net.fabricmc:yarn:$yarn_mappings:v2" + modImplementation "net.fabricmc:fabric-loader:$loader_version" + } + + jar { + archiveClassifier.set "dev" + } + + // Just use the source from the root project + compileJava { + source(sourceSets.main.java.srcDirs) + } + + processResources { + from(rootProject.sourceSets.main.resources) + inputs.property 'version', project.version + + filesMatching("fabric.mod.json") { + expand 'version': project.version, 'minecraft_version': minecraft_version, 'loader_version': project.loader_version + } + } +} + +compileJava.enabled = false +processResources.enabled = false \ No newline at end of file diff --git a/src/test/resources/projects/multi-mc-versions/gradle.properties b/src/test/resources/projects/multi-mc-versions/gradle.properties new file mode 100644 index 00000000..ce3fa341 --- /dev/null +++ b/src/test/resources/projects/multi-mc-versions/gradle.properties @@ -0,0 +1,9 @@ +# The project should pass the build with these setting +org.gradle.jvmargs=-Xmx2560M +org.gradle.workers.max=3 + +mod_version = 1.0.0 +maven_group = com.example +archives_base_name = example-mod + +loader_version=0.14.12 \ No newline at end of file diff --git a/src/test/resources/projects/multi-mc-versions/settings.gradle b/src/test/resources/projects/multi-mc-versions/settings.gradle new file mode 100644 index 00000000..a7376582 --- /dev/null +++ b/src/test/resources/projects/multi-mc-versions/settings.gradle @@ -0,0 +1,9 @@ +rootProject.name = "multi-mc-versions" + +// Yes lot of mc version +include 'fabric-1.14.4' +include 'fabric-1.15', 'fabric-1.15.2' +include 'fabric-1.16', 'fabric-1.16.5' +include 'fabric-1.17', 'fabric-1.17.1' +include 'fabric-1.18', 'fabric-1.18.2' +include 'fabric-1.19', 'fabric-1.19.3' diff --git a/src/test/resources/projects/multi-mc-versions/src/main/java/com/example/examplemod/ExampleMod.java b/src/test/resources/projects/multi-mc-versions/src/main/java/com/example/examplemod/ExampleMod.java new file mode 100644 index 00000000..693e6e0c --- /dev/null +++ b/src/test/resources/projects/multi-mc-versions/src/main/java/com/example/examplemod/ExampleMod.java @@ -0,0 +1,19 @@ +package com.example.examplemod; + +import net.fabricmc.api.ModInitializer; +import net.minecraft.block.GrassBlock; +import net.minecraft.client.MinecraftClient; + +public class ExampleMod implements ModInitializer { + @Override + public void onInitialize() { + // class_2372 grassBlock = (class_2372) class_2246.field_10219; + GrassBlock grassBlock = (GrassBlock) net.minecraft.block.Blocks.GRASS_BLOCK; + // class_310 mincecraft = class_310.method_1551(); + MinecraftClient minecraft = MinecraftClient.getInstance(); + + System.out.println("Hello Fabric world!"); + System.out.println("This is a grass block: " + grassBlock); + System.out.println("This is minecraft client: " + minecraft); + } +} diff --git a/src/test/resources/projects/multi-mc-versions/src/main/resources/fabric.mod.json b/src/test/resources/projects/multi-mc-versions/src/main/resources/fabric.mod.json new file mode 100644 index 00000000..64ea821e --- /dev/null +++ b/src/test/resources/projects/multi-mc-versions/src/main/resources/fabric.mod.json @@ -0,0 +1,25 @@ +{ + "schemaVersion": 1, + "id": "example-mod", + "version": "${version}", + "name": "Example Mod", + "description": "This is an example description! Tell everyone what your mod is about!", + "authors": [ + "Me!" + ], + "contact": { + "homepage": "https://fabricmc.net/", + "sources": "https://github.com/FabricMC/fabric-example-mod" + }, + "license": "CC0-1.0", + "environment": "client", + "entrypoints": { + "main": [ + "com.example.examplemod.ExampleMod" + ] + }, + "depends": { + "fabricloader": ">=${loader_version}", + "minecraft": "${minecraft_version}" + } +} From 8a434af084f4103bd98697023a27a3ee0aa58fea Mon Sep 17 00:00:00 2001 From: js6pak Date: Mon, 16 Jan 2023 20:09:06 +0100 Subject: [PATCH 8/9] Remove unnecessary publication (#619) --- build.gradle | 8 -------- 1 file changed, 8 deletions(-) diff --git a/build.gradle b/build.gradle index e9b73af3..86b060d3 100644 --- a/build.gradle +++ b/build.gradle @@ -216,14 +216,6 @@ import org.w3c.dom.Node publishing { publications { - plugin(MavenPublication) { publication -> - groupId project.group - artifactId project.archivesBaseName - version project.version - - from components.java - } - // Also publish a snapshot so people can use the latest version if they wish snapshot(MavenPublication) { publication -> groupId project.group From 7f06b646934db18f6035489139083c72045bb3d0 Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Mon, 16 Jan 2023 21:53:44 +0000 Subject: [PATCH 9/9] Fix issue caused in previous commit. --- .../java/net/fabricmc/loom/util/download/Download.java | 9 +++++++-- .../loom/test/unit/download/DownloadFileTest.groovy | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/fabricmc/loom/util/download/Download.java b/src/main/java/net/fabricmc/loom/util/download/Download.java index a1f3158a..785ac7ac 100644 --- a/src/main/java/net/fabricmc/loom/util/download/Download.java +++ b/src/main/java/net/fabricmc/loom/util/download/Download.java @@ -161,6 +161,12 @@ public class Download { eTag = readEtag(output); } + try { + createParentDirs(output.toFile()); + } catch (IOException e) { + throw error(e, "Failed to create parent directories"); + } + final HttpRequest httpRequest = eTag .map(this::getETagRequest) .orElseGet(this::getRequest); @@ -180,10 +186,9 @@ public class Download { if (success) { try { - createParentDirs(output.toFile()); Files.deleteIfExists(output); } catch (IOException e) { - throw error(e, "Failed to prepare path for download"); + throw error(e, "Failed to delete existing file"); } final long length = Long.parseLong(response.headers().firstValue("Content-Length").orElse("-1")); diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/download/DownloadFileTest.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/download/DownloadFileTest.groovy index f0b39f69..d0c08942 100644 --- a/src/test/groovy/net/fabricmc/loom/test/unit/download/DownloadFileTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/unit/download/DownloadFileTest.groovy @@ -60,7 +60,7 @@ class DownloadFileTest extends DownloadTest { it.result("Hello World") } - def output = new File(File.createTempDir(), "file.txt").toPath() + def output = new File(File.createTempDir(), "subdir/file.txt").toPath() when: def result = Download.create("$PATH/simpleFile").downloadPath(output)