diff --git a/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java b/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java index 69c44a1a..8fa3170d 100644 --- a/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java +++ b/src/main/java/net/fabricmc/loom/api/LoomGradleExtensionAPI.java @@ -70,9 +70,7 @@ public interface LoomGradleExtensionAPI { ConfigurableFileCollection getLog4jConfigs(); - default Dependency officialMojangMappings() { - return layered(LayeredMappingSpecBuilder::officialMojangMappings); - } + Dependency officialMojangMappings(); Dependency layered(Action action); diff --git a/src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java b/src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java index 4775599b..872fb6fa 100644 --- a/src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java +++ b/src/main/java/net/fabricmc/loom/configuration/mods/ModProcessor.java @@ -24,6 +24,8 @@ package net.fabricmc.loom.configuration.mods; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.UncheckedIOException; @@ -33,6 +35,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.jar.Manifest; import com.google.gson.JsonObject; import org.gradle.api.Project; @@ -47,6 +50,7 @@ import net.fabricmc.loom.configuration.RemappedConfigurationEntry; import net.fabricmc.loom.configuration.processors.dependency.ModDependencyInfo; import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl; import net.fabricmc.loom.kotlin.remapping.KotlinMetadataTinyRemapperExtension; +import net.fabricmc.loom.task.RemapJarTask; import net.fabricmc.loom.util.Constants; import net.fabricmc.loom.util.TinyRemapperHelper; import net.fabricmc.loom.util.ZipUtils; @@ -217,8 +221,21 @@ public class ModProcessor { } stripNestedJars(info.getRemappedOutput()); + remapJarManifestEntries(info.getRemappedOutput().toPath()); info.finaliseRemapping(); } } + + private void remapJarManifestEntries(Path jar) throws IOException { + ZipUtils.transform(jar, Map.of(RemapJarTask.MANIFEST_PATH, bytes -> { + var manifest = new Manifest(new ByteArrayInputStream(bytes)); + + manifest.getMainAttributes().putValue(RemapJarTask.MANIFEST_NAMESPACE_KEY, toM); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + manifest.write(out); + return out.toByteArray(); + })); + } } diff --git a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java index 490fa4d1..d5e8edba 100644 --- a/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java +++ b/src/main/java/net/fabricmc/loom/extension/LoomGradleExtensionApiImpl.java @@ -80,6 +80,9 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA private final NamedDomainObjectContainer decompilers; private final NamedDomainObjectContainer mods; + // A common mistake with layered mappings is to call the wrong `officialMojangMappings` method, use this to keep track of when we are building a layered mapping spec. + protected final ThreadLocal layeredSpecBuilderScope = ThreadLocal.withInitial(() -> false); + protected LoomGradleExtensionApiImpl(Project project, LoomFiles directories) { this.jarProcessors = project.getObjects().listProperty(JarProcessor.class) .empty(); @@ -165,10 +168,23 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA return jarProcessors; } + @Override + public Dependency officialMojangMappings() { + if (layeredSpecBuilderScope.get()) { + throw new IllegalStateException("Use `officialMojangMappings()` when configuring layered mappings, not the extension method `loom.officialMojangMappings()`"); + } + + return layered(LayeredMappingSpecBuilder::officialMojangMappings); + } + @Override public Dependency layered(Action action) { LayeredMappingSpecBuilderImpl builder = new LayeredMappingSpecBuilderImpl(); + + layeredSpecBuilderScope.set(true); action.execute(builder); + layeredSpecBuilderScope.set(false); + LayeredMappingSpec builtSpec = builder.build(); return new LayeredMappingsDependency(getProject(), new GradleMappingContext(getProject(), builtSpec.getVersion().replace("+", "_").replace(".", "_")), builtSpec, builtSpec.getVersion()); } diff --git a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java index 83af5533..86f43489 100644 --- a/src/main/java/net/fabricmc/loom/task/RemapJarTask.java +++ b/src/main/java/net/fabricmc/loom/task/RemapJarTask.java @@ -83,7 +83,8 @@ import net.fabricmc.tinyremapper.OutputConsumerPath; import net.fabricmc.tinyremapper.TinyRemapper; public abstract class RemapJarTask extends AbstractRemapJarTask { - private static final String MANIFEST_PATH = "META-INF/MANIFEST.MF"; + public static final String MANIFEST_PATH = "META-INF/MANIFEST.MF"; + public static final String MANIFEST_NAMESPACE_KEY = "Fabric-Mapping-Namespace"; @InputFiles public abstract ConfigurableFileCollection getNestedJars(); @@ -306,7 +307,7 @@ public abstract class RemapJarTask extends AbstractRemapJarTask { var manifest = new Manifest(new ByteArrayInputStream(bytes)); getParameters().getJarManifestService().get().apply(manifest, getParameters().getManifestAttributes().get()); - manifest.getMainAttributes().putValue("Fabric-Mapping-Namespace", getParameters().getTargetNamespace().get()); + manifest.getMainAttributes().putValue(MANIFEST_NAMESPACE_KEY, getParameters().getTargetNamespace().get()); ByteArrayOutputStream out = new ByteArrayOutputStream(); manifest.write(out); diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/MojangMappingsProjectTest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/MojangMappingsProjectTest.groovy index 6afba527..2e1db92c 100644 --- a/src/test/groovy/net/fabricmc/loom/test/integration/MojangMappingsProjectTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/integration/MojangMappingsProjectTest.groovy @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2018-2021 FabricMC + * Copyright (c) 2018-2022 FabricMC * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -74,4 +74,29 @@ class MojangMappingsProjectTest extends Specification implements GradleProjectTe where: version << STANDARD_TEST_VERSIONS } + + @Unroll + def "fail with wrong officialMojangMappings usage (gradle #version)"() { + setup: + def gradle = gradleProject(project: "minimalBase", version: version) + + gradle.buildGradle << ''' + dependencies { + minecraft "com.mojang:minecraft:1.18.2" + mappings loom.layered { + // This is the wrong method to call! + loom.officialMojangMappings() + } + } + ''' + + when: + def result = gradle.run(task: "build", expectFailure: true) + + then: + result.output.contains("Use `officialMojangMappings()` when configuring layered mappings, not the extension method `loom.officialMojangMappings()`") + + where: + version << STANDARD_TEST_VERSIONS + } }