Move jar remapping to Filament (#3300)

* Move jar remapping to Filament

* Replace MapJarTask.libraryDir with a file collection

* Use a more compact format for the task properties
This commit is contained in:
Juuz 2022-09-21 00:37:53 +03:00 committed by GitHub
parent 9c83509bfc
commit a7bf49e655
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 162 additions and 95 deletions

View File

@ -12,7 +12,6 @@ buildscript {
classpath "net.fabricmc:stitch:${project.stitch_version}" classpath "net.fabricmc:stitch:${project.stitch_version}"
classpath "commons-io:commons-io:2.11.0" classpath "commons-io:commons-io:2.11.0"
classpath "de.undercouch:gradle-download-task:4.1.1" 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:${project.unpick_version}"
classpath "net.fabricmc.unpick:unpick-format-utils:${project.unpick_version}" classpath "net.fabricmc.unpick:unpick-format-utils:${project.unpick_version}"
classpath "net.fabricmc:name-proposal:${project.name_proposal_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.ComposeMappingsCommand
import cuchaz.enigma.command.ConvertMappingsCommand import cuchaz.enigma.command.ConvertMappingsCommand
import cuchaz.enigma.command.MapSpecializedMethodsCommand import cuchaz.enigma.command.MapSpecializedMethodsCommand
import groovy.io.FileType
import groovy.json.JsonSlurper import groovy.json.JsonSlurper
import net.fabricmc.filament.task.MapJarTask
import net.fabricmc.stitch.commands.CommandMergeTiny import net.fabricmc.stitch.commands.CommandMergeTiny
import net.fabricmc.stitch.commands.CommandReorderTiny import net.fabricmc.stitch.commands.CommandReorderTiny
import net.fabricmc.stitch.commands.CommandRewriteIntermediary import net.fabricmc.stitch.commands.CommandRewriteIntermediary
import net.fabricmc.stitch.commands.tinyv2.CommandMergeTinyV2 import net.fabricmc.stitch.commands.tinyv2.CommandMergeTinyV2
import net.fabricmc.stitch.commands.tinyv2.CommandReorderTinyV2 import net.fabricmc.stitch.commands.tinyv2.CommandReorderTinyV2
import net.fabricmc.stitch.merge.JarMerger 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 net.fabricmc.nameproposal.MappingNameCompleter
import org.apache.commons.io.FileUtils 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.nio.charset.StandardCharsets
import java.util.zip.GZIPOutputStream 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 group = mapJarGroup
inputs.files downloadMcLibs.outputs.files.files output = intermediaryJar
outputs.file(intermediaryJar) input = mergedFile
mappings = downloadIntermediary.dest
//Force the task to always run classpath.from fileTree(libraries)
outputs.upToDateWhen { false } from = 'official'
to = 'intermediary'
doLast {
logger.lifecycle(":mapping minecraft to intermediary")
def tinyInput = downloadIntermediary.dest
mapJar(intermediaryJar, mergedFile, tinyInput, libraries, "official", "intermediary")
}
} }
task mapServerIntermediaryJar(dependsOn: [downloadMcLibs, downloadIntermediary, extractServerJar]) { task mapServerIntermediaryJar(type: MapJarTask, dependsOn: [downloadMcLibs, downloadIntermediary, extractServerJar]) {
group = mapJarGroup group = mapJarGroup
inputs.files downloadMcLibs.outputs.files.files output = serverIntermediaryJar
outputs.file(serverIntermediaryJar) input = serverJar
mappings = downloadIntermediary.dest
//Force the task to always run classpath.from fileTree(libraries)
outputs.upToDateWhen { false } from = 'official'
to = 'intermediary'
doLast {
logger.lifecycle(":mapping minecraft server to intermediary")
def tinyInput = downloadIntermediary.dest
mapJar(serverIntermediaryJar, serverJar, tinyInput, libraries, "official", "intermediary")
}
} }
task yarnUnpicked(dependsOn: "unpickIntermediaryJar", type: EnigmaTask) { 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 { combineUnpickDefinitions {
group = 'unpick' group = 'unpick'
input = file('unpick-definitions') 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") def fakeSourceDir = file(".gradle/temp/fakeSource")
task genFakeSource(type: JavaExec, dependsOn: ["mergeV2", "mapNamedJar"]) { task genFakeSource(type: JavaExec, dependsOn: ["mergeV2", "mapNamedJar"]) {
group = "javadoc generation" group = "javadoc generation"
@ -1003,42 +974,6 @@ task checkVersion {
publish.mustRunAfter checkVersion publish.mustRunAfter checkVersion
void mapJar(File output, File input, File mappings, File libraries, String from, String to,
Action<TinyRemapper.Builder> 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 { class FileOutput extends DefaultTask {
@OutputFile @OutputFile
File output File output

View File

@ -26,6 +26,7 @@ dependencies {
implementation "net.fabricmc.unpick:unpick:$properties.unpick_version" implementation "net.fabricmc.unpick:unpick:$properties.unpick_version"
implementation "net.fabricmc.unpick:unpick-format-utils:$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-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 platform("org.junit:junit-bom:$properties.junit_version")
testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.junit.jupiter:junit-jupiter'

View File

@ -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<String> getFrom();
@Input public abstract Property<String> getTo();
@Input public abstract MapProperty<String, String> 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<String> getFrom();
@Input Property<String> getTo();
@Input MapProperty<String, String> getClassMappings();
}
public abstract static class RemapAction implements WorkAction<RemapParameters> {
@Inject
public RemapAction() {
}
private static Path getPath(Provider<? extends FileSystemLocation> 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();
}
}
}
}