From ab21e0e550f483ce446e8c8115b80b77f8eb7adf Mon Sep 17 00:00:00 2001 From: modmuss50 Date: Mon, 20 Dec 2021 16:29:11 +0000 Subject: [PATCH] Rewrire Jar and Source remapping tasks. (#504) --- .../fabricmc/loom/LoomGradleExtension.java | 7 +- .../net/fabricmc/loom/build/JarRemapper.java | 159 ------- .../loom/build/MixinRefmapHelper.java | 61 +-- .../mixin/AnnotationProcessorInvoker.java | 2 +- .../build/nesting/IncludedJarFactory.java | 203 +++++++++ .../loom/build/nesting/JarNester.java | 3 +- .../nesting/MergedNestedJarProvider.java | 47 -- .../nesting/NestedDependencyProvider.java | 282 ------------ .../build/nesting/NestedJarPathProvider.java | 69 --- .../loom/build/nesting/NestedJarProvider.java | 40 -- .../configuration/CompileConfiguration.java | 12 +- .../JarManifestConfiguration.java | 92 ---- .../configuration/RemapConfiguration.java | 220 --------- .../accesswidener/AccessWidenerFile.java | 4 +- .../AccessWidenerJarProcessor.java | 23 - .../mappings/MappingsProviderImpl.java | 4 + .../extension/LoomGradleExtensionImpl.java | 18 +- .../loom/task/AbstractRemapJarTask.java | 123 ++++++ .../net/fabricmc/loom/task/LoomTasks.java | 6 +- .../loom/task/RemapAllSourcesTask.java | 38 -- .../net/fabricmc/loom/task/RemapJarTask.java | 417 +++++++++--------- .../loom/task/RemapSourcesJarTask.java | 109 +++-- .../loom/task/RemapTaskConfiguration.java | 138 ++++++ .../loom/task/service/JarManifestService.java | 123 ++++++ .../loom/task/service/MappingsService.java | 118 +++++ .../task/service/SourceRemapperService.java | 133 ++++++ .../fabricmc/loom/util/SourceRemapper.java | 7 +- .../loom/util/TinyRemapperHelper.java | 7 + .../loom/test/LoomTestConstants.groovy | 2 +- .../test/integration/FabricAPITest.groovy | 2 +- .../test/integration/MixinApSimpleTest.groovy | 2 +- .../test/integration/MultiProjectTest.groovy | 3 - .../test/integration/SimpleProjectTest.groovy | 1 + .../unit/MergedNestedJarProviderTest.groovy | 55 --- src/test/resources/patches/fabric_api.patch | 44 +- .../resources/projects/simple/build.gradle | 3 + 36 files changed, 1154 insertions(+), 1423 deletions(-) delete mode 100644 src/main/java/net/fabricmc/loom/build/JarRemapper.java create mode 100644 src/main/java/net/fabricmc/loom/build/nesting/IncludedJarFactory.java delete mode 100644 src/main/java/net/fabricmc/loom/build/nesting/MergedNestedJarProvider.java delete mode 100644 src/main/java/net/fabricmc/loom/build/nesting/NestedDependencyProvider.java delete mode 100644 src/main/java/net/fabricmc/loom/build/nesting/NestedJarPathProvider.java delete mode 100644 src/main/java/net/fabricmc/loom/build/nesting/NestedJarProvider.java delete mode 100644 src/main/java/net/fabricmc/loom/configuration/JarManifestConfiguration.java delete mode 100644 src/main/java/net/fabricmc/loom/configuration/RemapConfiguration.java create mode 100644 src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java delete mode 100644 src/main/java/net/fabricmc/loom/task/RemapAllSourcesTask.java create mode 100644 src/main/java/net/fabricmc/loom/task/RemapTaskConfiguration.java create mode 100644 src/main/java/net/fabricmc/loom/task/service/JarManifestService.java create mode 100644 src/main/java/net/fabricmc/loom/task/service/MappingsService.java create mode 100644 src/main/java/net/fabricmc/loom/task/service/SourceRemapperService.java delete mode 100644 src/test/groovy/net/fabricmc/loom/test/unit/MergedNestedJarProviderTest.groovy diff --git a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java index 5d4e88e..f1edd74 100644 --- a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java +++ b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java @@ -26,7 +26,6 @@ package net.fabricmc.loom; import java.io.File; import java.util.List; -import java.util.Set; import java.util.function.Supplier; import org.cadixdev.lorenz.MappingSet; @@ -36,6 +35,8 @@ import org.gradle.api.NamedDomainObjectProvider; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.file.FileCollection; +import org.gradle.api.tasks.SourceSet; import net.fabricmc.loom.api.LoomGradleExtensionAPI; import net.fabricmc.loom.configuration.InstallerData; @@ -94,9 +95,9 @@ public interface LoomGradleExtension extends LoomGradleExtensionAPI { return getMappingsProvider().mappedProvider; } - File getNextMixinMappings(); + File getMixinMappings(SourceSet sourceSet); - Set getAllMixinMappings(); + FileCollection getAllMixinMappings(); boolean isRootProject(); diff --git a/src/main/java/net/fabricmc/loom/build/JarRemapper.java b/src/main/java/net/fabricmc/loom/build/JarRemapper.java deleted file mode 100644 index 877d878..0000000 --- a/src/main/java/net/fabricmc/loom/build/JarRemapper.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * This file is part of fabric-loom, licensed under the MIT License (MIT). - * - * Copyright (c) 2020 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.build; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.function.BiConsumer; -import java.util.function.BiFunction; - -import org.gradle.api.Action; -import org.objectweb.asm.commons.Remapper; - -import net.fabricmc.loom.util.CloseableList; -import net.fabricmc.stitch.util.Pair; -import net.fabricmc.tinyremapper.IMappingProvider; -import net.fabricmc.tinyremapper.InputTag; -import net.fabricmc.tinyremapper.OutputConsumerPath; -import net.fabricmc.tinyremapper.TinyRemapper; - -public class JarRemapper { - private final List mappingProviders = new ArrayList<>(); - private final Set classPath = new HashSet<>(); - private final List remapData = new ArrayList<>(); - private List> remapOptions; - - public void addMappings(IMappingProvider mappingProvider) { - mappingProviders.add(mappingProvider); - } - - public void addToClasspath(Path... paths) { - classPath.addAll(Arrays.asList(paths)); - } - - public RemapData scheduleRemap(Path input, Path output) { - RemapData data = new RemapData(input, output); - remapData.add(data); - return data; - } - - public void remap() throws IOException { - TinyRemapper.Builder remapperBuilder = TinyRemapper.newRemapper(); - mappingProviders.forEach(remapperBuilder::withMappings); - - if (remapOptions != null) { - for (Action remapOption : remapOptions) { - remapOption.execute(remapperBuilder); - } - } - - TinyRemapper remapper = remapperBuilder.build(); - - Path[] remapClasspath = classPath.stream() - .filter(path -> - remapData.stream().noneMatch(remapData -> remapData.input.equals(path)) - ) - .toArray(Path[]::new); - - remapper.readClassPathAsync(remapClasspath); - - for (RemapData data : remapData) { - InputTag tag = remapper.createInputTag(); - data.tag = tag; - remapper.readInputsAsync(tag, data.input); - } - - //noinspection MismatchedQueryAndUpdateOfCollection - try (CloseableList outputConsumers = new CloseableList<>()) { - for (RemapData data : remapData) { - OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(data.output).build(); - outputConsumers.add(outputConsumer); - - outputConsumer.addNonClassFiles(data.input); - - data.processAccessWidener(remapper.getEnvironment().getRemapper()); - remapper.apply(outputConsumer, data.tag); - } - - remapper.finish(); - } catch (Exception e) { - for (RemapData data : remapData) { - // Cleanup bad outputs - Files.deleteIfExists(data.output); - } - - throw new IOException("Failed to remap %s files".formatted(remapData.size()), e); - } - - remapData.forEach(RemapData::complete); - } - - public void addOptions(List> remapOptions) { - this.remapOptions = remapOptions; - } - - public static class RemapData { - public final Path input; - public final Path output; - BiFunction> accesWidenerSupplier; - BiConsumer> onComplete; - - private InputTag tag; - private Pair accessWidener; - - public RemapData(Path input, Path output) { - this.input = input; - this.output = output; - } - - public RemapData complete(BiConsumer> onComplete) { - this.onComplete = onComplete; - return this; - } - - public RemapData supplyAccessWidener(BiFunction> beforeFinish) { - this.accesWidenerSupplier = beforeFinish; - return this; - } - - private void complete() { - if (onComplete != null) { - onComplete.accept(this, accessWidener); - } - } - - private void processAccessWidener(Remapper remapper) { - if (accesWidenerSupplier != null) { - accessWidener = accesWidenerSupplier.apply(this, remapper); - } - } - } -} diff --git a/src/main/java/net/fabricmc/loom/build/MixinRefmapHelper.java b/src/main/java/net/fabricmc/loom/build/MixinRefmapHelper.java index 4d1ba26..49cde0d 100644 --- a/src/main/java/net/fabricmc/loom/build/MixinRefmapHelper.java +++ b/src/main/java/net/fabricmc/loom/build/MixinRefmapHelper.java @@ -27,13 +27,9 @@ package net.fabricmc.loom.build; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; -import java.io.UncheckedIOException; -import java.nio.file.Path; import java.util.Collection; import java.util.Collections; -import java.util.Objects; import java.util.stream.Collectors; -import java.util.stream.Stream; import java.util.stream.StreamSupport; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -41,74 +37,35 @@ import java.util.zip.ZipFile; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; -import org.gradle.api.Project; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.LoomGradlePlugin; -import net.fabricmc.loom.extension.MixinExtension; -import net.fabricmc.loom.util.Pair; -import net.fabricmc.loom.util.ZipUtils; public final class MixinRefmapHelper { private MixinRefmapHelper() { } private static final String FABRIC_MOD_JSON = "fabric.mod.json"; - public static boolean addRefmapName(Project project, Path outputPath) { - try { - MixinExtension mixin = LoomGradleExtension.get(project).getMixin(); - File output = outputPath.toFile(); - - Collection allMixinConfigs = getMixinConfigurationFiles(readFabricModJson(output)); - - return mixin.getMixinSourceSetsStream().map(sourceSet -> { - MixinExtension.MixinInformationContainer container = Objects.requireNonNull( - MixinExtension.getMixinInformationContainer(sourceSet) - ); - - Stream mixinConfigs = sourceSet.getResources() - .matching(container.mixinConfigPattern()) - .getFiles() - .stream() - .map(File::getName) - .filter(allMixinConfigs::contains); - - String refmapName = container.refmapNameProvider().get(); - - try { - return ZipUtils.transformJson(JsonObject.class, outputPath, mixinConfigs.map(f -> new Pair<>(f, json -> { - if (!json.has("refmap")) { - json.addProperty("refmap", refmapName); - } - - return json; - }))) > 0; - } catch (IOException e) { - throw new UncheckedIOException("Failed to transform mixin configs in jar", e); - } - }).reduce(false, Boolean::logicalOr); - } catch (Exception e) { - project.getLogger().error(e.getMessage()); - return false; - } - } - - @NotNull - private static JsonObject readFabricModJson(File output) { + @Nullable + public static JsonObject readFabricModJson(File output) { try (ZipFile zip = new ZipFile(output)) { ZipEntry entry = zip.getEntry(FABRIC_MOD_JSON); + if (entry == null) { + return null; + } + try (InputStreamReader reader = new InputStreamReader(zip.getInputStream(entry))) { return LoomGradlePlugin.GSON.fromJson(reader, JsonObject.class); } } catch (IOException e) { - throw new RuntimeException("Cannot read file fabric.mod.json in the output jar.", e); + throw new RuntimeException("Cannot read file fabric.mod.json in the jar.", e); } } @NotNull - private static Collection getMixinConfigurationFiles(JsonObject fabricModJson) { + public static Collection getMixinConfigurationFiles(JsonObject fabricModJson) { JsonArray mixins = fabricModJson.getAsJsonArray("mixins"); if (mixins == null) { diff --git a/src/main/java/net/fabricmc/loom/build/mixin/AnnotationProcessorInvoker.java b/src/main/java/net/fabricmc/loom/build/mixin/AnnotationProcessorInvoker.java index b8203ab..7378050 100644 --- a/src/main/java/net/fabricmc/loom/build/mixin/AnnotationProcessorInvoker.java +++ b/src/main/java/net/fabricmc/loom/build/mixin/AnnotationProcessorInvoker.java @@ -84,7 +84,7 @@ public abstract class AnnotationProcessorInvoker { String refmapName = Objects.requireNonNull(MixinExtension.getMixinInformationContainer(sourceSet)).refmapNameProvider().get(); Map args = new HashMap<>() {{ put(Constants.MixinArguments.IN_MAP_FILE_NAMED_INTERMEDIARY, loom.getMappingsProvider().tinyMappings.toFile().getCanonicalPath()); - put(Constants.MixinArguments.OUT_MAP_FILE_NAMED_INTERMEDIARY, loom.getNextMixinMappings().getCanonicalPath()); + put(Constants.MixinArguments.OUT_MAP_FILE_NAMED_INTERMEDIARY, loom.getMixinMappings(sourceSet).getCanonicalPath()); put(Constants.MixinArguments.OUT_REFMAP_FILE, getRefmapDestination(task, refmapName)); put(Constants.MixinArguments.DEFAULT_OBFUSCATION_ENV, "named:intermediary"); }}; diff --git a/src/main/java/net/fabricmc/loom/build/nesting/IncludedJarFactory.java b/src/main/java/net/fabricmc/loom/build/nesting/IncludedJarFactory.java new file mode 100644 index 0000000..610b720 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/build/nesting/IncludedJarFactory.java @@ -0,0 +1,203 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 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.build.nesting; + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.util.Collection; +import java.util.Locale; +import java.util.Set; + +import com.google.common.collect.Sets; +import com.google.gson.JsonObject; +import org.apache.commons.io.FileUtils; +import org.gradle.api.Project; +import org.gradle.api.Task; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.artifacts.Dependency; +import org.gradle.api.artifacts.ProjectDependency; +import org.gradle.api.artifacts.ResolvedArtifact; +import org.gradle.api.artifacts.ResolvedConfiguration; +import org.gradle.api.artifacts.ResolvedDependency; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.plugins.JavaPlugin; +import org.gradle.api.provider.Provider; +import org.gradle.api.tasks.bundling.AbstractArchiveTask; +import org.jetbrains.annotations.Nullable; + +import net.fabricmc.loom.LoomGradleExtension; +import net.fabricmc.loom.LoomGradlePlugin; +import net.fabricmc.loom.task.RemapTaskConfiguration; +import net.fabricmc.loom.util.ModUtils; +import net.fabricmc.loom.util.ZipUtils; + +public final class IncludedJarFactory { + private final Project project; + + public IncludedJarFactory(Project project) { + this.project = project; + } + + public Provider getNestedJars(final Configuration configuration) { + return project.provider(() -> { + final ConfigurableFileCollection files = project.files(); + final Set visited = Sets.newHashSet(); + + files.from(getProjectDeps(configuration, visited)); + files.from(getFileDeps(configuration, visited)); + files.builtBy(configuration.getBuildDependencies()); + return files; + }); + } + + private ConfigurableFileCollection getFileDeps(Configuration configuration, Set visited) { + final ConfigurableFileCollection files = project.files(); + + final ResolvedConfiguration resolvedConfiguration = configuration.getResolvedConfiguration(); + final Set dependencies = resolvedConfiguration.getFirstLevelModuleDependencies(); + + for (ResolvedDependency dependency : dependencies) { + if (!visited.add(dependency.getModuleGroup() + ":" + dependency.getModuleName() + ":" + dependency.getModuleVersion())) { + continue; + } + + for (ResolvedArtifact artifact : dependency.getModuleArtifacts()) { + Metadata metadata = new Metadata( + dependency.getModuleGroup(), + dependency.getModuleName(), + dependency.getModuleVersion(), + artifact.getClassifier() + ); + + files.from(project.provider(() -> getNestableJar(artifact.getFile(), metadata))); + } + } + + return files; + } + + private ConfigurableFileCollection getProjectDeps(Configuration configuration, Set visited) { + final ConfigurableFileCollection files = project.files(); + + for (Dependency dependency : configuration.getDependencies()) { + if (dependency instanceof ProjectDependency projectDependency) { + if (!visited.add(dependency.getGroup() + ":" + dependency.getName() + ":" + dependency.getVersion())) { + continue; + } + + // Get the outputs of the project + final Project dependentProject = projectDependency.getDependencyProject(); + + Collection remapJarTasks = dependentProject.getTasksByName(RemapTaskConfiguration.REMAP_JAR_TASK_NAME, false); + Collection jarTasks = dependentProject.getTasksByName(JavaPlugin.JAR_TASK_NAME, false); + + if (remapJarTasks.isEmpty() && jarTasks.isEmpty()) { + throw new UnsupportedOperationException("%s does not have a remapJar or jar task, cannot nest it".formatted(dependentProject.getName())); + } + + for (Task task : remapJarTasks.isEmpty() ? jarTasks : remapJarTasks) { + if (task instanceof AbstractArchiveTask archiveTask) { + final Metadata metadata = new Metadata( + projectDependency.getGroup(), + projectDependency.getName(), + projectDependency.getVersion(), + archiveTask.getArchiveClassifier().getOrNull() + ); + + Provider provider = archiveTask.getArchiveFile().map(regularFile -> getNestableJar(regularFile.getAsFile(), metadata)); + files.from(provider); + files.builtBy(task); + } else { + throw new UnsupportedOperationException("Cannot nest none AbstractArchiveTask task: " + task.getName()); + } + } + } + } + + return files; + } + + private File getNestableJar(final File input, final Metadata metadata) { + if (ModUtils.isMod(input)) { + // Input is a mod, nothing needs to be done. + return input; + } + + LoomGradleExtension extension = LoomGradleExtension.get(project); + File tempDir = new File(extension.getFiles().getUserCache(), "temp/modprocessing"); + + if (!tempDir.exists()) { + tempDir.mkdirs(); + } + + File tempFile = new File(tempDir, input.getName()); + + if (tempFile.exists()) { + tempFile.delete(); + } + + try { + FileUtils.copyFile(input, tempFile); + ZipUtils.add(tempFile.toPath(), "fabric.mod.json", generateModForDependency(metadata).getBytes(StandardCharsets.UTF_8)); + } catch (IOException e) { + throw new UncheckedIOException("Failed to add dummy mod while including %s".formatted(input), e); + } + + return tempFile; + } + + // Generates a barebones mod for a dependency + private static String generateModForDependency(Metadata metadata) { + final String modId = (metadata.group() + "_" + metadata.name() + metadata.classifier()) + .replaceAll("\\.", "_") + .toLowerCase(Locale.ENGLISH); + + final JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("schemaVersion", 1); + + jsonObject.addProperty("id", modId); + jsonObject.addProperty("version", metadata.version()); + jsonObject.addProperty("name", metadata.name()); + + JsonObject custom = new JsonObject(); + custom.addProperty("fabric-loom:generated", true); + jsonObject.add("custom", custom); + + return LoomGradlePlugin.GSON.toJson(jsonObject); + } + + private record Metadata(String group, String name, String version, @Nullable String classifier) { + @Override + public String classifier() { + if (classifier == null) { + return ""; + } else { + return "_" + classifier; + } + } + } +} diff --git a/src/main/java/net/fabricmc/loom/build/nesting/JarNester.java b/src/main/java/net/fabricmc/loom/build/nesting/JarNester.java index efae834..06bf4b5 100644 --- a/src/main/java/net/fabricmc/loom/build/nesting/JarNester.java +++ b/src/main/java/net/fabricmc/loom/build/nesting/JarNester.java @@ -36,7 +36,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import org.gradle.api.UncheckedIOException; -import org.gradle.api.logging.Logger; +import org.slf4j.Logger; import net.fabricmc.loom.util.ModUtils; import net.fabricmc.loom.util.Pair; @@ -69,6 +69,7 @@ public class JarNester { for (File file : jars) { String nestedJarPath = "META-INF/jars/" + file.getName(); + Preconditions.checkArgument(ModUtils.isMod(file), "Cannot nest none mod jar: " + file.getName()); for (JsonElement nestedJar : nestedJars) { JsonObject jsonObject = nestedJar.getAsJsonObject(); diff --git a/src/main/java/net/fabricmc/loom/build/nesting/MergedNestedJarProvider.java b/src/main/java/net/fabricmc/loom/build/nesting/MergedNestedJarProvider.java deleted file mode 100644 index 48b4db0..0000000 --- a/src/main/java/net/fabricmc/loom/build/nesting/MergedNestedJarProvider.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * This file is part of fabric-loom, licensed under the MIT License (MIT). - * - * Copyright (c) 2016-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.build.nesting; - -import java.io.File; -import java.util.Arrays; -import java.util.Collection; -import java.util.stream.Collectors; - -import org.gradle.api.Project; - -public record MergedNestedJarProvider(NestedJarProvider... children) implements NestedJarProvider { - @Override - public Collection provide() { - return Arrays.stream(children) - .map(NestedJarProvider::provide) - .flatMap(Collection::stream) - .collect(Collectors.toList()); - } - - @Override - public void prepare(Project project) { - Arrays.stream(children).forEach(nestedJarProvider -> nestedJarProvider.prepare(project)); - } -} diff --git a/src/main/java/net/fabricmc/loom/build/nesting/NestedDependencyProvider.java b/src/main/java/net/fabricmc/loom/build/nesting/NestedDependencyProvider.java deleted file mode 100644 index a911d30..0000000 --- a/src/main/java/net/fabricmc/loom/build/nesting/NestedDependencyProvider.java +++ /dev/null @@ -1,282 +0,0 @@ -/* - * This file is part of fabric-loom, licensed under the MIT License (MIT). - * - * Copyright (c) 2019-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.build.nesting; - -import java.io.File; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.Set; - -import javax.annotation.Nullable; - -import com.google.gson.JsonObject; -import org.apache.commons.io.FileUtils; -import org.gradle.api.Project; -import org.gradle.api.Task; -import org.gradle.api.artifacts.Configuration; -import org.gradle.api.artifacts.Dependency; -import org.gradle.api.artifacts.DependencySet; -import org.gradle.api.artifacts.ProjectDependency; -import org.gradle.api.artifacts.ResolvedArtifact; -import org.gradle.api.artifacts.ResolvedConfiguration; -import org.gradle.api.artifacts.ResolvedDependency; -import org.gradle.api.tasks.bundling.AbstractArchiveTask; - -import net.fabricmc.loom.LoomGradleExtension; -import net.fabricmc.loom.LoomGradlePlugin; -import net.fabricmc.loom.task.RemapJarTask; -import net.fabricmc.loom.util.Constants; -import net.fabricmc.loom.util.ModUtils; -import net.fabricmc.loom.util.ZipUtils; - -public final class NestedDependencyProvider implements NestedJarProvider { - final Project project; - final List> files; - - private NestedDependencyProvider(Project project, List> files) { - this.project = project; - this.files = files; - } - - public static NestedDependencyProvider createNestedDependencyProviderFromConfiguration(Project project, Configuration configuration) { - List> fileList = new ArrayList<>(); - Set visited = new HashSet<>(); - - fileList.addAll(populateProjectDependencies(configuration, visited)); - fileList.addAll(populateResolvedDependencies(configuration, visited)); - - return new NestedDependencyProvider(project, fileList); - } - - // Looks for any deps that require a sub project to be built first - public static List getRequiredTasks(Project project) { - List remapTasks = new ArrayList<>(); - - Configuration configuration = project.getConfigurations().getByName(Constants.Configurations.INCLUDE); - DependencySet dependencies = configuration.getDependencies(); - - for (Dependency dependency : dependencies) { - if (dependency instanceof ProjectDependency projectDependency) { - Project dependencyProject = projectDependency.getDependencyProject(); - - for (Task task : dependencyProject.getTasksByName("remapJar", false)) { - if (task instanceof RemapJarTask remapJarTask) { - remapTasks.add(remapJarTask); - } - } - } - } - - return remapTasks; - } - - private static List> populateProjectDependencies(Configuration configuration, Set visited) { - List> fileList = new ArrayList<>(); - - for (Dependency dependency : configuration.getDependencies()) { - if (dependency instanceof ProjectDependency projectDependency) { - Project dependencyProject = projectDependency.getDependencyProject(); - - visited.add(dependency.getGroup() + ":" + dependency.getName() + ":" + dependency.getVersion()); - - Collection remapJarTasks = dependencyProject.getTasksByName("remapJar", false); - Collection jarTasks = dependencyProject.getTasksByName("jar", false); - - for (Task task : remapJarTasks.isEmpty() ? jarTasks : remapJarTasks) { - if (task instanceof AbstractArchiveTask abstractArchiveTask) { - fileList.add(new DependencyInfo<>( - projectDependency, - new ProjectDependencyMetaExtractor(), - abstractArchiveTask.getArchiveFile().get().getAsFile(), - abstractArchiveTask.getArchiveClassifier().getOrNull() - )); - } - } - } - } - - return fileList; - } - - private static List> populateResolvedDependencies(Configuration configuration, Set visited) { - ResolvedConfiguration resolvedConfiguration = configuration.getResolvedConfiguration(); - Set dependencies = resolvedConfiguration.getFirstLevelModuleDependencies(); - - List> fileList = new ArrayList<>(); - - for (ResolvedDependency dependency : dependencies) { - if (visited.contains(dependency.getModuleGroup() + ":" + dependency.getModuleName() + ":" + dependency.getModuleVersion())) { - continue; - } - - for (ResolvedArtifact artifact : dependency.getModuleArtifacts()) { - fileList.add(new DependencyInfo<>( - dependency, - new ResolvedDependencyMetaExtractor(), - artifact.getFile(), - artifact.getClassifier() - )); - } - } - - return fileList; - } - - @Override - public List provide() { - List fileList = new ArrayList<>(); - - for (DependencyInfo metaFile : files) { - metaFile.validateInputs(); - - File file = metaFile.file; - - //A lib that doesnt have a mod.json, we turn it into a fake mod - if (!ModUtils.isMod(file)) { - LoomGradleExtension extension = LoomGradleExtension.get(project); - File tempDir = new File(extension.getFiles().getUserCache(), "temp/modprocessing"); - - if (!tempDir.exists()) { - tempDir.mkdirs(); - } - - File tempFile = new File(tempDir, file.getName()); - - if (tempFile.exists()) { - tempFile.delete(); - } - - try { - FileUtils.copyFile(file, tempFile); - } catch (IOException e) { - throw new RuntimeException("Failed to copy file", e); - } - - try { - ZipUtils.add(tempFile.toPath(), "fabric.mod.json", generateModForDependency(metaFile).getBytes()); - } catch (IOException e) { - throw new UncheckedIOException("Failed to add dummy mod while including %s".formatted(file), e); - } - - fileList.add(tempFile); - } else { - // Default copy the jar right in - fileList.add(file); - } - } - - return fileList; - } - - // Generates a barebones mod for a dependency - private static String generateModForDependency(DependencyInfo info) { - DependencyMetaExtractor metaExtractor = info.metaExtractor; - D dependency = info.dependency; - - JsonObject jsonObject = new JsonObject(); - jsonObject.addProperty("schemaVersion", 1); - - jsonObject.addProperty("id", - (metaExtractor.group(dependency) + "_" + metaExtractor.name(dependency) + info.getClassifierSuffix()) - .replaceAll("\\.", "_") - .toLowerCase(Locale.ENGLISH) - ); - jsonObject.addProperty("version", metaExtractor.version(dependency)); - jsonObject.addProperty("name", metaExtractor.name(dependency)); - - JsonObject custom = new JsonObject(); - custom.addProperty("fabric-loom:generated", true); - jsonObject.add("custom", custom); - - return LoomGradlePlugin.GSON.toJson(jsonObject); - } - - private record DependencyInfo(D dependency, DependencyMetaExtractor metaExtractor, File file, @Nullable String classifier) { - void validateInputs() { - if (!file.exists()) { - throw new RuntimeException("Failed to include nested jars, as it could not be found @ " + file.getAbsolutePath()); - } - - if (file.isDirectory() || !file.getName().endsWith(".jar")) { - throw new RuntimeException("Failed to include nested jars, as file was not a jar: " + file.getAbsolutePath()); - } - } - - String getClassifierSuffix() { - if (classifier == null) { - return ""; - } else { - return "_" + classifier; - } - } - } - - private interface DependencyMetaExtractor { - String group(D dependency); - - String version(D dependency); - - String name(D dependency); - } - - private static final class ProjectDependencyMetaExtractor implements DependencyMetaExtractor { - @Override - public String group(ProjectDependency dependency) { - return dependency.getGroup(); - } - - @Override - public String version(ProjectDependency dependency) { - return dependency.getVersion(); - } - - @Override - public String name(ProjectDependency dependency) { - return dependency.getName(); - } - } - - private static final class ResolvedDependencyMetaExtractor implements DependencyMetaExtractor { - @Override - public String group(ResolvedDependency dependency) { - return dependency.getModuleGroup(); - } - - @Override - public String version(ResolvedDependency dependency) { - return dependency.getModuleVersion(); - } - - @Override - public String name(ResolvedDependency dependency) { - return dependency.getModuleName(); - } - } -} diff --git a/src/main/java/net/fabricmc/loom/build/nesting/NestedJarPathProvider.java b/src/main/java/net/fabricmc/loom/build/nesting/NestedJarPathProvider.java deleted file mode 100644 index deccda4..0000000 --- a/src/main/java/net/fabricmc/loom/build/nesting/NestedJarPathProvider.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * This file is part of fabric-loom, licensed under the MIT License (MIT). - * - * Copyright (c) 2016-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.build.nesting; - -import java.io.File; -import java.util.Collection; -import java.util.Set; - -import com.google.common.base.Preconditions; -import org.gradle.api.Project; - -import net.fabricmc.loom.util.ModUtils; - -public final class NestedJarPathProvider implements NestedJarProvider { - private final Set nestedPaths; - private Set files = null; - public NestedJarPathProvider(Set nestedPaths) { - this.nestedPaths = nestedPaths; - } - - private Set resolve(Project project) { - return project.files(nestedPaths).getFiles(); - } - - @Override - public void prepare(Project project) { - if (files == null) { - files = resolve(project); - } - } - - @Override - public Collection provide() { - validateFiles(); - return files; - } - - private void validateFiles() { - Preconditions.checkNotNull(files, "null files to nest, was prepare called?"); - - for (File file : files) { - Preconditions.checkArgument(file.getName().endsWith(".jar"), String.format("Tried to nest %s but it is not a jar", file.getAbsolutePath())); - Preconditions.checkArgument(file.exists(), String.format("Tried to nest jar %s but it does not exist", file.getAbsolutePath())); - Preconditions.checkArgument(ModUtils.isMod(file), String.format("Cannot use nest none mod jar %s", file.getAbsolutePath())); - } - } -} diff --git a/src/main/java/net/fabricmc/loom/build/nesting/NestedJarProvider.java b/src/main/java/net/fabricmc/loom/build/nesting/NestedJarProvider.java deleted file mode 100644 index 79c605c..0000000 --- a/src/main/java/net/fabricmc/loom/build/nesting/NestedJarProvider.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * This file is part of fabric-loom, licensed under the MIT License (MIT). - * - * Copyright (c) 2016-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.build.nesting; - -import java.io.File; -import java.util.Collection; - -import org.gradle.api.Project; -import org.jetbrains.annotations.ApiStatus; - -@ApiStatus.Internal -public interface NestedJarProvider { - // provide all the files to be included, they should already be resolved but can be transformed here - Collection provide(); - - // Setup the files ready to be provided - default void prepare(Project project) { } -} diff --git a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java index 74abad3..719e90d 100644 --- a/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java +++ b/src/main/java/net/fabricmc/loom/configuration/CompileConfiguration.java @@ -35,7 +35,6 @@ import org.gradle.api.tasks.AbstractCopyTask; import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.compile.JavaCompile; import org.gradle.api.tasks.javadoc.Javadoc; -import org.gradle.jvm.tasks.Jar; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.build.mixin.JavaApInvoker; @@ -124,6 +123,7 @@ public final class CompileConfiguration { public static void configureCompile(Project p) { final JavaPluginExtension javaPluginExtension = p.getExtensions().getByType(JavaPluginExtension.class); + LoomGradleExtension extension = LoomGradleExtension.get(p); SourceSet main = javaPluginExtension.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME); @@ -131,8 +131,6 @@ public final class CompileConfiguration { javadoc.setClasspath(main.getOutput().plus(main.getCompileClasspath())); p.afterEvaluate(project -> { - LoomGradleExtension extension = LoomGradleExtension.get(project); - LoomDependencyManager dependencyManager = new LoomDependencyManager(); extension.setDependencyManager(dependencyManager); @@ -148,14 +146,6 @@ public final class CompileConfiguration { extension.getRemapArchives().finalizeValue(); - // Enables the default mod remapper - if (extension.getRemapArchives().get()) { - RemapConfiguration.setupDefaultRemap(project); - } else { - Jar jarTask = (Jar) project.getTasks().getByName("jar"); - extension.getUnmappedModCollection().from(jarTask); - } - MixinExtension mixin = LoomGradleExtension.get(project).getMixin(); if (mixin.getUseLegacyMixinAp().get()) { diff --git a/src/main/java/net/fabricmc/loom/configuration/JarManifestConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/JarManifestConfiguration.java deleted file mode 100644 index eeeb4d2..0000000 --- a/src/main/java/net/fabricmc/loom/configuration/JarManifestConfiguration.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * This file is part of fabric-loom, licensed under the MIT License (MIT). - * - * Copyright (c) 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; - -import java.util.Optional; -import java.util.jar.Attributes; -import java.util.jar.Manifest; - -import org.gradle.api.Project; -import org.gradle.api.artifacts.Dependency; -import org.gradle.util.GradleVersion; - -import net.fabricmc.loom.LoomGradleExtension; -import net.fabricmc.loom.LoomGradlePlugin; -import net.fabricmc.loom.util.Constants; -import net.fabricmc.tinyremapper.TinyRemapper; - -public final record JarManifestConfiguration(Project project) { - public void configure(Manifest manifest) { - // Dont set when running the reproducible build tests as it will break them when anything updates - if (Boolean.getBoolean("loom.test.reproducible")) { - return; - } - - LoomGradleExtension extension = LoomGradleExtension.get(project); - - Attributes attributes = manifest.getMainAttributes(); - Optional tinyRemapperVersion = Optional.ofNullable(TinyRemapper.class.getPackage().getImplementationVersion()); - - attributes.putValue("Fabric-Gradle-Version", GradleVersion.current().getVersion()); - attributes.putValue("Fabric-Loom-Version", LoomGradlePlugin.LOOM_VERSION); - attributes.putValue("Fabric-Mixin-Compile-Extensions-Version", Constants.Dependencies.Versions.MIXIN_COMPILE_EXTENSIONS); - attributes.putValue("Fabric-Minecraft-Version", extension.getMinecraftProvider().minecraftVersion()); - tinyRemapperVersion.ifPresent(s -> attributes.putValue("Fabric-Tiny-Remapper-Version", s)); - getLoaderVersion().ifPresent(s -> attributes.putValue("Fabric-Loader-Version", s)); - - // This can be overridden by mods if required - if (!attributes.containsKey("Fabric-Mixin-Version")) { - addMixinVersion(attributes); - } - } - - private void addMixinVersion(Attributes attributes) { - // Not super ideal that this uses the mod compile classpath, should prob look into making this not a thing at somepoint - Optional dependency = project.getConfigurations().getByName(Constants.Configurations.LOADER_DEPENDENCIES) - .getDependencies() - .stream() - .filter(dep -> "sponge-mixin".equals(dep.getName())) - .findFirst(); - - if (dependency.isEmpty()) { - project.getLogger().warn("Could not determine Mixin version for jar manifest"); - return; - } - - attributes.putValue("Fabric-Mixin-Version", dependency.get().getVersion()); - attributes.putValue("Fabric-Mixin-Group", dependency.get().getGroup()); - } - - private Optional getLoaderVersion() { - LoomGradleExtension extension = LoomGradleExtension.get(project); - - if (extension.getInstallerData() == null) { - project.getLogger().warn("Could not determine fabric loader version for jar manifest"); - return Optional.empty(); - } - - return Optional.of(extension.getInstallerData().version()); - } -} diff --git a/src/main/java/net/fabricmc/loom/configuration/RemapConfiguration.java b/src/main/java/net/fabricmc/loom/configuration/RemapConfiguration.java deleted file mode 100644 index efbf5a1..0000000 --- a/src/main/java/net/fabricmc/loom/configuration/RemapConfiguration.java +++ /dev/null @@ -1,220 +0,0 @@ -/* - * This file is part of fabric-loom, licensed under the MIT License (MIT). - * - * Copyright (c) 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; - -import java.io.IOException; - -import com.google.common.base.Preconditions; -import org.gradle.api.Action; -import org.gradle.api.Project; -import org.gradle.api.Task; -import org.gradle.api.UnknownTaskException; -import org.gradle.api.artifacts.ConfigurablePublishArtifact; -import org.gradle.api.artifacts.Configuration; -import org.gradle.api.artifacts.PublishArtifact; -import org.gradle.api.artifacts.dsl.ArtifactHandler; -import org.gradle.api.plugins.JavaPlugin; -import org.gradle.api.tasks.bundling.AbstractArchiveTask; -import org.jetbrains.annotations.ApiStatus; - -import net.fabricmc.loom.LoomGradleExtension; -import net.fabricmc.loom.build.JarRemapper; -import net.fabricmc.loom.build.nesting.NestedDependencyProvider; -import net.fabricmc.loom.task.AbstractLoomTask; -import net.fabricmc.loom.task.RemapAllSourcesTask; -import net.fabricmc.loom.task.RemapJarTask; -import net.fabricmc.loom.task.RemapSourcesJarTask; -import net.fabricmc.loom.util.SourceRemapper; - -public class RemapConfiguration { - private static final String DEFAULT_JAR_TASK_NAME = JavaPlugin.JAR_TASK_NAME; - private static final String DEFAULT_SOURCES_JAR_TASK_NAME = "sourcesJar"; - private static final String DEFAULT_REMAP_JAR_TASK_NAME = "remapJar"; - private static final String DEFAULT_REMAP_SOURCES_JAR_TASK_NAME = "remapSourcesJar"; - private static final String DEFAULT_REMAP_ALL_JARS_TASK_NAME = "remapAllJars"; - private static final String DEFAULT_REMAP_ALL_SOURCES_TASK_NAME = "remapAllSources"; - - public static void setupDefaultRemap(Project project) { - setupRemap(project, true, DEFAULT_JAR_TASK_NAME, DEFAULT_SOURCES_JAR_TASK_NAME, DEFAULT_REMAP_JAR_TASK_NAME, DEFAULT_REMAP_SOURCES_JAR_TASK_NAME, DEFAULT_REMAP_ALL_JARS_TASK_NAME, DEFAULT_REMAP_ALL_SOURCES_TASK_NAME); - - LoomGradleExtension extension = LoomGradleExtension.get(project); - extension.getSetupRemappedVariants().finalizeValue(); - - if (extension.getSetupRemappedVariants().get()) { - ArtifactHandler artifacts = project.getArtifacts(); - project.getTasks().named(DEFAULT_REMAP_JAR_TASK_NAME, task -> { - artifacts.add(JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME, task, artifactConfigurationAction(task, DEFAULT_REMAP_JAR_TASK_NAME, project)); - artifacts.add(JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME, task, artifactConfigurationAction(task, DEFAULT_REMAP_JAR_TASK_NAME, project)); - }); - project.getTasks().named(DEFAULT_REMAP_SOURCES_JAR_TASK_NAME, RemapSourcesJarTask.class, task -> { - if (!project.getConfigurations().getNames().contains(JavaPlugin.SOURCES_ELEMENTS_CONFIGURATION_NAME)) { - // Sources jar may not have been created with withSourcesJar - project.getLogger().info("Not publishing sources jar as it was not found. Use java.withSourcesJar() to fix."); - return; - } - - PublishArtifact artifact = artifacts.add(JavaPlugin.SOURCES_ELEMENTS_CONFIGURATION_NAME, task.getOutput(), artifactConfigurationAction(task, DEFAULT_REMAP_ALL_SOURCES_TASK_NAME, project)); - - // Remove the existing artifact that does not run remapSourcesJar. - // It doesn't seem to hurt, but I'm not sure if the file-level duplicates cause issues. - Configuration configuration = project.getConfigurations().getByName(JavaPlugin.SOURCES_ELEMENTS_CONFIGURATION_NAME); - configuration.getArtifacts().removeIf(a -> a != artifact && artifact.getFile().equals(a.getFile())); - }); - - // Remove -dev jars from the default jar task - for (String configurationName : new String[] { JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME, JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME }) { - Configuration configuration = project.getConfigurations().getByName(configurationName); - configuration.getArtifacts().removeIf(artifact -> { - Task jarTask = project.getTasks().getByName(DEFAULT_JAR_TASK_NAME); - // if the artifact is a -dev jar and "builtBy jar" - return "dev".equals(artifact.getClassifier()) && artifact.getBuildDependencies().getDependencies(null).contains(jarTask); - }); - } - } - } - - @ApiStatus.Experimental // This is only an api if you squint really hard, expect it to explode every 5 mins. If you must call in afterEvaluate on all projects - public static void setupRemap(Project project, String jarTaskName, String sourcesJarTaskName, String remapJarTaskName, String remapSourcesJarTaskName, String remapAllJarsTaskName, String remapAllSourcesTaskName) { - setupRemap(project, false, jarTaskName, sourcesJarTaskName, remapJarTaskName, remapSourcesJarTaskName, remapAllJarsTaskName, remapAllSourcesTaskName); - } - - // isDefaultRemap is set to true for the standard remap task, some defaults are left out when this is false. - private static void setupRemap(Project project, boolean isDefaultRemap, String jarTaskName, String sourcesJarTaskName, String remapJarTaskName, String remapSourcesJarTaskName, String remapAllJarsTaskName, String remapAllSourcesTaskName) { - LoomGradleExtension extension = LoomGradleExtension.get(project); - AbstractArchiveTask jarTask = (AbstractArchiveTask) project.getTasks().getByName(jarTaskName); - RemapJarTask remapJarTask = (RemapJarTask) project.getTasks().findByName(remapJarTaskName); - - assert remapJarTask != null; - - if (!remapJarTask.getInput().isPresent() && isDefaultRemap) { - jarTask.getArchiveClassifier().convention("dev"); - remapJarTask.getArchiveClassifier().convention(""); - remapJarTask.getInput().convention(jarTask.getArchiveFile()); - } - - if (isDefaultRemap) { - extension.getUnmappedModCollection().from(jarTask); - remapJarTask.getAddNestedDependencies().convention(true); - remapJarTask.getRemapAccessWidener().convention(true); - - project.getArtifacts().add("archives", remapJarTask); - } - - remapJarTask.dependsOn(jarTask); - project.getTasks().getByName("build").dependsOn(remapJarTask); - - // TODO this might be wrong? - project.getTasks().withType(RemapJarTask.class).forEach(task -> { - if (task.getAddNestedDependencies().getOrElse(false)) { - NestedDependencyProvider.getRequiredTasks(project).forEach(task::dependsOn); - } - }); - - SourceRemapper remapper = null; - // TODO what is this for? - Task parentTask = project.getTasks().getByName("build"); - - if (extension.getShareRemapCaches().get()) { - Project rootProject = project.getRootProject(); - - if (extension.isRootProject()) { - SourceRemapper sourceRemapper = new SourceRemapper(rootProject, false); - JarRemapper jarRemapper = new JarRemapper(); - - remapJarTask.jarRemapper = jarRemapper; - - rootProject.getTasks().register(remapAllSourcesTaskName, RemapAllSourcesTask.class, task -> { - task.sourceRemapper = sourceRemapper; - task.doLast(t -> sourceRemapper.remapAll()); - }); - - parentTask = rootProject.getTasks().getByName(remapAllSourcesTaskName); - - rootProject.getTasks().register(remapAllJarsTaskName, AbstractLoomTask.class, task -> { - task.doLast(t -> { - try { - jarRemapper.remap(); - } catch (IOException e) { - throw new RuntimeException("Failed to remap jars", e); - } - }); - }); - } else { - parentTask = rootProject.getTasks().getByName(remapAllSourcesTaskName); - remapper = ((RemapAllSourcesTask) parentTask).sourceRemapper; - Preconditions.checkNotNull(remapper); - - remapJarTask.jarRemapper = ((RemapJarTask) rootProject.getTasks().getByName(remapJarTaskName)).jarRemapper; - - project.getTasks().getByName("build").dependsOn(parentTask); - project.getTasks().getByName("build").dependsOn(rootProject.getTasks().getByName(remapAllJarsTaskName)); - rootProject.getTasks().getByName(remapAllJarsTaskName).dependsOn(project.getTasks().getByName(remapJarTaskName)); - } - } - - try { - AbstractArchiveTask sourcesTask = (AbstractArchiveTask) project.getTasks().getByName(sourcesJarTaskName); - - RemapSourcesJarTask remapSourcesJarTask = (RemapSourcesJarTask) project.getTasks().findByName(remapSourcesJarTaskName); - Preconditions.checkNotNull(remapSourcesJarTask, "Could not find " + remapSourcesJarTaskName + " in " + project.getName()); - remapSourcesJarTask.getInput().convention(sourcesTask.getArchiveFile()); - remapSourcesJarTask.getOutput().convention(sourcesTask.getArchiveFile()); - remapSourcesJarTask.dependsOn(project.getTasks().getByName(sourcesJarTaskName)); - - if (isDefaultRemap) { - // Do not use lambda here, see: https://github.com/gradle/gradle/pull/17087 - //noinspection Convert2Lambda - remapSourcesJarTask.doLast(new Action<>() { - @Override - public void execute(Task task) { - project.getArtifacts().add("archives", remapSourcesJarTask.getOutput()); - } - }); - } - - if (extension.getShareRemapCaches().get()) { - remapSourcesJarTask.setSourceRemapper(remapper); - } - - parentTask.dependsOn(remapSourcesJarTask); - } catch (UnknownTaskException ignored) { - // pass - } - } - - private static Action artifactConfigurationAction(Task standardTask, String sharedTaskName, Project project) { - LoomGradleExtension extension = LoomGradleExtension.get(project); - - return artifact -> { - Task remapTask = standardTask; - - if (extension.getShareRemapCaches().get()) { - remapTask = project.getRootProject().getTasks().getByName(sharedTaskName); - } - - artifact.builtBy(remapTask); - }; - } -} diff --git a/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerFile.java b/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerFile.java index 893a161..72c39b4 100644 --- a/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerFile.java +++ b/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerFile.java @@ -37,7 +37,7 @@ import com.google.gson.JsonObject; import net.fabricmc.loom.util.ZipUtils; public record AccessWidenerFile( - String name, + String path, String modId, byte[] content ) { @@ -83,7 +83,7 @@ public record AccessWidenerFile( @Override public int hashCode() { - int result = Objects.hash(name, modId); + int result = Objects.hash(path, modId); result = 31 * result + Arrays.hashCode(content); return result; } 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 3baeb08..8b4a2fc 100644 --- a/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerJarProcessor.java +++ b/src/main/java/net/fabricmc/loom/configuration/accesswidener/AccessWidenerJarProcessor.java @@ -34,14 +34,10 @@ import java.util.Arrays; import com.google.common.hash.Hashing; import org.gradle.api.Project; -import org.objectweb.asm.commons.Remapper; import net.fabricmc.accesswidener.AccessWidener; import net.fabricmc.accesswidener.AccessWidenerReader; -import net.fabricmc.accesswidener.AccessWidenerRemapper; -import net.fabricmc.accesswidener.AccessWidenerWriter; import net.fabricmc.loom.LoomGradleExtension; -import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; import net.fabricmc.loom.configuration.processors.JarProcessor; import net.fabricmc.loom.util.ZipUtils; @@ -96,25 +92,6 @@ public class AccessWidenerJarProcessor implements JarProcessor { } } - /** - * Get this mods access widener remapped to the intermediary namespace. - */ - public byte[] getRemappedAccessWidener(Remapper asmRemapper, String targetNamespace) throws IOException { - int version = AccessWidenerReader.readVersion(modAccessWidener); - - AccessWidenerWriter writer = new AccessWidenerWriter(version); - AccessWidenerRemapper remapper = new AccessWidenerRemapper( - writer, - asmRemapper, - MappingsNamespace.NAMED.toString(), - targetNamespace - ); - AccessWidenerReader reader = new AccessWidenerReader(remapper); - reader.read(modAccessWidener); - - return writer.write(); - } - @Override public boolean isInvalid(File file) { byte[] hash; diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProviderImpl.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProviderImpl.java index 8ed07b9..2ab18e9 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProviderImpl.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/MappingsProviderImpl.java @@ -491,6 +491,10 @@ public class MappingsProviderImpl extends DependencyProvider implements Mappings } } + public String getBuildServiceName(String name, String from, String to) { + return "%s:%s:%s>%S".formatted(name, mappingsIdentifier(), from, to); + } + public record UnpickMetadata(String unpickGroup, String unpickVersion) { } } diff --git a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java index 5c98ac4..37077dc 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionImpl.java @@ -26,13 +26,10 @@ package net.fabricmc.loom.extension; import java.io.File; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Set; import java.util.function.Supplier; import org.cadixdev.lorenz.MappingSet; @@ -42,6 +39,8 @@ import org.gradle.api.NamedDomainObjectProvider; import org.gradle.api.Project; import org.gradle.api.artifacts.Configuration; import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.file.FileCollection; +import org.gradle.api.tasks.SourceSet; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.configuration.InstallerData; @@ -55,7 +54,7 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen private final LoomFiles loomFiles; private final ConfigurableFileCollection unmappedMods; - private final Set mixinMappings = Collections.synchronizedSet(new HashSet<>()); + private final ConfigurableFileCollection mixinMappings; private final MappingSet[] srcMappingCache = new MappingSet[2]; private final Mercury[] srcMercuryCache = new Mercury[2]; private final Map> lazyConfigurations = new HashMap<>(); @@ -70,6 +69,7 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen this.project = project; // Initiate with newInstance to allow gradle to decorate our extension this.mixinApExtension = project.getObjects().newInstance(MixinExtensionImpl.class, project); + this.mixinMappings = project.getObjects().fileCollection(); this.loomFiles = files; this.unmappedMods = project.files(); } @@ -85,15 +85,15 @@ public class LoomGradleExtensionImpl extends LoomGradleExtensionApiImpl implemen } @Override - public synchronized File getNextMixinMappings() { - File mixinMapping = new File(getFiles().getProjectBuildCache(), "mixin-map-" + getMappingsProvider().mappingsIdentifier() + "." + mixinMappings.size() + ".tiny"); - mixinMappings.add(mixinMapping); + public synchronized File getMixinMappings(SourceSet sourceSet) { + File mixinMapping = new File(getFiles().getProjectBuildCache(), "mixin-map-" + getMappingsProvider().mappingsIdentifier() + "." + sourceSet.getName() + ".tiny"); + mixinMappings.from(getProject().files(mixinMapping)); return mixinMapping; } @Override - public Set getAllMixinMappings() { - return mixinMappings; + public FileCollection getAllMixinMappings() { + return mixinMappings.filter(File::exists); } @Override diff --git a/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java b/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java new file mode 100644 index 0000000..af022a8 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java @@ -0,0 +1,123 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 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.task; + +import java.io.IOException; +import java.nio.file.Path; + +import javax.inject.Inject; + +import org.gradle.api.Action; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputFile; +import org.gradle.api.tasks.InputFiles; +import org.gradle.jvm.tasks.Jar; +import org.gradle.workers.WorkAction; +import org.gradle.workers.WorkParameters; +import org.gradle.workers.WorkQueue; +import org.gradle.workers.WorkerExecutor; + +import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; +import net.fabricmc.loom.util.ZipReprocessorUtil; + +public abstract class AbstractRemapJarTask extends Jar { + @InputFile + public abstract RegularFileProperty getInputFile(); + + @InputFiles + public abstract ConfigurableFileCollection getClasspath(); + + @Input + public abstract Property getSourceNamespace(); + + @Input + public abstract Property getTargetNamespace(); + + @Inject + protected abstract WorkerExecutor getWorkerExecutor(); + + @Inject + public AbstractRemapJarTask() { + getSourceNamespace().convention(MappingsNamespace.NAMED.toString()).finalizeValueOnRead(); + getTargetNamespace().convention(MappingsNamespace.INTERMEDIARY.toString()).finalizeValueOnRead(); + } + + public final

void submitWork(Class> workAction, Action

action) { + final WorkQueue workQueue = getWorkerExecutor().noIsolation(); + + workQueue.submit(workAction, params -> { + params.getInputFile().set(getInputFile()); + params.getOutputFile().set(getArchiveFile()); + + params.getSourceNamespace().set(getSourceNamespace()); + params.getTargetNamespace().set(getTargetNamespace()); + + params.getArchivePreserveFileTimestamps().set(isPreserveFileTimestamps()); + params.getArchiveReproducibleFileOrder().set(isReproducibleFileOrder()); + + action.execute(params); + }); + } + + public interface AbstractRemapParams extends WorkParameters { + RegularFileProperty getInputFile(); + RegularFileProperty getOutputFile(); + + Property getSourceNamespace(); + Property getTargetNamespace(); + + Property getArchivePreserveFileTimestamps(); + Property getArchiveReproducibleFileOrder(); + } + + public abstract static class AbstractRemapAction implements WorkAction { + protected final Path inputFile; + protected final Path outputFile; + + @Inject + public AbstractRemapAction() { + inputFile = getParameters().getInputFile().getAsFile().get().toPath(); + outputFile = getParameters().getOutputFile().getAsFile().get().toPath(); + } + + protected void rewriteJar() throws IOException { + final boolean isReproducibleFileOrder = getParameters().getArchiveReproducibleFileOrder().get(); + final boolean isPreserveFileTimestamps = getParameters().getArchivePreserveFileTimestamps().get(); + + if (isReproducibleFileOrder || !isPreserveFileTimestamps) { + ZipReprocessorUtil.reprocessZip(outputFile.toFile(), isReproducibleFileOrder, isPreserveFileTimestamps); + } + } + } + + @Deprecated + @InputFile + public RegularFileProperty getInput() { + return getInputFile(); + } +} diff --git a/src/main/java/net/fabricmc/loom/task/LoomTasks.java b/src/main/java/net/fabricmc/loom/task/LoomTasks.java index 42732f8..f34746f 100644 --- a/src/main/java/net/fabricmc/loom/task/LoomTasks.java +++ b/src/main/java/net/fabricmc/loom/task/LoomTasks.java @@ -50,17 +50,13 @@ public final class LoomTasks { t.getOutputs().upToDateWhen(o -> false); }); - tasks.register("remapJar", RemapJarTask.class, t -> { - t.setDescription("Remaps the built project jar to intermediary mappings."); - t.setGroup(Constants.TaskGroup.FABRIC); - }); + RemapTaskConfiguration.setupRemap(project); TaskProvider extractNatives = tasks.register("extractNatives", ExtractNativesTask.class); tasks.register("downloadAssets", DownloadAssetsTask.class, t -> { t.dependsOn(extractNatives); t.setDescription("Downloads required assets for Fabric."); }); - tasks.register("remapSourcesJar", RemapSourcesJarTask.class, t -> t.setDescription("Remaps the project sources jar to intermediary names.")); TaskProvider validateAccessWidener = tasks.register("validateAccessWidener", ValidateAccessWidenerTask.class, t -> { t.setDescription("Validate all the rules in the access widener against the Minecraft jar"); diff --git a/src/main/java/net/fabricmc/loom/task/RemapAllSourcesTask.java b/src/main/java/net/fabricmc/loom/task/RemapAllSourcesTask.java deleted file mode 100644 index 62bff63..0000000 --- a/src/main/java/net/fabricmc/loom/task/RemapAllSourcesTask.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * This file is part of fabric-loom, licensed under the MIT License (MIT). - * - * Copyright (c) 2016-2020 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; - -import org.gradle.api.tasks.Internal; - -import net.fabricmc.loom.util.SourceRemapper; - -public class RemapAllSourcesTask extends AbstractLoomTask { - public SourceRemapper sourceRemapper; - - @Internal - public SourceRemapper getSourceRemapper() { - return sourceRemapper; - } -} diff --git a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java index 62dd881..16b8642 100644 --- a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java +++ b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2016-2021 FabricMC + * Copyright (c) 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 @@ -27,276 +27,281 @@ package net.fabricmc.loom.task; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; -import java.io.UncheckedIOException; +import java.io.Serializable; import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Collections; -import java.util.LinkedHashSet; +import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.Set; +import java.util.Objects; import java.util.jar.Manifest; +import java.util.stream.Collectors; + +import javax.inject.Inject; import com.google.common.base.Preconditions; -import org.gradle.api.Action; -import org.gradle.api.Project; +import com.google.gson.JsonObject; import org.gradle.api.artifacts.Configuration; +import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.FileCollection; -import org.gradle.api.file.RegularFileProperty; import org.gradle.api.plugins.JavaPlugin; +import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.Property; +import org.gradle.api.provider.Provider; import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.InputFile; +import org.gradle.api.tasks.InputFiles; +import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.TaskAction; -import org.gradle.jvm.tasks.Jar; -import org.jetbrains.annotations.ApiStatus; +import org.objectweb.asm.commons.Remapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import net.fabricmc.accesswidener.AccessWidenerReader; +import net.fabricmc.accesswidener.AccessWidenerRemapper; +import net.fabricmc.accesswidener.AccessWidenerWriter; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; -import net.fabricmc.loom.build.JarRemapper; import net.fabricmc.loom.build.MixinRefmapHelper; +import net.fabricmc.loom.build.nesting.IncludedJarFactory; import net.fabricmc.loom.build.nesting.JarNester; -import net.fabricmc.loom.build.nesting.MergedNestedJarProvider; -import net.fabricmc.loom.build.nesting.NestedDependencyProvider; -import net.fabricmc.loom.build.nesting.NestedJarPathProvider; -import net.fabricmc.loom.build.nesting.NestedJarProvider; -import net.fabricmc.loom.configuration.JarManifestConfiguration; import net.fabricmc.loom.configuration.accesswidener.AccessWidenerFile; -import net.fabricmc.loom.configuration.accesswidener.AccessWidenerJarProcessor; -import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; +import net.fabricmc.loom.extension.MixinExtension; +import net.fabricmc.loom.task.service.JarManifestService; +import net.fabricmc.loom.task.service.MappingsService; import net.fabricmc.loom.util.Constants; -import net.fabricmc.loom.util.TinyRemapperHelper; -import net.fabricmc.loom.util.ZipReprocessorUtil; import net.fabricmc.loom.util.ZipUtils; -import net.fabricmc.stitch.util.Pair; +import net.fabricmc.tinyremapper.InputTag; +import net.fabricmc.tinyremapper.OutputConsumerPath; import net.fabricmc.tinyremapper.TinyRemapper; import net.fabricmc.tinyremapper.TinyUtils; -import net.fabricmc.tinyremapper.extension.mixin.MixinExtension; -public class RemapJarTask extends Jar { +public abstract class RemapJarTask extends AbstractRemapJarTask { private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF"; - private final RegularFileProperty input; - private final Property addNestedDependencies; - private final Property addDefaultNestedDependencies; - private final Property remapAccessWidener; - private final List> remapOptions = new ArrayList<>(); - public JarRemapper jarRemapper; - private FileCollection classpath; - private final Set nestedPaths = new LinkedHashSet<>(); + @InputFiles + public abstract ConfigurableFileCollection getNestedJars(); + @Input + public abstract Property getAddNestedDependencies(); + + @Inject public RemapJarTask() { super(); - LoomGradleExtension extension = LoomGradleExtension.get(getProject()); - input = getProject().getObjects().fileProperty(); - addNestedDependencies = getProject().getObjects().property(Boolean.class) - .convention(false); - addDefaultNestedDependencies = getProject().getObjects().property(Boolean.class) - .convention(true); - remapAccessWidener = getProject().getObjects().property(Boolean.class) - .convention(false); - if (!extension.getMixin().getUseLegacyMixinAp().get()) { - remapOptions.add(b -> b.extension(new MixinExtension())); - } + getClasspath().from(getProject().getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME)); + getAddNestedDependencies().convention(true).finalizeValueOnRead(); + + Configuration includeConfiguration = getProject().getConfigurations().getByName(Constants.Configurations.INCLUDE); + getNestedJars().from(new IncludedJarFactory(getProject()).getNestedJars(includeConfiguration)); } @TaskAction - public void doTask() throws Throwable { - boolean singleRemap = false; + public void run() { + final LoomGradleExtension extension = LoomGradleExtension.get(getProject()); - if (jarRemapper == null) { - singleRemap = true; - jarRemapper = new JarRemapper(); + submitWork(RemapAction.class, params -> { + if (getAddNestedDependencies().get()) { + params.getNestedJars().from(getNestedJars()); + } + + params.getJarManifestService().set(JarManifestService.get(getProject())); + params.getRemapClasspath().from(getClasspath()); + params.getMappings().add(MappingsService.createDefault(getProject(), getSourceNamespace().get(), getTargetNamespace().get())); + + final boolean legacyMixin = extension.getMixin().getUseLegacyMixinAp().get(); + params.getUseMixinExtension().set(!legacyMixin); + + if (legacyMixin) { + params.getMixinMappings().from(extension.getAllMixinMappings()); + setupLegacyMixinRefmapRemapping(params); + } + }); + } + + private void setupLegacyMixinRefmapRemapping(RemapParams params) { + final LoomGradleExtension extension = LoomGradleExtension.get(getProject()); + final MixinExtension mixinExtension = extension.getMixin(); + + final JsonObject fabricModJson = MixinRefmapHelper.readFabricModJson(getInputFile().getAsFile().get()); + + if (fabricModJson == null) { + getProject().getLogger().warn("Could not find fabric.mod.json file in: " + getInputFile().getAsFile().get().getName()); + return; } - scheduleRemap(singleRemap || LoomGradleExtension.get(getProject()).isRootProject()); + final Collection allMixinConfigs = MixinRefmapHelper.getMixinConfigurationFiles(fabricModJson); - if (singleRemap) { - jarRemapper.remap(); + for (SourceSet sourceSet : mixinExtension.getMixinSourceSets()) { + MixinExtension.MixinInformationContainer container = Objects.requireNonNull( + MixinExtension.getMixinInformationContainer(sourceSet) + ); + + final String refmapName = container.refmapNameProvider().get(); + final List mixinConfigs = container.sourceSet().getResources() + .matching(container.mixinConfigPattern()) + .getFiles() + .stream() + .map(File::getName) + .filter(allMixinConfigs::contains) + .toList(); + + params.getMixinData().add(new RemapParams.RefmapData(mixinConfigs, refmapName)); } } - public void scheduleRemap(boolean isMainRemapTask) throws Throwable { - Project project = getProject(); - LoomGradleExtension extension = LoomGradleExtension.get(getProject()); - Path input = this.getInput().getAsFile().get().toPath(); - Path output = this.getArchiveFile().get().getAsFile().toPath(); + public interface RemapParams extends AbstractRemapParams { + ConfigurableFileCollection getNestedJars(); + ConfigurableFileCollection getRemapClasspath(); + ConfigurableFileCollection getMixinMappings(); + ListProperty> getMappings(); - if (!Files.exists(input)) { - throw new FileNotFoundException(input.toString()); - } + Property getUseMixinExtension(); - MappingsProviderImpl mappingsProvider = extension.getMappingsProvider(); + record RefmapData(List mixinConfigs, String refmapName) implements Serializable { } + ListProperty getMixinData(); - String fromM = MappingsNamespace.NAMED.toString(); - String toM = MappingsNamespace.INTERMEDIARY.toString(); + Property getJarManifestService(); + } - if (isMainRemapTask) { - jarRemapper.addToClasspath(getRemapClasspath()); + public abstract static class RemapAction extends AbstractRemapAction { + private static final Logger LOGGER = LoggerFactory.getLogger(RemapAction.class); - jarRemapper.addMappings(TinyRemapperHelper.create(mappingsProvider.getMappings(), fromM, toM, false)); - } + private TinyRemapper tinyRemapper; - for (File mixinMapFile : extension.getAllMixinMappings()) { - if (mixinMapFile.exists()) { - jarRemapper.addMappings(TinyUtils.createTinyMappingProvider(mixinMapFile.toPath(), fromM, toM)); + @Override + public void execute() { + try { + LOGGER.info("Remapping {} to {}", inputFile, outputFile); + + tinyRemapper = createTinyRemapper(); + + remap(); + remapAccessWidener(); + addRefmaps(); + addNestedJars(); + modifyJarManifest(); + rewriteJar(); + + tinyRemapper.finish(); + tinyRemapper = null; + + LOGGER.debug("Finished remapping {}", inputFile); + } catch (Exception e) { + try { + Files.deleteIfExists(outputFile); + } catch (IOException ex) { + LOGGER.error("Failed to delete output file", ex); + } + + throw new RuntimeException("Failed to remap", e); } } - // Add remap options to the jar remapper - jarRemapper.addOptions(this.remapOptions); + private void remap() throws IOException { + final InputTag inputTag = tinyRemapper.createInputTag(); - NestedJarProvider nestedJarProvider = getNestedJarProvider(); - nestedJarProvider.prepare(getProject()); + tinyRemapper.readInputsAsync(inputTag, inputFile); - jarRemapper.scheduleRemap(input, output) - .supplyAccessWidener((remapData, remapper) -> { - if (getRemapAccessWidener().getOrElse(false) && extension.getAccessWidenerPath().isPresent()) { - AccessWidenerJarProcessor accessWidenerJarProcessor = extension.getJarProcessorManager().getByType(AccessWidenerJarProcessor.class); - byte[] data; - - try { - data = accessWidenerJarProcessor.getRemappedAccessWidener(remapper, toM); - } catch (IOException e) { - throw new RuntimeException("Failed to remap access widener", e); - } - - AccessWidenerFile awFile = AccessWidenerFile.fromModJar(remapData.input); - Preconditions.checkNotNull(awFile, "Failed to find accessWidener in fabric.mod.json: " + remapData.input); - - return Pair.of(awFile.name(), data); - } - - return null; - }) - .complete((data, accessWidener) -> { - if (!Files.exists(output)) { - throw new RuntimeException("Failed to remap " + input + " to " + output + " - file missing!"); - } - - if (extension.getMixin().getUseLegacyMixinAp().get()) { - if (MixinRefmapHelper.addRefmapName(project, output)) { - project.getLogger().debug("Transformed mixin reference maps in output JAR!"); - } - } - - if (getAddNestedDependencies().getOrElse(false)) { - JarNester.nestJars(nestedJarProvider.provide(), output.toFile(), project.getLogger()); - } - - if (accessWidener != null) { - try { - ZipUtils.replace(data.output, accessWidener.getLeft(), accessWidener.getRight()); - } catch (IOException e) { - throw new UncheckedIOException("Failed to replace access widener in output jar", e); - } - } - - // Add data to the manifest - try { - int count = ZipUtils.transform(data.output, Map.of(MANIFEST_PATH, bytes -> { - var manifest = new Manifest(new ByteArrayInputStream(bytes)); - var manifestConfiguration = new JarManifestConfiguration(project); - - manifestConfiguration.configure(manifest); - manifest.getMainAttributes().putValue("Fabric-Mapping-Namespace", toM); - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - manifest.write(out); - return out.toByteArray(); - })); - - Preconditions.checkState(count > 0, "Did not transform any jar manifest"); - } catch (IOException e) { - throw new UncheckedIOException("Failed to transform jar manifest", e); - } - - if (isReproducibleFileOrder() || !isPreserveFileTimestamps()) { - try { - ZipReprocessorUtil.reprocessZip(output.toFile(), isReproducibleFileOrder(), isPreserveFileTimestamps()); - } catch (IOException e) { - throw new RuntimeException("Failed to re-process jar", e); - } - } - }); - } - - private NestedJarProvider getNestedJarProvider() { - Configuration includeConfiguration = getProject().getConfigurations().getByName(Constants.Configurations.INCLUDE); - - if (!addDefaultNestedDependencies.getOrElse(true)) { - return new NestedJarPathProvider(nestedPaths); + try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(outputFile).build()) { + outputConsumer.addNonClassFiles(inputFile); + tinyRemapper.apply(outputConsumer, inputTag); + } } - NestedJarProvider baseProvider = NestedDependencyProvider.createNestedDependencyProviderFromConfiguration(getProject(), includeConfiguration); + private void remapAccessWidener() throws IOException { + final AccessWidenerFile accessWidenerFile = AccessWidenerFile.fromModJar(inputFile); - if (nestedPaths.isEmpty()) { - return baseProvider; + if (accessWidenerFile == null) { + return; + } + + byte[] remapped = remapAccessWidener(accessWidenerFile.content(), tinyRemapper.getEnvironment().getRemapper(), MappingsNamespace.INTERMEDIARY.toString()); + + // Finally, replace the output with the remaped aw + ZipUtils.replace(outputFile, accessWidenerFile.path(), remapped); } - return new MergedNestedJarProvider( - baseProvider, - new NestedJarPathProvider(nestedPaths) - ); - } + private static byte[] remapAccessWidener(byte[] input, Remapper asmRemapper, String targetNamespace) { + int version = AccessWidenerReader.readVersion(input); - private Path[] getRemapClasspath() { - FileCollection files = this.classpath; + AccessWidenerWriter writer = new AccessWidenerWriter(version); + AccessWidenerRemapper remapper = new AccessWidenerRemapper( + writer, + asmRemapper, + MappingsNamespace.NAMED.toString(), + targetNamespace + ); + AccessWidenerReader reader = new AccessWidenerReader(remapper); + reader.read(input); - if (files == null) { - files = getProject().getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME); + return writer.write(); } - return files.getFiles().stream() - .map(File::toPath) - .filter(Files::exists) - .toArray(Path[]::new); - } + private void addNestedJars() { + FileCollection nestedJars = getParameters().getNestedJars(); - @InputFile - public RegularFileProperty getInput() { - return input; - } + if (nestedJars.isEmpty()) { + LOGGER.info("No jars to nest"); + return; + } - @Input - public Property getAddNestedDependencies() { - return addNestedDependencies; - } - - @Input - public Property getAddDefaultNestedDependencies() { - return addDefaultNestedDependencies; - } - - @Input - public Property getRemapAccessWidener() { - return remapAccessWidener; - } - - public void remapOptions(Action action) { - this.remapOptions.add(action); - } - - public RemapJarTask classpath(FileCollection collection) { - if (this.classpath == null) { - this.classpath = collection; - } else { - this.classpath = this.classpath.plus(collection); + JarNester.nestJars(nestedJars.getFiles(), outputFile.toFile(), LOGGER); } - return this; - } + private void modifyJarManifest() throws IOException { + int count = ZipUtils.transform(outputFile, Map.of(MANIFEST_PATH, bytes -> { + var manifest = new Manifest(new ByteArrayInputStream(bytes)); - @ApiStatus.Experimental - // This only allows mod jars, proceed with care when trying to pass in configurations with projects, or something that depends on a task. - public RemapJarTask include(Object... paths) { - Collections.addAll(nestedPaths, paths); - this.addNestedDependencies.set(true); + getParameters().getJarManifestService().get().apply(manifest); + manifest.getMainAttributes().putValue("Fabric-Mapping-Namespace", getParameters().getTargetNamespace().get()); - return this; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + manifest.write(out); + return out.toByteArray(); + })); + + Preconditions.checkState(count > 0, "Did not transform any jar manifest"); + } + + private void addRefmaps() throws IOException { + if (getParameters().getUseMixinExtension().get()) { + return; + } + + for (RemapParams.RefmapData refmapData : getParameters().getMixinData().get()) { + int transformed = ZipUtils.transformJson(JsonObject.class, outputFile, refmapData.mixinConfigs().stream().collect(Collectors.toMap(s -> s, s -> json -> { + if (!json.has("refmap")) { + json.addProperty("refmap", refmapData.refmapName()); + } + + return json; + }))); + } + } + + private TinyRemapper createTinyRemapper() { + TinyRemapper.Builder builder = TinyRemapper.newRemapper(); + + for (Provider provider : getParameters().getMappings().get()) { + builder.withMappings(provider.get().getMappingsProvider()); + } + + for (File mixinMapping : getParameters().getMixinMappings()) { + builder.withMappings(TinyUtils.createTinyMappingProvider(mixinMapping.toPath(), getParameters().getSourceNamespace().get(), getParameters().getTargetNamespace().get())); + } + + if (getParameters().getUseMixinExtension().get()) { + builder.extension(new net.fabricmc.tinyremapper.extension.mixin.MixinExtension()); + } + + TinyRemapper remapper = builder.build(); + + // Apply classpath + for (File file : getParameters().getRemapClasspath()) { + remapper.readClassPathAsync(file.toPath()); + } + + return remapper; + } } } diff --git a/src/main/java/net/fabricmc/loom/task/RemapSourcesJarTask.java b/src/main/java/net/fabricmc/loom/task/RemapSourcesJarTask.java index 26fd6a3..824a678 100644 --- a/src/main/java/net/fabricmc/loom/task/RemapSourcesJarTask.java +++ b/src/main/java/net/fabricmc/loom/task/RemapSourcesJarTask.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2016-2021 FabricMC + * Copyright (c) 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 @@ -24,70 +24,65 @@ package net.fabricmc.loom.task; -import org.gradle.api.file.RegularFileProperty; +import java.io.IOException; +import java.nio.file.Files; + +import javax.inject.Inject; + +import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.provider.Property; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.InputFile; -import org.gradle.api.tasks.Internal; -import org.gradle.api.tasks.OutputFile; import org.gradle.api.tasks.TaskAction; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; -import net.fabricmc.loom.util.SourceRemapper; - -public class RemapSourcesJarTask extends AbstractLoomTask { - private final RegularFileProperty input = getProject().getObjects().fileProperty(); - private final RegularFileProperty output = getProject().getObjects().fileProperty().convention(input); - private final Property targetNamespace = getProject().getObjects().property(String.class).convention(MappingsNamespace.INTERMEDIARY.toString()); - private SourceRemapper sourceRemapper = null; - private final Property preserveFileTimestamps = getProject().getObjects().property(Boolean.class).convention(true); - private final Property reproducibleFileOrder = getProject().getObjects().property(Boolean.class).convention(false); +import net.fabricmc.loom.task.service.MappingsService; +import net.fabricmc.loom.task.service.SourceRemapperService; +public abstract class RemapSourcesJarTask extends AbstractRemapJarTask { + @Inject public RemapSourcesJarTask() { + super(); + + getClasspath().from(getProject().getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME)); } @TaskAction - public void remap() throws Exception { - if (sourceRemapper == null) { - String direction = targetNamespace.get(); - SourceRemapper.remapSources(getProject(), input.get().getAsFile(), output.get().getAsFile(), direction.equals(MappingsNamespace.NAMED.toString()), reproducibleFileOrder.get(), preserveFileTimestamps.get()); - } else { - sourceRemapper.scheduleRemapSources(input.get().getAsFile(), output.get().getAsFile(), reproducibleFileOrder.get(), preserveFileTimestamps.get()); + public void run() { + submitWork(RemapSourcesAction.class, params -> { + params.getSourcesRemapperService().set(SourceRemapperService.create(getProject(), MappingsService.createDefault(getProject(), getSourceNamespace().get(), getTargetNamespace().get()), getClasspath())); + }); + } + + public interface RemapSourcesParams extends AbstractRemapParams { + Property getSourcesRemapperService(); + } + + public abstract static class RemapSourcesAction extends AbstractRemapAction { + private static final Logger LOGGER = LoggerFactory.getLogger(RemapSourcesAction.class); + + private final SourceRemapperService sourceRemapperService; + + public RemapSourcesAction() { + super(); + + sourceRemapperService = getParameters().getSourcesRemapperService().get(); + } + + @Override + public void execute() { + try { + sourceRemapperService.remapSourcesJar(inputFile, outputFile); + + rewriteJar(); + } catch (Exception e) { + try { + Files.deleteIfExists(outputFile); + } catch (IOException ex) { + LOGGER.error("Failed to delete output file", ex); + } + + throw new RuntimeException("Failed to remap sources", e); + } } } - - @Internal - public SourceRemapper getSourceRemapper() { - return sourceRemapper; - } - - public RemapSourcesJarTask setSourceRemapper(SourceRemapper sourceRemapper) { - this.sourceRemapper = sourceRemapper; - return this; - } - - @InputFile - public RegularFileProperty getInput() { - return input; - } - - @OutputFile - public RegularFileProperty getOutput() { - return output; - } - - @Input - public Property getTargetNamespace() { - return targetNamespace; - } - - @Input - public Property getPreserveFileTimestamps() { - return preserveFileTimestamps; - } - - @Input - public Property getReproducibleFileOrder() { - return reproducibleFileOrder; - } } diff --git a/src/main/java/net/fabricmc/loom/task/RemapTaskConfiguration.java b/src/main/java/net/fabricmc/loom/task/RemapTaskConfiguration.java new file mode 100644 index 0000000..35fa28d --- /dev/null +++ b/src/main/java/net/fabricmc/loom/task/RemapTaskConfiguration.java @@ -0,0 +1,138 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2016-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.task; + +import java.io.File; + +import org.gradle.api.Project; +import org.gradle.api.Task; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.plugins.BasePlugin; +import org.gradle.api.plugins.JavaPlugin; +import org.gradle.api.plugins.JavaPluginExtension; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.TaskContainer; +import org.gradle.api.tasks.TaskProvider; +import org.gradle.api.tasks.bundling.AbstractArchiveTask; +import org.gradle.api.tasks.bundling.Jar; + +import net.fabricmc.loom.LoomGradleExtension; +import net.fabricmc.loom.util.Constants; + +public class RemapTaskConfiguration { + public static final String REMAP_JAR_TASK_NAME = "remapJar"; + public static final String REMAP_SOURCES_JAR_TASK_NAME = "remapSourcesJar"; + + public static void setupRemap(Project project) { + final TaskContainer tasks = project.getTasks(); + final LoomGradleExtension extension = LoomGradleExtension.get(project); + + if (!extension.getRemapArchives().get()) { + extension.getUnmappedModCollection().from(project.getTasks().getByName(JavaPlugin.JAR_TASK_NAME)); + return; + } + + // Register the default remap jar task + TaskProvider remapJarTaskProvider = tasks.register(REMAP_JAR_TASK_NAME, RemapJarTask.class, task -> { + final AbstractArchiveTask jarTask = tasks.named(JavaPlugin.JAR_TASK_NAME, AbstractArchiveTask.class).get(); + + // Basic task setup + task.dependsOn(jarTask); + task.setDescription("Remaps the built project jar to intermediary mappings."); + task.setGroup(Constants.TaskGroup.FABRIC); + project.getArtifacts().add(JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME, task); + project.getArtifacts().add(JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME, task); + + // Setup the input file and the nested deps + task.getInputFile().convention(jarTask.getArchiveFile()); + task.dependsOn(tasks.named(JavaPlugin.JAR_TASK_NAME)); + }); + + // Configure the default jar task + tasks.named(JavaPlugin.JAR_TASK_NAME, AbstractArchiveTask.class).configure(task -> { + task.getArchiveClassifier().convention("dev"); + task.getDestinationDirectory().set(new File(project.getBuildDir(), "devlibs")); + }); + + tasks.named(BasePlugin.ASSEMBLE_TASK_NAME).configure(task -> task.dependsOn(remapJarTaskProvider)); + + trySetupSourceRemapping(project); + + if (extension.getSetupRemappedVariants().get()) { + // Remove -dev jars from the default jar task + for (String configurationName : new String[] { JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME, JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME }) { + Configuration configuration = project.getConfigurations().getByName(configurationName); + configuration.getArtifacts().removeIf(artifact -> { + Task jarTask = project.getTasks().getByName(JavaPlugin.JAR_TASK_NAME); + // if the artifact is a -dev jar and "builtBy jar" + return "dev".equals(artifact.getClassifier()) && artifact.getBuildDependencies().getDependencies(null).contains(jarTask); + }); + } + } + } + + private static void trySetupSourceRemapping(Project project) { + final TaskContainer tasks = project.getTasks(); + final LoomGradleExtension extension = LoomGradleExtension.get(project); + + TaskProvider remapSourcesTask = tasks.register(REMAP_SOURCES_JAR_TASK_NAME, RemapSourcesJarTask.class, task -> { + task.setDescription("Remaps the default sources jar to intermediary mappings."); + task.setGroup(Constants.TaskGroup.FABRIC); + + final JavaPluginExtension javaExtension = project.getExtensions().getByType(JavaPluginExtension.class); + final String sourcesJarTaskName = javaExtension.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME).getSourcesJarTaskName(); + final Task sourcesTask = project.getTasks().findByName(sourcesJarTaskName); + + if (sourcesTask == null) { + project.getLogger().info("{} task was not found, not remapping sources", sourcesJarTaskName); + task.setEnabled(false); + return; + } + + if (!(sourcesTask instanceof Jar sourcesJarTask)) { + project.getLogger().info("{} task is not a Jar task, not remapping sources", sourcesJarTaskName); + task.setEnabled(false); + return; + } + + sourcesJarTask.getArchiveClassifier().convention("dev-sources"); + sourcesJarTask.getDestinationDirectory().set(new File(project.getBuildDir(), "devlibs")); + task.getArchiveClassifier().convention("sources"); + + task.dependsOn(sourcesJarTask); + task.getInputFile().convention(sourcesJarTask.getArchiveFile()); + + if (extension.getSetupRemappedVariants().get()) { + project.getArtifacts().add(JavaPlugin.SOURCES_ELEMENTS_CONFIGURATION_NAME, task); + + // Remove the dev sources artifact + Configuration configuration = project.getConfigurations().getByName(JavaPlugin.SOURCES_ELEMENTS_CONFIGURATION_NAME); + configuration.getArtifacts().removeIf(a -> a.getFile().equals(sourcesJarTask.getArchiveFile().get().getAsFile())); + } + }); + + tasks.named(BasePlugin.ASSEMBLE_TASK_NAME).configure(task -> task.dependsOn(remapSourcesTask)); + } +} diff --git a/src/main/java/net/fabricmc/loom/task/service/JarManifestService.java b/src/main/java/net/fabricmc/loom/task/service/JarManifestService.java new file mode 100644 index 0000000..c80852e --- /dev/null +++ b/src/main/java/net/fabricmc/loom/task/service/JarManifestService.java @@ -0,0 +1,123 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 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.task.service; + +import java.io.Serializable; +import java.util.Optional; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +import org.gradle.api.Project; +import org.gradle.api.artifacts.Dependency; +import org.gradle.api.provider.Property; +import org.gradle.api.provider.Provider; +import org.gradle.api.services.BuildService; +import org.gradle.api.services.BuildServiceParameters; +import org.gradle.util.GradleVersion; + +import net.fabricmc.loom.LoomGradleExtension; +import net.fabricmc.loom.LoomGradlePlugin; +import net.fabricmc.loom.util.Constants; +import net.fabricmc.tinyremapper.TinyRemapper; + +public abstract class JarManifestService implements BuildService { + interface Params extends BuildServiceParameters { + Property getGradleVersion(); + Property getLoomVersion(); + Property getMCEVersion(); + Property getMinecraftVersion(); + Property getTinyRemapperVersion(); + Property getFabricLoaderVersion(); + Property getMixinVersion(); + } + + public static Provider get(Project project) { + return project.getGradle().getSharedServices().registerIfAbsent("LoomJarManifestService:" + project.getName(), JarManifestService.class, spec -> { + spec.parameters(params -> { + LoomGradleExtension extension = LoomGradleExtension.get(project); + Optional tinyRemapperVersion = Optional.ofNullable(TinyRemapper.class.getPackage().getImplementationVersion()); + + params.getGradleVersion().set(GradleVersion.current().getVersion()); + params.getLoomVersion().set(LoomGradlePlugin.LOOM_VERSION); + params.getMCEVersion().set(Constants.Dependencies.Versions.MIXIN_COMPILE_EXTENSIONS); + params.getMinecraftVersion().set(extension.getMinecraftProvider().minecraftVersion()); + params.getTinyRemapperVersion().set(tinyRemapperVersion.orElse("unknown")); + params.getFabricLoaderVersion().set(getLoaderVersion(project).orElse("unknown")); + params.getMixinVersion().set(getMixinVersion(project).orElse(new MixinVersion("unknown", "unknown"))); + }); + }); + } + + public void apply(Manifest manifest) { + // Don't set when running the reproducible build tests as it will break them when anything updates + if (Boolean.getBoolean("loom.test.reproducible")) { + return; + } + + Attributes attributes = manifest.getMainAttributes(); + Params p = getParameters(); + + attributes.putValue("Fabric-Gradle-Version", p.getGradleVersion().get()); + attributes.putValue("Fabric-Loom-Version", p.getLoomVersion().get()); + attributes.putValue("Fabric-Mixin-Compile-Extensions-Version", p.getMCEVersion().get()); + attributes.putValue("Fabric-Minecraft-Version", p.getMinecraftVersion().get()); + attributes.putValue("Fabric-Tiny-Remapper-Version", p.getTinyRemapperVersion().get()); + attributes.putValue("Fabric-Loader-Version", p.getFabricLoaderVersion().get()); + + // This can be overridden by mods if required + if (!attributes.containsKey("Fabric-Mixin-Version")) { + attributes.putValue("Fabric-Mixin-Version", p.getMixinVersion().get().version()); + attributes.putValue("Fabric-Mixin-Group", p.getMixinVersion().get().group()); + } + } + + private static Optional getLoaderVersion(Project project) { + LoomGradleExtension extension = LoomGradleExtension.get(project); + + if (extension.getInstallerData() == null) { + project.getLogger().warn("Could not determine fabric loader version for jar manifest"); + return Optional.empty(); + } + + return Optional.of(extension.getInstallerData().version()); + } + + private record MixinVersion(String group, String version) implements Serializable { } + + private static Optional getMixinVersion(Project project) { + // Not super ideal that this uses the mod compile classpath, should prob look into making this not a thing at somepoint + Optional dependency = project.getConfigurations().getByName(Constants.Configurations.LOADER_DEPENDENCIES) + .getDependencies() + .stream() + .filter(dep -> "sponge-mixin".equals(dep.getName())) + .findFirst(); + + if (dependency.isEmpty()) { + project.getLogger().warn("Could not determine Mixin version for jar manifest"); + } + + return dependency.map(d -> new MixinVersion(d.getGroup(), d.getVersion())); + } +} diff --git a/src/main/java/net/fabricmc/loom/task/service/MappingsService.java b/src/main/java/net/fabricmc/loom/task/service/MappingsService.java new file mode 100644 index 0000000..99cebcb --- /dev/null +++ b/src/main/java/net/fabricmc/loom/task/service/MappingsService.java @@ -0,0 +1,118 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 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.task.service; + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; + +import org.gradle.api.Project; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.provider.Provider; +import org.gradle.api.services.BuildService; +import org.gradle.api.services.BuildServiceParameters; + +import net.fabricmc.loom.LoomGradleExtension; +import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; +import net.fabricmc.loom.util.TinyRemapperHelper; +import net.fabricmc.mappingio.MappingReader; +import net.fabricmc.mappingio.tree.MemoryMappingTree; +import net.fabricmc.tinyremapper.IMappingProvider; + +public abstract class MappingsService implements BuildService, AutoCloseable { + interface Params extends BuildServiceParameters { + RegularFileProperty getMappingsFile(); + + Property getFromNamespace(); + Property getToNamespace(); + + Property getRemapLocals(); + } + + public static synchronized Provider create(Project project, String name, File mappingsFile, String from, String to, boolean remapLocals) { + return project.getGradle().getSharedServices().registerIfAbsent(name, MappingsService.class, spec -> { + spec.parameters(params -> { + params.getMappingsFile().set(mappingsFile); + params.getFromNamespace().set(from); + params.getToNamespace().set(to); + params.getRemapLocals().set(remapLocals); + }); + }); + } + + public static Provider createDefault(Project project, String from, String to) { + final MappingsProviderImpl mappingsProvider = LoomGradleExtension.get(project).getMappingsProvider(); + final String name = mappingsProvider.getBuildServiceName("mappingsProvider", from, to); + return MappingsService.create(project, name, mappingsProvider.tinyMappings.toFile(), from, to, false); + } + + private IMappingProvider mappingProvider = null; + private MemoryMappingTree memoryMappingTree = null; + + public synchronized IMappingProvider getMappingsProvider() { + if (mappingProvider == null) { + try { + mappingProvider = TinyRemapperHelper.create( + getParameters().getMappingsFile().get().getAsFile().toPath(), + getParameters().getFromNamespace().get(), + getParameters().getToNamespace().get(), + getParameters().getRemapLocals().get() + ); + } catch (IOException e) { + throw new UncheckedIOException("Failed to read mappings from: " + getParameters().getMappingsFile().get().getAsFile().getAbsolutePath(), e); + } + } + + return mappingProvider; + } + + public synchronized MemoryMappingTree getMemoryMappingTree() { + if (memoryMappingTree == null) { + memoryMappingTree = new MemoryMappingTree(); + + try { + MappingReader.read(getParameters().getMappingsFile().get().getAsFile().toPath(), memoryMappingTree); + } catch (IOException e) { + throw new UncheckedIOException("Failed to read mappings from: " + getParameters().getMappingsFile().get().getAsFile().getAbsolutePath(), e); + } + } + + return memoryMappingTree; + } + + public String getFromNamespace() { + return getParameters().getFromNamespace().get(); + } + + public String getToNamespace() { + return getParameters().getToNamespace().get(); + } + + @Override + public void close() { + mappingProvider = null; + } +} diff --git a/src/main/java/net/fabricmc/loom/task/service/SourceRemapperService.java b/src/main/java/net/fabricmc/loom/task/service/SourceRemapperService.java new file mode 100644 index 0000000..891a909 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/task/service/SourceRemapperService.java @@ -0,0 +1,133 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 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.task.service; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.cadixdev.lorenz.MappingSet; +import org.cadixdev.mercury.Mercury; +import org.cadixdev.mercury.remapper.MercuryRemapper; +import org.gradle.api.Project; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.file.FileCollection; +import org.gradle.api.provider.Property; +import org.gradle.api.provider.Provider; +import org.gradle.api.services.BuildService; +import org.gradle.api.services.BuildServiceParameters; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import net.fabricmc.loom.util.DeletingFileVisitor; +import net.fabricmc.loom.util.FileSystemUtil; +import net.fabricmc.loom.util.SourceRemapper; +import net.fabricmc.loom.util.ZipUtils; +import net.fabricmc.lorenztiny.TinyMappingsReader; + +public abstract class SourceRemapperService implements BuildService, AutoCloseable { + public interface Params extends BuildServiceParameters { + Property> getMappings(); + + ConfigurableFileCollection getClasspath(); + } + + public static synchronized Provider create(Project project, Provider mappings, FileCollection classpath) { + // TODO may need a better name, im not too sure + return project.getGradle().getSharedServices().registerIfAbsent("sourceremapper", SourceRemapperService.class, spec -> + spec.parameters(params -> { + params.getMappings().set(mappings); + params.getClasspath().from(classpath); + } + )); + } + + private static final Logger LOGGER = LoggerFactory.getLogger(SourceRemapperService.class); + + private Mercury mercury; + + public void remapSourcesJar(Path source, Path destination) throws IOException { + if (source.equals(destination)) { + throw new UnsupportedOperationException("Cannot remap in place"); + } + + Path srcPath = source; + boolean isSrcTmp = false; + + // Create a temp directory with all of the sources + if (!Files.isDirectory(source)) { + isSrcTmp = true; + srcPath = Files.createTempDirectory("fabric-loom-src"); + ZipUtils.unpackAll(source, srcPath); + } + + if (!Files.isDirectory(destination) && Files.exists(destination)) { + Files.delete(destination); + } + + try (FileSystemUtil.Delegate dstFs = Files.isDirectory(destination) ? null : FileSystemUtil.getJarFileSystem(destination, true)) { + Path dstPath = dstFs != null ? dstFs.get().getPath("/") : destination; + + doRemap(srcPath, dstPath, source); + SourceRemapper.copyNonJavaFiles(srcPath, dstPath, LOGGER, source); + } finally { + if (isSrcTmp) { + Files.walkFileTree(srcPath, new DeletingFileVisitor()); + } + } + } + + private synchronized void doRemap(Path srcPath, Path dstPath, Path source) throws IOException { + if (mercury == null) { + mercury = new Mercury(); + mercury.setGracefulClasspathChecks(true); + mercury.getProcessors().add(MercuryRemapper.create(getMappings())); + + getParameters().getClasspath().forEach(file -> mercury.getClassPath().add(file.toPath())); + } + + try { + // Not thread safe!! + mercury.rewrite(srcPath, dstPath); + } catch (Exception e) { + LOGGER.warn("Could not remap " + source + " fully!", e); + } + } + + private MappingSet getMappings() throws IOException { + return new TinyMappingsReader(mappingsService().getMemoryMappingTree(), mappingsService().getFromNamespace(), mappingsService().getToNamespace()).read(); + } + + private MappingsService mappingsService() { + return getParameters().getMappings().get().get(); + } + + @Override + public void close() throws Exception { + mercury = null; + // This is required (: + System.gc(); + } +} diff --git a/src/main/java/net/fabricmc/loom/util/SourceRemapper.java b/src/main/java/net/fabricmc/loom/util/SourceRemapper.java index f37211b..08b241d 100644 --- a/src/main/java/net/fabricmc/loom/util/SourceRemapper.java +++ b/src/main/java/net/fabricmc/loom/util/SourceRemapper.java @@ -37,6 +37,7 @@ import org.cadixdev.lorenz.MappingSet; import org.cadixdev.mercury.Mercury; import org.cadixdev.mercury.remapper.MercuryRemapper; import org.gradle.api.Project; +import org.slf4j.Logger; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; @@ -142,7 +143,7 @@ public class SourceRemapper { project.getLogger().warn("Could not remap " + source.getName() + " fully!", e); } - copyNonJavaFiles(srcPath, dstPath, project, source); + copyNonJavaFiles(srcPath, dstPath, project.getLogger(), source.toPath()); if (dstFs != null) { dstFs.close(); @@ -202,7 +203,7 @@ public class SourceRemapper { return mercury; } - private static void copyNonJavaFiles(Path from, Path to, Project project, File source) throws IOException { + public static void copyNonJavaFiles(Path from, Path to, Logger logger, Path source) throws IOException { Files.walk(from).forEach(path -> { Path targetPath = to.resolve(from.relativize(path).toString()); @@ -210,7 +211,7 @@ public class SourceRemapper { try { Files.copy(path, targetPath); } catch (IOException e) { - project.getLogger().warn("Could not copy non-java sources '" + source.getName() + "' fully!", e); + logger.warn("Could not copy non-java sources '" + source + "' fully!", e); } } }); diff --git a/src/main/java/net/fabricmc/loom/util/TinyRemapperHelper.java b/src/main/java/net/fabricmc/loom/util/TinyRemapperHelper.java index d534f97..e0e6b18 100644 --- a/src/main/java/net/fabricmc/loom/util/TinyRemapperHelper.java +++ b/src/main/java/net/fabricmc/loom/util/TinyRemapperHelper.java @@ -36,6 +36,7 @@ import org.gradle.api.Project; import net.fabricmc.loom.LoomGradleExtension; import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; +import net.fabricmc.mappingio.MappingReader; import net.fabricmc.mappingio.tree.MappingTree; import net.fabricmc.mappingio.tree.MemoryMappingTree; import net.fabricmc.tinyremapper.IMappingProvider; @@ -101,6 +102,12 @@ public final class TinyRemapperHelper { return new IMappingProvider.Member(className, memberName, descriptor); } + public static IMappingProvider create(Path mappings, String from, String to, boolean remapLocalVariables) throws IOException { + MemoryMappingTree mappingTree = new MemoryMappingTree(); + MappingReader.read(mappings, mappingTree); + return create(mappingTree, from, to, remapLocalVariables); + } + public static IMappingProvider create(MappingTree mappings, String from, String to, boolean remapLocalVariables) { return (acceptor) -> { for (MappingTree.ClassMapping classDef : mappings.getClasses()) { diff --git a/src/test/groovy/net/fabricmc/loom/test/LoomTestConstants.groovy b/src/test/groovy/net/fabricmc/loom/test/LoomTestConstants.groovy index ef596a7..74814eb 100644 --- a/src/test/groovy/net/fabricmc/loom/test/LoomTestConstants.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/LoomTestConstants.groovy @@ -28,7 +28,7 @@ import org.gradle.util.GradleVersion class LoomTestConstants { public final static String DEFAULT_GRADLE = GradleVersion.current().getVersion() - public final static String PRE_RELEASE_GRADLE = "7.4-20211216231505+0000" + public final static String PRE_RELEASE_GRADLE = "7.4-20211219231013+0000" public final static String[] STANDARD_TEST_VERSIONS = [DEFAULT_GRADLE, PRE_RELEASE_GRADLE] } 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 b730024..0bfbf17 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: "ce6198f63bbe0e17ba631420e9186fb72cc8b2af", + commit: "71b634e5b7845296b11be3fa6545f4fbfacc017f", version: version, patch: "fabric_api" ) diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/MixinApSimpleTest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/MixinApSimpleTest.groovy index 831e226..123a831 100644 --- a/src/test/groovy/net/fabricmc/loom/test/integration/MixinApSimpleTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/integration/MixinApSimpleTest.groovy @@ -47,7 +47,7 @@ class MixinApSimpleTest extends Specification implements GradleProjectTestTrait result.task(":build").outcome == SUCCESS // verify the ref-map name is correctly generated - def main = new JarFile(gradle.getOutputFile("fabric-example-mod-1.0.0-dev.jar").absoluteFile) + def main = new JarFile(new File(gradle.projectDir, "build/devlibs/fabric-example-mod-1.0.0-dev.jar").absoluteFile) main.getEntry("main-refmap0000.json") != null def mixin = new JarFile(gradle.getOutputFile("fabric-example-mod-1.0.0-mixin.jar").absoluteFile) mixin.getEntry("default-refmap0000.json") != null diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/MultiProjectTest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/MultiProjectTest.groovy index 5aa5b70..3984e00 100644 --- a/src/test/groovy/net/fabricmc/loom/test/integration/MultiProjectTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/integration/MultiProjectTest.groovy @@ -45,9 +45,6 @@ class MultiProjectTest extends Specification implements GradleProjectTestTrait { result.task(":core:build").outcome == SUCCESS result.task(":example:build").outcome == SUCCESS - result.task(":remapAllJars").outcome == SUCCESS - result.task(":remapAllSources").outcome == SUCCESS - gradle.hasOutputZipEntry("multiproject-1.0.0.jar", "META-INF/jars/example-1.0.0.jar") gradle.hasOutputZipEntry("multiproject-1.0.0.jar", "META-INF/jars/core-1.0.0.jar") gradle.hasOutputZipEntry("multiproject-1.0.0.jar", "META-INF/jars/fabric-api-base-0.2.1+9354966b7d.jar") diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/SimpleProjectTest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/SimpleProjectTest.groovy index 5adf4ae..2ceb2a0 100644 --- a/src/test/groovy/net/fabricmc/loom/test/integration/SimpleProjectTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/integration/SimpleProjectTest.groovy @@ -51,6 +51,7 @@ class SimpleProjectTest extends Specification implements GradleProjectTestTrait then: result.task(":build").outcome == SUCCESS gradle.getOutputZipEntry("fabric-example-mod-1.0.0.jar", "META-INF/MANIFEST.MF").contains("Fabric-Loom-Version: 0.0.0+unknown") + gradle.getOutputZipEntry("fabric-example-mod-1.0.0-sources.jar", "net/fabricmc/example/mixin/ExampleMixin.java").contains("class_442") // Very basic test to ensure sources got remapped serverResult.successful() serverResult.output.contains("Hello simple Fabric mod") // A check to ensure our mod init was actually called diff --git a/src/test/groovy/net/fabricmc/loom/test/unit/MergedNestedJarProviderTest.groovy b/src/test/groovy/net/fabricmc/loom/test/unit/MergedNestedJarProviderTest.groovy deleted file mode 100644 index 23b7d93..0000000 --- a/src/test/groovy/net/fabricmc/loom/test/unit/MergedNestedJarProviderTest.groovy +++ /dev/null @@ -1,55 +0,0 @@ -/* - * This file is part of fabric-loom, licensed under the MIT License (MIT). - * - * Copyright (c) 2016-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.test.unit - -import net.fabricmc.loom.build.nesting.MergedNestedJarProvider -import net.fabricmc.loom.build.nesting.NestedJarProvider -import org.gradle.api.Project -import spock.lang.Specification - -class MergedNestedJarProviderTest extends Specification { - def "empty test"() { - given: - def nestedJarProvider = new MergedNestedJarProvider(new TestNestedJarProvider()) - when: - nestedJarProvider.prepare(null) - then: - nestedJarProvider.provide() != null - } - - private class TestNestedJarProvider implements NestedJarProvider { - private Collection files = null - - @Override - Collection provide() { - return files - } - - @Override - void prepare(Project project) { - files = [] - } - } -} diff --git a/src/test/resources/patches/fabric_api.patch b/src/test/resources/patches/fabric_api.patch index b9f578a..c1d922e 100644 --- a/src/test/resources/patches/fabric_api.patch +++ b/src/test/resources/patches/fabric_api.patch @@ -1,6 +1,6 @@ diff --git a/build.gradle b/build.gradle ---- a/build.gradle (revision ce6198f63bbe0e17ba631420e9186fb72cc8b2af) -+++ b/build.gradle (date 1637848132986) +--- a/build.gradle (revision 71b634e5b7845296b11be3fa6545f4fbfacc017f) ++++ b/build.gradle (date 1638654919842) @@ -31,17 +31,7 @@ throw new NullPointerException("Could not find version for " + project.name) } @@ -20,43 +20,3 @@ diff --git a/build.gradle b/build.gradle } def getBranch() { -@@ -132,9 +122,8 @@ - include "**/*.java" - } - -- task sourcesJar(type: Jar, dependsOn: classes) { -- archiveClassifier = "sources" -- from sourceSets.main.allSource -+ java { -+ withSourcesJar() - } - - checkstyle { -@@ -229,12 +218,16 @@ - publications { - mavenJava(MavenPublication) { - from components.java -+ -+ artifact javadocJar - } - } - - setupRepositories(repositories) - } - -+ loom.disableDeprecatedPomGeneration(publishing.publications.mavenJava) -+ - javadoc.enabled = false - - afterEvaluate { -@@ -242,10 +235,6 @@ - genSourcesWithFernFlower.enabled = false - genSourcesWithCfr.enabled = false - unpickJar.enabled = false -- -- // Work around a loom bug causing empty jars to be pushed to maven local. -- publishMavenJavaPublicationToMavenLocal.dependsOn rootProject.tasks.getByName("remapAllJars") -- publishMavenJavaPublicationToMavenLocal.dependsOn rootProject.tasks.getByName("remapAllSources") - } - } - diff --git a/src/test/resources/projects/simple/build.gradle b/src/test/resources/projects/simple/build.gradle index 46b957c..5ce232e 100644 --- a/src/test/resources/projects/simple/build.gradle +++ b/src/test/resources/projects/simple/build.gradle @@ -29,6 +29,9 @@ dependencies { // PSA: Some older mods, compiled on Loom 0.2.1, might have outdated Maven POMs. // You may need to force-disable transitiveness on them. + + // Example include + include "org.xerial:sqlite-jdbc:3.36.0.3" } tasks.withType(JavaCompile).configureEach {