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 "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<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 {
@OutputFile
File output

View File

@ -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'

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();
}
}
}
}