diff --git a/src/main/java/net/fabricmc/loom/task/NestJarsAction.java b/src/main/java/net/fabricmc/loom/task/NestJarsAction.java new file mode 100644 index 00000000..200ef520 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/task/NestJarsAction.java @@ -0,0 +1,76 @@ +/* + * 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 java.io.Serializable; +import java.util.Arrays; + +import org.gradle.api.Action; +import org.gradle.api.Task; +import org.gradle.api.file.Directory; +import org.gradle.api.provider.Provider; +import org.gradle.jvm.tasks.Jar; +import org.jetbrains.annotations.NotNull; + +import net.fabricmc.loom.build.nesting.JarNester; + +/** + * Configuration-cache-compatible action for nesting jars. + * Uses a provider to avoid capturing task references at configuration time. + * Do NOT turn me into a record! + */ +class NestJarsAction implements Action, Serializable { + private final Provider nestedJarsDir; + + NestJarsAction(Provider nestedJarsDir) { + this.nestedJarsDir = nestedJarsDir; + } + + @Override + public void execute(@NotNull Task t) { + final Jar jarTask = (Jar) t; + final File jarFile = jarTask.getArchiveFile().get().getAsFile(); + + if (!nestedJarsDir.isPresent()) { + return; + } + + final File outputDir = nestedJarsDir.get().getAsFile(); + + if (outputDir.exists() && outputDir.isDirectory()) { + final File[] jars = outputDir.listFiles((dir, name) -> name.endsWith(".jar")); + + if (jars != null && jars.length > 0) { + JarNester.nestJars( + Arrays.asList(jars), + jarFile, + jarTask.getLogger() + ); + jarTask.getLogger().lifecycle("Nested {} jar(s) into {}", jars.length, jarFile.getName()); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/net/fabricmc/loom/task/NonRemappedJarTaskConfiguration.java b/src/main/java/net/fabricmc/loom/task/NonRemappedJarTaskConfiguration.java new file mode 100644 index 00000000..56a9e00e --- /dev/null +++ b/src/main/java/net/fabricmc/loom/task/NonRemappedJarTaskConfiguration.java @@ -0,0 +1,61 @@ +/* + * 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 org.gradle.api.Project; +import org.gradle.api.plugins.JavaPlugin; +import org.gradle.api.tasks.TaskProvider; +import org.gradle.jvm.tasks.Jar; + +import net.fabricmc.loom.LoomGradleExtension; +import net.fabricmc.loom.build.nesting.NestableJarGenerationTask; + +/** + * Configures the jar task for non-remapped (non-obfuscated) output. + * Used when remapping is disabled via dontRemapOutputs(). + */ +public class NonRemappedJarTaskConfiguration { + private final Project project; + private final LoomGradleExtension extension; + private final TaskProvider processIncludeJarsTask; + + public NonRemappedJarTaskConfiguration(Project project, LoomGradleExtension extension, TaskProvider processIncludeJarsTask) { + this.project = project; + this.extension = extension; + this.processIncludeJarsTask = processIncludeJarsTask; + } + + public void configure() { + // No remapping needed - use simplified JIJ approach directly on jar task + project.getTasks().named(JavaPlugin.JAR_TASK_NAME, Jar.class).configure(task -> { + task.dependsOn(processIncludeJarsTask); + // Use JarNester to properly add jars and update fabric.mod.json + task.doLast(new NestJarsAction(processIncludeJarsTask.flatMap(NestableJarGenerationTask::getOutputDirectory))); + }); + + // Add jar task to unmapped collection + extension.getUnmappedModCollection().from(project.getTasks().getByName(JavaPlugin.JAR_TASK_NAME)); + } +} \ No newline at end of file diff --git a/src/main/java/net/fabricmc/loom/task/RemapTaskConfiguration.java b/src/main/java/net/fabricmc/loom/task/RemapTaskConfiguration.java index 8f6f4994..9db78a7a 100644 --- a/src/main/java/net/fabricmc/loom/task/RemapTaskConfiguration.java +++ b/src/main/java/net/fabricmc/loom/task/RemapTaskConfiguration.java @@ -67,17 +67,18 @@ public abstract class RemapTaskConfiguration implements Runnable { SyncTaskBuildService.register(getProject()); - if (extension.dontRemapOutputs()) { - extension.getUnmappedModCollection().from(getTasks().getByName(JavaPlugin.JAR_TASK_NAME)); - return; - } - Configuration includeConfiguration = getProject().getConfigurations().getByName(Constants.Configurations.INCLUDE_INTERNAL); - getTasks().register(Constants.Task.PROCESS_INCLUDE_JARS, NestableJarGenerationTask.class, task -> { + TaskProvider processIncludeJarsTask = getTasks().register(Constants.Task.PROCESS_INCLUDE_JARS, NestableJarGenerationTask.class, task -> { task.from(includeConfiguration); task.getOutputDirectory().set(getProject().getLayout().getBuildDirectory().dir(task.getName())); }); + if (extension.dontRemapOutputs()) { + new NonRemappedJarTaskConfiguration(getProject(), extension, processIncludeJarsTask).configure(); + return; + } + + // Remapping needed - use the traditional remapJar task with JIJ support (original logic) Action remapJarTaskAction = task -> { final TaskProvider jarTask = getTasks().named(JavaPlugin.JAR_TASK_NAME, AbstractArchiveTask.class); diff --git a/src/main/java/net/fabricmc/loom/task/prod/AbstractProductionRunTask.java b/src/main/java/net/fabricmc/loom/task/prod/AbstractProductionRunTask.java index d1b3a546..007c8c35 100644 --- a/src/main/java/net/fabricmc/loom/task/prod/AbstractProductionRunTask.java +++ b/src/main/java/net/fabricmc/loom/task/prod/AbstractProductionRunTask.java @@ -36,6 +36,7 @@ import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.Dependency; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPluginExtension; import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.Property; @@ -128,7 +129,12 @@ public abstract sealed class AbstractProductionRunTask extends AbstractLoomTask getJavaLauncher().convention(getJavaToolchainService().launcherFor(defaultToolchain)); getRunDir().convention(getProject().getLayout().getProjectDirectory().dir("run")); - if (!getExtension().dontRemapOutputs()) { + // Use the appropriate jar based on whether remapping is enabled + if (getExtension().dontRemapOutputs()) { + // No remapping - use the standard jar task + getMods().from(getProject().getTasks().named(JavaPlugin.JAR_TASK_NAME)); + } else { + // Remapping enabled - use the remapJar task getMods().from(getProject().getTasks().named(RemapTaskConfiguration.REMAP_JAR_TASK_NAME)); } diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/IncludedJarsNoRemapTest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/IncludedJarsNoRemapTest.groovy new file mode 100644 index 00000000..3ad38539 --- /dev/null +++ b/src/test/groovy/net/fabricmc/loom/test/integration/IncludedJarsNoRemapTest.groovy @@ -0,0 +1,58 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2023 FabricMC + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package net.fabricmc.loom.test.integration + +import spock.lang.Specification +import spock.lang.Unroll + +import net.fabricmc.loom.test.util.GradleProjectTestTrait + +import static net.fabricmc.loom.test.LoomTestConstants.STANDARD_TEST_VERSIONS +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS + +class IncludedJarsNoRemapTest extends Specification implements GradleProjectTestTrait { + @Unroll + def "included jars without remapping (gradle #version)"() { + setup: + def gradle = gradleProject(project: "includedJarsNoRemap", version: version) + + when: + def result = gradle.run(tasks: ["jar"]) + + then: + result.task(":jar").outcome == SUCCESS + + // Assert directly declared dependencies are present in jar (no remap) + gradle.hasOutputZipEntry("includedJars.jar", "META-INF/jars/log4j-core-2.22.0.jar") + gradle.hasOutputZipEntry("includedJars.jar", "META-INF/jars/adventure-text-serializer-gson-4.14.0.jar") + + // But not transitives. + !gradle.hasOutputZipEntry("includedJars.jar", "META-INF/jars/log4j-api-2.22.0.jar") + !gradle.hasOutputZipEntry("includedJars.jar", "META-INF/jars/adventure-api-4.14.0.jar") + + where: + version << STANDARD_TEST_VERSIONS + } +} \ No newline at end of file diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/IncludedJarsTest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/IncludedJarsTest.groovy index 457b61f8..e1ae8c66 100644 --- a/src/test/groovy/net/fabricmc/loom/test/integration/IncludedJarsTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/integration/IncludedJarsTest.groovy @@ -44,7 +44,7 @@ class IncludedJarsTest extends Specification implements GradleProjectTestTrait { then: result.task(":remapJar").outcome == SUCCESS - // Assert directly declared dependencies are present + // Assert directly declared dependencies are present in remapped jar gradle.hasOutputZipEntry("includedJars.jar", "META-INF/jars/log4j-core-2.22.0.jar") gradle.hasOutputZipEntry("includedJars.jar", "META-INF/jars/adventure-text-serializer-gson-4.14.0.jar") diff --git a/src/test/resources/projects/includedJarsNoRemap/build.gradle b/src/test/resources/projects/includedJarsNoRemap/build.gradle new file mode 100644 index 00000000..d13915ab --- /dev/null +++ b/src/test/resources/projects/includedJarsNoRemap/build.gradle @@ -0,0 +1,19 @@ +plugins { + id 'net.fabricmc.fabric-loom-no-remap-experimental' +} + +repositories { + mavenCentral() +} + +dependencies { + minecraft 'com.mojang:minecraft:25w45a_unobfuscated' + + include 'org.apache.logging.log4j:log4j-core:2.22.0' + + // Test bom/platform dependencies + include platform('net.kyori:adventure-bom:4.14.0') + + // bom provides version + include 'net.kyori:adventure-text-serializer-gson' +} diff --git a/src/test/resources/projects/includedJarsNoRemap/settings.gradle b/src/test/resources/projects/includedJarsNoRemap/settings.gradle new file mode 100644 index 00000000..7fdfcf73 --- /dev/null +++ b/src/test/resources/projects/includedJarsNoRemap/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'includedJars' diff --git a/src/test/resources/projects/includedJarsNoRemap/src/main/resources/fabric.mod.json b/src/test/resources/projects/includedJarsNoRemap/src/main/resources/fabric.mod.json new file mode 100644 index 00000000..33bad8c2 --- /dev/null +++ b/src/test/resources/projects/includedJarsNoRemap/src/main/resources/fabric.mod.json @@ -0,0 +1,9 @@ +{ + "schemaVersion": 1, + "id": "modid", + "version": "0.0.0", + + "name": "Example Mod", + "description": "This is an example description! Tell everyone what your mod is about!", + "environment": "*" +}