diff --git a/build.gradle b/build.gradle index 950b8450e6..5fbf1e1535 100644 --- a/build.gradle +++ b/build.gradle @@ -12,7 +12,6 @@ buildscript { classpath "net.fabricmc:stitch:${project.stitch_version}" classpath "commons-io:commons-io:2.11.0" classpath "de.undercouch:gradle-download-task:4.1.1" - classpath "net.fabricmc:tiny-remapper:${project.tiny_remapper_version}" classpath "net.fabricmc.unpick:unpick:${project.unpick_version}" classpath "net.fabricmc.unpick:unpick-format-utils:${project.unpick_version}" classpath "net.fabricmc:name-proposal:${project.name_proposal_version}" @@ -119,22 +118,16 @@ import cuchaz.enigma.command.CheckMappingsCommand import cuchaz.enigma.command.ComposeMappingsCommand import cuchaz.enigma.command.ConvertMappingsCommand import cuchaz.enigma.command.MapSpecializedMethodsCommand -import groovy.io.FileType import groovy.json.JsonSlurper +import net.fabricmc.filament.task.MapJarTask import net.fabricmc.stitch.commands.CommandMergeTiny import net.fabricmc.stitch.commands.CommandReorderTiny import net.fabricmc.stitch.commands.CommandRewriteIntermediary import net.fabricmc.stitch.commands.tinyv2.CommandMergeTinyV2 import net.fabricmc.stitch.commands.tinyv2.CommandReorderTinyV2 import net.fabricmc.stitch.merge.JarMerger -import net.fabricmc.tinyremapper.OutputConsumerPath -import net.fabricmc.tinyremapper.TinyRemapper -import net.fabricmc.tinyremapper.TinyUtils import net.fabricmc.nameproposal.MappingNameCompleter import org.apache.commons.io.FileUtils -import org.objectweb.asm.ClassVisitor -import org.objectweb.asm.FieldVisitor -import org.objectweb.asm.Opcodes; import java.nio.charset.StandardCharsets import java.util.zip.GZIPOutputStream @@ -417,34 +410,24 @@ task patchIntermediary(dependsOn: [mergeJars, downloadIntermediary]) { } } -task mapIntermediaryJar(dependsOn: [downloadMcLibs, downloadIntermediary, mergeJars]) { +task mapIntermediaryJar(type: MapJarTask, dependsOn: [downloadMcLibs, downloadIntermediary, mergeJars]) { group = mapJarGroup - inputs.files downloadMcLibs.outputs.files.files - outputs.file(intermediaryJar) - - //Force the task to always run - outputs.upToDateWhen { false } - - doLast { - logger.lifecycle(":mapping minecraft to intermediary") - def tinyInput = downloadIntermediary.dest - mapJar(intermediaryJar, mergedFile, tinyInput, libraries, "official", "intermediary") - } + output = intermediaryJar + input = mergedFile + mappings = downloadIntermediary.dest + classpath.from fileTree(libraries) + from = 'official' + to = 'intermediary' } -task mapServerIntermediaryJar(dependsOn: [downloadMcLibs, downloadIntermediary, extractServerJar]) { +task mapServerIntermediaryJar(type: MapJarTask, dependsOn: [downloadMcLibs, downloadIntermediary, extractServerJar]) { group = mapJarGroup - inputs.files downloadMcLibs.outputs.files.files - outputs.file(serverIntermediaryJar) - - //Force the task to always run - outputs.upToDateWhen { false } - - doLast { - logger.lifecycle(":mapping minecraft server to intermediary") - def tinyInput = downloadIntermediary.dest - mapJar(serverIntermediaryJar, serverJar, tinyInput, libraries, "official", "intermediary") - } + output = serverIntermediaryJar + input = serverJar + mappings = downloadIntermediary.dest + classpath.from fileTree(libraries) + from = 'official' + to = 'intermediary' } task yarnUnpicked(dependsOn: "unpickIntermediaryJar", type: EnigmaTask) { @@ -636,33 +619,6 @@ task importMappingsOfficial(dependsOn: invertIntermediary) { } } -task mapNamedJar(dependsOn: ["mergeV2", "unpickIntermediaryJar"]) { - group = mapJarGroup - inputs.files downloadMcLibs.outputs.files.files - outputs.file(namedJar) - - //Force the task to always run - outputs.upToDateWhen { false } - - def jsrToJetbrains = [ - "javax/annotation/Nullable": "org/jetbrains/annotations/Nullable", - "javax/annotation/Nonnull": "org/jetbrains/annotations/NotNull", - "javax/annotation/concurrent/Immutable": "org/jetbrains/annotations/Unmodifiable" - ] - - doLast { - logger.lifecycle(":mapping minecraft to named") - - mapJar(namedJar, unpickedJar, mergeV2.output, libraries, "intermediary", "named") { - it.withMappings { out -> - jsrToJetbrains.each { e -> - out.acceptClass e.key, e.value - } - } - } - } -} - combineUnpickDefinitions { group = 'unpick' input = file('unpick-definitions') @@ -821,6 +777,21 @@ task v2MergedYarnJar(dependsOn: ["mergeV2"], type: Jar) { } } +task mapNamedJar(type: MapJarTask, dependsOn: ["mergeV2", "unpickIntermediaryJar"]) { + group = mapJarGroup + output = namedJar + input = unpickedJar + mappings = mergeV2.output + classpath.from fileTree(libraries) + from = 'intermediary' + to = 'named' + classMappings = [ + "javax/annotation/Nullable": "org/jetbrains/annotations/Nullable", + "javax/annotation/Nonnull": "org/jetbrains/annotations/NotNull", + "javax/annotation/concurrent/Immutable": "org/jetbrains/annotations/Unmodifiable" + ] +} + def fakeSourceDir = file(".gradle/temp/fakeSource") task genFakeSource(type: JavaExec, dependsOn: ["mergeV2", "mapNamedJar"]) { group = "javadoc generation" @@ -1003,42 +974,6 @@ task checkVersion { publish.mustRunAfter checkVersion -void mapJar(File output, File input, File mappings, File libraries, String from, String to, - Action action = { }) { - if (output.exists()) { - output.delete() - } - - def remapperBuilder = TinyRemapper.newRemapper() - .withMappings(TinyUtils.createTinyMappingProvider(mappings.toPath(), from, to)) - .renameInvalidLocals(true) - .rebuildSourceFilenames(true) - .invalidLvNamePattern(~/\$\$\d+/) - .inferNameFromSameLvIndex(true) - - action.execute(remapperBuilder) - def remapper = remapperBuilder - .build() - - try { - def outputConsumerBuilder = new OutputConsumerPath.Builder(output.toPath()) - // expose output consumer builder to function if there is need in the future - def outputConsumer = outputConsumerBuilder.build() - outputConsumer.addNonClassFiles(input.toPath()) - remapper.readInputs(input.toPath()) - - libraries.eachFileRecurse(FileType.FILES) { file -> - remapper.readClassPath(file.toPath()) - } - remapper.apply(outputConsumer) - outputConsumer.close() - remapper.finish() - } catch (Exception e) { - remapper.finish() - throw new RuntimeException("Failed to remap jar", e) - } -} - class FileOutput extends DefaultTask { @OutputFile File output diff --git a/filament/build.gradle b/filament/build.gradle index 2b95a69501..54f6af479b 100644 --- a/filament/build.gradle +++ b/filament/build.gradle @@ -26,6 +26,7 @@ dependencies { implementation "net.fabricmc.unpick:unpick:$properties.unpick_version" implementation "net.fabricmc.unpick:unpick-format-utils:$properties.unpick_version" implementation "net.fabricmc:tiny-mappings-parser:$properties.tiny_mappings_parser_version" + implementation "net.fabricmc:tiny-remapper:$properties.tiny_remapper_version" testImplementation platform("org.junit:junit-bom:$properties.junit_version") testImplementation 'org.junit.jupiter:junit-jupiter' diff --git a/filament/src/main/java/net/fabricmc/filament/task/MapJarTask.java b/filament/src/main/java/net/fabricmc/filament/task/MapJarTask.java new file mode 100644 index 0000000000..531078e25c --- /dev/null +++ b/filament/src/main/java/net/fabricmc/filament/task/MapJarTask.java @@ -0,0 +1,131 @@ +package net.fabricmc.filament.task; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; +import java.util.regex.Pattern; + +import javax.inject.Inject; + +import org.gradle.api.DefaultTask; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.file.FileSystemLocation; +import org.gradle.api.file.FileVisitDetails; +import org.gradle.api.file.FileVisitor; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.provider.MapProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.provider.Provider; +import org.gradle.api.tasks.Classpath; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputFile; +import org.gradle.api.tasks.OutputFile; +import org.gradle.api.tasks.TaskAction; +import org.gradle.workers.WorkAction; +import org.gradle.workers.WorkParameters; +import org.gradle.workers.WorkQueue; +import org.gradle.workers.WorkerExecutor; + +import net.fabricmc.tinyremapper.OutputConsumerPath; +import net.fabricmc.tinyremapper.TinyRemapper; +import net.fabricmc.tinyremapper.TinyUtils; + +public abstract class MapJarTask extends DefaultTask { + @InputFile public abstract RegularFileProperty getInput(); + @InputFile public abstract RegularFileProperty getMappings(); + @OutputFile public abstract RegularFileProperty getOutput(); + @Classpath public abstract ConfigurableFileCollection getClasspath(); + @Input public abstract Property getFrom(); + @Input public abstract Property getTo(); + @Input public abstract MapProperty getClassMappings(); + + @Inject + protected abstract WorkerExecutor getWorkerExecutor(); + + public MapJarTask() { + getClassMappings().convention(Map.of()); + } + + @TaskAction + public void remap() { + getProject().getLogger().lifecycle(":remapping {} from {} to {}", getInput().get().getAsFile(), getFrom().get(), getTo().get()); + + WorkQueue workQueue = getWorkerExecutor().noIsolation(); + workQueue.submit(RemapAction.class, parameters -> { + parameters.getInput().set(getInput()); + parameters.getMappings().set(getMappings()); + parameters.getOutput().set(getOutput()); + parameters.getClasspath().setFrom(getClasspath()); + parameters.getFrom().set(getFrom()); + parameters.getTo().set(getTo()); + parameters.getClassMappings().set(getClassMappings()); + }); + } + + public interface RemapParameters extends WorkParameters { + @InputFile RegularFileProperty getInput(); + @InputFile RegularFileProperty getMappings(); + @OutputFile RegularFileProperty getOutput(); + @Classpath ConfigurableFileCollection getClasspath(); + @Input Property getFrom(); + @Input Property getTo(); + @Input MapProperty getClassMappings(); + } + + public abstract static class RemapAction implements WorkAction { + @Inject + public RemapAction() { + } + + private static Path getPath(Provider provider) { + return provider.get().getAsFile().toPath(); + } + + @Override + public void execute() { + try { + doExecute(); + } catch (Exception e) { + throw new RuntimeException("Failed to remap jar: " + e.getMessage(), e); + } + } + + private void doExecute() throws IOException { + RemapParameters params = getParameters(); + Path output = getPath(params.getOutput()); + Files.deleteIfExists(output); + + TinyRemapper.Builder remapperBuilder = TinyRemapper.newRemapper() + .withMappings(TinyUtils.createTinyMappingProvider(getPath(params.getMappings()), params.getFrom().get(), params.getTo().get())) + .renameInvalidLocals(true) + .rebuildSourceFilenames(true) + .invalidLvNamePattern(Pattern.compile("\\$\\$\\d+")) + .inferNameFromSameLvIndex(true); + remapperBuilder.withMappings(out -> params.getClassMappings().get().forEach(out::acceptClass)); + TinyRemapper remapper = remapperBuilder.build(); + + try (OutputConsumerPath outputConsumer = new OutputConsumerPath.Builder(output).build()) { + Path input = getPath(params.getInput()); + outputConsumer.addNonClassFiles(input); + remapper.readInputs(input); + + params.getClasspath().getAsFileTree().visit(new FileVisitor() { + @Override + public void visitDir(FileVisitDetails dirDetails) { + // ignore + } + + @Override + public void visitFile(FileVisitDetails fileDetails) { + remapper.readClassPath(fileDetails.getFile().toPath()); + } + }); + + remapper.apply(outputConsumer); + } finally { + remapper.finish(); + } + } + } +}