From 5f9f087ff76268fdb6f4ec64ff3a46c5e3100798 Mon Sep 17 00:00:00 2001 From: modmuss Date: Sat, 7 Sep 2024 12:50:20 +0100 Subject: [PATCH] Rewrite migrate mappings task to be configuration cache compatible. (#1167) --- .../mappings/TinyMappingsService.java | 51 ++++- .../loom/task/AbstractRemapJarTask.java | 7 - .../loom/task/MigrateMappingsTask.java | 196 +++--------------- .../task/service/MigrateMappingsService.java | 182 ++++++++++++++++ .../loom/util/gradle/GradleTypeAdapter.java | 16 ++ .../integration/MigrateMappingsTest.groovy | 115 +++++++++- 6 files changed, 379 insertions(+), 188 deletions(-) create mode 100644 src/main/java/net/fabricmc/loom/task/service/MigrateMappingsService.java diff --git a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/TinyMappingsService.java b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/TinyMappingsService.java index 80519337..6135aa23 100644 --- a/src/main/java/net/fabricmc/loom/configuration/providers/mappings/TinyMappingsService.java +++ b/src/main/java/net/fabricmc/loom/configuration/providers/mappings/TinyMappingsService.java @@ -31,10 +31,16 @@ import java.util.function.Supplier; import com.google.common.base.Suppliers; import org.gradle.api.Project; -import org.gradle.api.file.RegularFileProperty; +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.tasks.InputFile; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputFiles; +import org.gradle.api.tasks.Optional; +import org.jetbrains.annotations.Nullable; +import net.fabricmc.loom.util.FileSystemUtil; import net.fabricmc.loom.util.service.Service; import net.fabricmc.loom.util.service.ServiceFactory; import net.fabricmc.loom.util.service.ServiceType; @@ -45,12 +51,29 @@ public final class TinyMappingsService extends Service TYPE = new ServiceType<>(Options.class, TinyMappingsService.class); public interface Options extends Service.Options { - @InputFile - RegularFileProperty getMappings(); + @InputFiles + ConfigurableFileCollection getMappings(); // Only a single file + + /** + * When present, the mappings will be read from the specified zip entry path. + */ + @Optional + @Input + Property getZipEntryPath(); } public static Provider createOptions(Project project, Path mappings) { - return TYPE.create(project, options -> options.getMappings().set(project.file(mappings))); + return TYPE.create(project, options -> { + options.getMappings().from(project.file(mappings)); + options.getZipEntryPath().unset(); + }); + } + + public static Provider createOptions(Project project, FileCollection mappings, @Nullable String zipEntryPath) { + return TYPE.create(project, options -> { + options.getMappings().from(mappings); + options.getZipEntryPath().set(zipEntryPath); + }); } public TinyMappingsService(Options options, ServiceFactory serviceFactory) { @@ -58,14 +81,28 @@ public final class TinyMappingsService extends Service mappingTree = Suppliers.memoize(() -> { + Path mappings = getOptions().getMappings().getSingleFile().toPath(); + + if (getOptions().getZipEntryPath().isPresent()) { + try (FileSystemUtil.Delegate delegate = FileSystemUtil.getJarFileSystem(mappings)) { + return readMappings(delegate.fs().getPath(getOptions().getZipEntryPath().get())); + } catch (IOException e) { + throw new UncheckedIOException("Failed to read mappings from zip", e); + } + } + + return readMappings(mappings); + }); + + private MemoryMappingTree readMappings(Path mappings) { try { MemoryMappingTree mappingTree = new MemoryMappingTree(); - MappingReader.read(getOptions().getMappings().get().getAsFile().toPath(), mappingTree); + MappingReader.read(mappings, mappingTree); return mappingTree; } catch (IOException e) { throw new UncheckedIOException("Failed to read mappings", e); } - }); + } public MemoryMappingTree getMappingTree() { return mappingTree.get(); diff --git a/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java b/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java index 9621df62..9b818e38 100644 --- a/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java +++ b/src/main/java/net/fabricmc/loom/task/AbstractRemapJarTask.java @@ -47,7 +47,6 @@ 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.Internal; import org.gradle.api.tasks.Nested; import org.gradle.api.tasks.Optional; import org.gradle.api.tasks.SourceSet; @@ -246,12 +245,6 @@ public abstract class AbstractRemapJarTask extends Jar { return getInputFile(); } - @ApiStatus.Internal - @Internal - protected LoomGradleExtension getLoomExtension() { - return LoomGradleExtension.get(getProject()); - } - private SourceSet getClientSourceSet() { Preconditions.checkArgument(LoomGradleExtension.get(getProject()).areEnvironmentSourceSetsSplit(), "Cannot get client sourceset as project is not split"); return SourceSetHelper.getSourceSetByName(getClientOnlySourceSetName().get(), getProject()); diff --git a/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java b/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java index 7c122c82..123a5404 100644 --- a/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java +++ b/src/main/java/net/fabricmc/loom/task/MigrateMappingsTask.java @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2019-2022 FabricMC + * Copyright (c) 2019-2024 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,189 +24,47 @@ package net.fabricmc.loom.task; -import java.io.File; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Collections; -import java.util.Set; - -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Iterables; -import org.cadixdev.lorenz.MappingSet; -import org.cadixdev.mercury.Mercury; -import org.cadixdev.mercury.remapper.MercuryRemapper; -import org.gradle.api.GradleException; -import org.gradle.api.IllegalDependencyNotation; -import org.gradle.api.JavaVersion; -import org.gradle.api.Project; -import org.gradle.api.artifacts.Dependency; -import org.gradle.api.file.ConfigurableFileCollection; -import org.gradle.api.plugins.JavaPlugin; -import org.gradle.api.plugins.JavaPluginExtension; -import org.gradle.api.tasks.InputFiles; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputDirectory; +import org.gradle.api.tasks.Nested; +import org.gradle.api.tasks.OutputDirectory; import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.options.Option; import org.gradle.work.DisableCachingByDefault; -import net.fabricmc.loom.LoomGradleExtension; -import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; -import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuilderImpl; -import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsFactory; -import net.fabricmc.loom.configuration.providers.mappings.MappingConfiguration; -import net.fabricmc.loom.util.FileSystemUtil; -import net.fabricmc.loom.util.SourceRemapper; +import net.fabricmc.loom.task.service.MigrateMappingsService; import net.fabricmc.loom.util.service.ScopedServiceFactory; -import net.fabricmc.lorenztiny.TinyMappingsJoiner; -import net.fabricmc.mappingio.MappingReader; -import net.fabricmc.mappingio.tree.MemoryMappingTree; @DisableCachingByDefault(because = "Always rerun this task.") public abstract class MigrateMappingsTask extends AbstractLoomTask { - private Path inputDir; - private Path outputDir; - private String mappings; + @Input + @Option(option = "mappings", description = "Target mappings") + public abstract Property getMappings(); + + @InputDirectory + @Option(option = "input", description = "Java source file directory") + public abstract DirectoryProperty getInputDir(); + + @OutputDirectory + @Option(option = "output", description = "Remapped source output directory") + public abstract DirectoryProperty getOutputDir(); + + @Nested + protected abstract Property getMigrationServiceOptions(); public MigrateMappingsTask() { - inputDir = getProject().file("src/main/java").toPath(); - outputDir = getProject().file("remappedSrc").toPath(); - - // Ensure we resolve the classpath inputs before running the task. - getCompileClasspath().from(getProject().getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME)); - - notCompatibleWithConfigurationCache("Not yet supported."); + getInputDir().convention(getProject().getLayout().getProjectDirectory().dir("src/main/java")); + getOutputDir().convention(getProject().getLayout().getProjectDirectory().dir("remappedSrc")); + getMigrationServiceOptions().set(MigrateMappingsService.createOptions(getProject(), getMappings(), getInputDir(), getOutputDir())); } - @Option(option = "input", description = "Java source file directory") - public void setInputDir(String inputDir) { - this.inputDir = getProject().file(inputDir).toPath(); - } - - @Option(option = "output", description = "Remapped source output directory") - public void setOutputDir(String outputDir) { - this.outputDir = getProject().file(outputDir).toPath(); - } - - @Option(option = "mappings", description = "Target mappings") - public void setMappings(String mappings) { - this.mappings = mappings; - } - - @InputFiles - public abstract ConfigurableFileCollection getCompileClasspath(); - @TaskAction public void doTask() throws Throwable { - Project project = getProject(); - LoomGradleExtension extension = getExtension(); - - project.getLogger().info(":loading mappings"); - - if (!Files.exists(inputDir) || !Files.isDirectory(inputDir)) { - throw new IllegalArgumentException("Could not find input directory: " + inputDir.toAbsolutePath()); - } - - Files.createDirectories(outputDir); - - File mappings = loadMappings(); - MappingConfiguration mappingConfiguration = extension.getMappingConfiguration(); - try (var serviceFactory = new ScopedServiceFactory()) { - MemoryMappingTree currentMappings = mappingConfiguration.getMappingsService(project, serviceFactory).getMappingTree(); - MemoryMappingTree targetMappings = getMappings(mappings); - migrateMappings(project, extension, inputDir, outputDir, currentMappings, targetMappings); - project.getLogger().lifecycle(":remapped project written to " + outputDir.toAbsolutePath()); - } catch (IOException e) { - throw new IllegalArgumentException("Error while loading mappings", e); + MigrateMappingsService service = serviceFactory.get(getMigrationServiceOptions().get()); + service.migrateMapppings(); } } - - private File loadMappings() { - Project project = getProject(); - - if (mappings == null || mappings.isEmpty()) { - throw new IllegalArgumentException("No mappings were specified. Use --mappings=\"\" to specify target mappings"); - } - - Set files; - - try { - if (mappings.startsWith("net.minecraft:mappings:")) { - if (!mappings.endsWith(":" + LoomGradleExtension.get(project).getMinecraftProvider().minecraftVersion())) { - throw new UnsupportedOperationException("Migrating Mojang mappings is currently only supported for the specified minecraft version"); - } - - LayeredMappingsFactory dep = new LayeredMappingsFactory(LayeredMappingSpecBuilderImpl.buildOfficialMojangMappings()); - files = Collections.singleton(dep.resolve(getProject()).toFile()); - } else { - Dependency dependency = project.getDependencies().create(mappings); - files = project.getConfigurations().detachedConfiguration(dependency).resolve(); - } - } catch (IllegalDependencyNotation ignored) { - project.getLogger().info("Could not locate mappings, presuming V2 Yarn"); - - try { - files = project.getConfigurations().detachedConfiguration(project.getDependencies().create(ImmutableMap.of("group", "net.fabricmc", "name", "yarn", "version", mappings, "classifier", "v2"))).resolve(); - } catch (GradleException ignored2) { - project.getLogger().info("Could not locate mappings, presuming V1 Yarn"); - files = project.getConfigurations().detachedConfiguration(project.getDependencies().create(ImmutableMap.of("group", "net.fabricmc", "name", "yarn", "version", mappings))).resolve(); - } - } catch (IOException e) { - throw new UncheckedIOException("Failed to resolve mappings", e); - } - - if (files.isEmpty()) { - throw new IllegalArgumentException("Mappings could not be found"); - } - - return Iterables.getOnlyElement(files); - } - - private static MemoryMappingTree getMappings(File mappings) throws IOException { - MemoryMappingTree mappingTree = new MemoryMappingTree(); - - try (FileSystemUtil.Delegate delegate = FileSystemUtil.getJarFileSystem(mappings.toPath())) { - MappingReader.read(delegate.fs().getPath("mappings/mappings.tiny"), mappingTree); - } - - return mappingTree; - } - - private static void migrateMappings(Project project, LoomGradleExtension extension, - Path inputDir, Path outputDir, MemoryMappingTree currentMappings, MemoryMappingTree targetMappings - ) throws IOException { - project.getLogger().info(":joining mappings"); - - MappingSet mappingSet = new TinyMappingsJoiner( - currentMappings, MappingsNamespace.NAMED.toString(), - targetMappings, MappingsNamespace.NAMED.toString(), - MappingsNamespace.INTERMEDIARY.toString() - ).read(); - - project.getLogger().lifecycle(":remapping"); - Mercury mercury = SourceRemapper.createMercuryWithClassPath(project, false); - - final JavaVersion javaVersion = project.getExtensions().getByType(JavaPluginExtension.class).getSourceCompatibility(); - mercury.setSourceCompatibility(javaVersion.toString()); - - for (Path intermediaryJar : extension.getMinecraftJars(MappingsNamespace.INTERMEDIARY)) { - mercury.getClassPath().add(intermediaryJar); - } - - for (Path intermediaryJar : extension.getMinecraftJars(MappingsNamespace.NAMED)) { - mercury.getClassPath().add(intermediaryJar); - } - - mercury.getProcessors().add(MercuryRemapper.create(mappingSet)); - - try { - mercury.rewrite(inputDir, outputDir); - } catch (Exception e) { - project.getLogger().warn("Could not remap fully!", e); - } - - project.getLogger().info(":cleaning file descriptors"); - System.gc(); - } } diff --git a/src/main/java/net/fabricmc/loom/task/service/MigrateMappingsService.java b/src/main/java/net/fabricmc/loom/task/service/MigrateMappingsService.java new file mode 100644 index 00000000..0691cf26 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/task/service/MigrateMappingsService.java @@ -0,0 +1,182 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2024 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 java.nio.file.Files; +import java.nio.file.Path; + +import com.google.common.collect.ImmutableMap; +import org.cadixdev.lorenz.MappingSet; +import org.cadixdev.mercury.Mercury; +import org.cadixdev.mercury.remapper.MercuryRemapper; +import org.gradle.api.IllegalDependencyNotation; +import org.gradle.api.JavaVersion; +import org.gradle.api.Project; +import org.gradle.api.artifacts.Dependency; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.file.FileCollection; +import org.gradle.api.plugins.JavaPlugin; +import org.gradle.api.plugins.JavaPluginExtension; +import org.gradle.api.provider.Property; +import org.gradle.api.provider.Provider; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputDirectory; +import org.gradle.api.tasks.InputFiles; +import org.gradle.api.tasks.Nested; +import org.gradle.api.tasks.OutputDirectory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import net.fabricmc.loom.LoomGradleExtension; +import net.fabricmc.loom.api.mappings.layered.MappingsNamespace; +import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingSpecBuilderImpl; +import net.fabricmc.loom.configuration.providers.mappings.LayeredMappingsFactory; +import net.fabricmc.loom.configuration.providers.mappings.TinyMappingsService; +import net.fabricmc.loom.util.service.Service; +import net.fabricmc.loom.util.service.ServiceFactory; +import net.fabricmc.loom.util.service.ServiceType; +import net.fabricmc.lorenztiny.TinyMappingsJoiner; + +public class MigrateMappingsService extends Service { + private static final Logger LOGGER = LoggerFactory.getLogger(MigrateMappingsService.class); + private static final ServiceType TYPE = new ServiceType<>(Options.class, MigrateMappingsService.class); + + public MigrateMappingsService(Options options, ServiceFactory serviceFactory) { + super(options, serviceFactory); + } + + public interface Options extends Service.Options { + @Nested + Property getSourceMappings(); + @Nested + Property getTargetMappings(); + @InputDirectory + DirectoryProperty getInputDir(); + @Input + Property getSourceCompatibility(); + @InputFiles + ConfigurableFileCollection getClasspath(); + @OutputDirectory + DirectoryProperty getOutputDir(); + } + + public static Provider createOptions(Project project, Provider targetMappings, DirectoryProperty inputDir, DirectoryProperty outputDir) { + LoomGradleExtension extension = LoomGradleExtension.get(project); + final Provider from = project.provider(() -> "intermediary"); + final Provider to = project.provider(() -> "named"); + final JavaVersion javaVersion = project.getExtensions().getByType(JavaPluginExtension.class).getSourceCompatibility(); + + ConfigurableFileCollection classpath = project.getObjects().fileCollection(); + classpath.from(project.getConfigurations().getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME)); + // Question: why are both of these needed? + classpath.from(extension.getMinecraftJars(MappingsNamespace.INTERMEDIARY)); + classpath.from(extension.getMinecraftJars(MappingsNamespace.NAMED)); + + return TYPE.create(project, (o) -> { + FileCollection targetMappingsFile = getTargetMappingsFile(project, targetMappings.get()); + o.getSourceMappings().set(MappingsService.createOptionsWithProjectMappings(project, from, to)); + o.getTargetMappings().set(TinyMappingsService.createOptions(project, targetMappingsFile, "mappings/mappings.tiny")); + o.getSourceCompatibility().set(javaVersion.toString()); + o.getInputDir().set(inputDir); + o.getClasspath().from(classpath); + o.getOutputDir().set(outputDir); + }); + } + + public void migrateMapppings() throws IOException { + final Path inputDir = getOptions().getInputDir().get().getAsFile().toPath(); + final Path outputDir = getOptions().getOutputDir().get().getAsFile().toPath(); + + if (!Files.exists(inputDir) || !Files.isDirectory(inputDir)) { + throw new IllegalArgumentException("Could not find input directory: " + inputDir.toAbsolutePath()); + } + + Files.deleteIfExists(outputDir); + Files.createDirectories(outputDir); + + Mercury mercury = new Mercury(); + mercury.setGracefulClasspathChecks(true); + mercury.setSourceCompatibility(getOptions().getSourceCompatibility().get()); + + final MappingsService sourceMappingsService = getServiceFactory().get(getOptions().getSourceMappings().get()); + final TinyMappingsService targetMappingsService = getServiceFactory().get(getOptions().getTargetMappings().get()); + + final MappingSet mappingSet = new TinyMappingsJoiner( + sourceMappingsService.getMemoryMappingTree(), MappingsNamespace.NAMED.toString(), + targetMappingsService.getMappingTree(), MappingsNamespace.NAMED.toString(), + MappingsNamespace.INTERMEDIARY.toString() + ).read(); + + mercury.getProcessors().add(MercuryRemapper.create(mappingSet)); + + for (File file : getOptions().getClasspath().getFiles()) { + mercury.getClassPath().add(file.toPath()); + } + + try { + mercury.rewrite( + inputDir, + outputDir + ); + } catch (Exception e) { + LOGGER.warn("Could not remap fully!", e); + } + + // clean file descriptors + System.gc(); + } + + /** + * Return a mappings file for the requested mappings. + */ + private static FileCollection getTargetMappingsFile(Project project, String mappings) { + if (mappings == null || mappings.isEmpty()) { + throw new IllegalArgumentException("No mappings were specified. Use --mappings=\"\" to specify target mappings"); + } + + try { + if (mappings.startsWith("net.minecraft:mappings:")) { + if (!mappings.endsWith(":" + LoomGradleExtension.get(project).getMinecraftProvider().minecraftVersion())) { + throw new UnsupportedOperationException("Migrating Mojang mappings is currently only supported for the specified minecraft version"); + } + + LayeredMappingsFactory dep = new LayeredMappingsFactory(LayeredMappingSpecBuilderImpl.buildOfficialMojangMappings()); + return project.files(dep.resolve(project).toFile()); + } else { + Dependency dependency = project.getDependencies().create(mappings); + return project.getConfigurations().detachedConfiguration(dependency); + } + } catch (IllegalDependencyNotation ignored) { + LOGGER.info("Could not locate mappings, presuming V2 Yarn"); + return project.getConfigurations().detachedConfiguration(project.getDependencies().create(ImmutableMap.of("group", "net.fabricmc", "name", "yarn", "version", mappings, "classifier", "v2"))); + } catch (IOException e) { + throw new UncheckedIOException("Failed to resolve mappings", e); + } + } +} diff --git a/src/main/java/net/fabricmc/loom/util/gradle/GradleTypeAdapter.java b/src/main/java/net/fabricmc/loom/util/gradle/GradleTypeAdapter.java index 8f4782bc..e165b9a5 100644 --- a/src/main/java/net/fabricmc/loom/util/gradle/GradleTypeAdapter.java +++ b/src/main/java/net/fabricmc/loom/util/gradle/GradleTypeAdapter.java @@ -35,6 +35,7 @@ import com.google.gson.TypeAdapterFactory; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonWriter; +import org.gradle.api.file.DirectoryProperty; import org.gradle.api.file.FileCollection; import org.gradle.api.file.RegularFileProperty; import org.gradle.api.provider.ListProperty; @@ -55,6 +56,8 @@ public class GradleTypeAdapter implements TypeAdapterFactory { return new FileCollectionTypeAdapter(); } else if (RegularFileProperty.class.isAssignableFrom(rawClass)) { return new RegularFilePropertyTypeAdapter(); + } else if (DirectoryProperty.class.isAssignableFrom(rawClass)) { + return new DirectoryPropertyTypeAdapter(); } else if (ListProperty.class.isAssignableFrom(rawClass)) { return new ListPropertyTypeAdapter(gson); } else if (MapProperty.class.isAssignableFrom(rawClass)) { @@ -117,6 +120,19 @@ public class GradleTypeAdapter implements TypeAdapterFactory { } } + private static final class DirectoryPropertyTypeAdapter extends WriteOnlyTypeAdapter { + @Override + public void write(JsonWriter out, T property) throws IOException { + if (!property.isPresent()) { + out.nullValue(); + return; + } + + final File file = property.get().getAsFile(); + out.value(file.getAbsolutePath()); + } + } + private static final class ListPropertyTypeAdapter> extends WriteOnlyTypeAdapter { private final Gson gson; diff --git a/src/test/groovy/net/fabricmc/loom/test/integration/MigrateMappingsTest.groovy b/src/test/groovy/net/fabricmc/loom/test/integration/MigrateMappingsTest.groovy index 08bf7f60..aab06c36 100644 --- a/src/test/groovy/net/fabricmc/loom/test/integration/MigrateMappingsTest.groovy +++ b/src/test/groovy/net/fabricmc/loom/test/integration/MigrateMappingsTest.groovy @@ -1,7 +1,7 @@ /* * This file is part of fabric-loom, licensed under the MIT License (MIT). * - * Copyright (c) 2021 FabricMC + * Copyright (c) 2021-2024 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 @@ -34,20 +34,125 @@ import static org.gradle.testkit.runner.TaskOutcome.SUCCESS class MigrateMappingsTest extends Specification implements GradleProjectTestTrait { @Unroll - def "Migrate mappings (gradle #version)"() { + def "Migrate mappings yarn short hand (gradle #version)"() { setup: - def gradle = gradleProject(project: "java16", version: version) + def gradle = gradleProject(project: "minimalBase", version: version) + gradle.buildGradle << """ + dependencies { + minecraft 'com.mojang:minecraft:24w36a' + mappings 'net.fabricmc:yarn:24w36a+build.2:v2' + } + """.stripIndent() + + def sourceFile = new File(gradle.projectDir, "src/main/java/example/Test.java") + sourceFile.parentFile.mkdirs() + sourceFile.text = """ + package example; + + import net.minecraft.class_10184; + + public class Test { + public static void main(String[] args) { + class_10184 cls = null; + } + } + """ when: def result = gradle.run(tasks: [ "migrateMappings", "--mappings", - "21w38a+build.10" + "24w36a+build.6" ]) + def remapped = new File(gradle.projectDir, "remappedSrc/example/Test.java").text then: result.task(":migrateMappings").outcome == SUCCESS - // TODO check it actually did something + remapped.contains("import net.minecraft.predicate.entity.InputPredicate;") + remapped.contains("InputPredicate cls = null;") + + where: + version << STANDARD_TEST_VERSIONS + } + + @Unroll + def "Migrate mappings maven complete (gradle #version)"() { + setup: + def gradle = gradleProject(project: "minimalBase", version: version) + gradle.buildGradle << """ + dependencies { + minecraft 'com.mojang:minecraft:24w36a' + mappings 'net.fabricmc:yarn:24w36a+build.2:v2' + } + """.stripIndent() + + def sourceFile = new File(gradle.projectDir, "src/main/java/example/Test.java") + sourceFile.parentFile.mkdirs() + sourceFile.text = """ + package example; + + import net.minecraft.class_10184; + + public class Test { + public static void main(String[] args) { + class_10184 cls = null; + } + } + """ + + when: + def result = gradle.run(tasks: [ + "migrateMappings", + "--mappings", + "net.fabricmc:yarn:24w36a+build.6:v2" + ]) + def remapped = new File(gradle.projectDir, "remappedSrc/example/Test.java").text + + then: + result.task(":migrateMappings").outcome == SUCCESS + remapped.contains("import net.minecraft.predicate.entity.InputPredicate;") + remapped.contains("InputPredicate cls = null;") + + where: + version << STANDARD_TEST_VERSIONS + } + + @Unroll + def "Migrate mappings to mojmap (gradle #version)"() { + setup: + def gradle = gradleProject(project: "minimalBase", version: version) + gradle.buildGradle << """ + dependencies { + minecraft 'com.mojang:minecraft:24w36a' + mappings 'net.fabricmc:yarn:24w36a+build.6:v2' + } + """.stripIndent() + + def sourceFile = new File(gradle.projectDir, "src/main/java/example/Test.java") + sourceFile.parentFile.mkdirs() + sourceFile.text = """ + package example; + + import net.minecraft.predicate.entity.InputPredicate; + + public class Test { + public static void main(String[] args) { + InputPredicate cls = null; + } + } + """ + + when: + def result = gradle.run(tasks: [ + "migrateMappings", + "--mappings", + "net.minecraft:mappings:24w36a" + ]) + def remapped = new File(gradle.projectDir, "remappedSrc/example/Test.java").text + + then: + result.task(":migrateMappings").outcome == SUCCESS + remapped.contains("import net.minecraft.advancements.critereon.InputPredicate;") where: version << STANDARD_TEST_VERSIONS