Decompiler API improvements:

* Fix decompiler tasks getting registered in afterEvaluate
* Allow decompilers to add file collections to the forked JVM classpath.
* General code cleanup.
This commit is contained in:
modmuss50 2021-12-29 00:10:58 +00:00
parent e4244dc895
commit 53b839b739
9 changed files with 106 additions and 73 deletions

View file

@ -25,6 +25,7 @@
package net.fabricmc.loom.api;
import org.gradle.api.Action;
import org.gradle.api.DomainObjectCollection;
import org.gradle.api.NamedDomainObjectContainer;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.file.ConfigurableFileCollection;
@ -55,7 +56,7 @@ public interface LoomGradleExtensionAPI {
getShareRemapCaches().set(true);
}
ListProperty<LoomDecompiler> getGameDecompilers();
DomainObjectCollection<LoomDecompiler> getGameDecompilers();
default void addDecompiler(LoomDecompiler decompiler) {
getGameDecompilers().add(decompiler);

View file

@ -26,6 +26,10 @@ package net.fabricmc.loom.api.decompilers;
import java.nio.file.Path;
import org.gradle.api.Project;
import org.gradle.api.file.FileCollection;
import org.jetbrains.annotations.Nullable;
public interface LoomDecompiler {
String name();
@ -37,4 +41,12 @@ public interface LoomDecompiler {
* @param metaData Additional information that may or may not be needed while decompiling
*/
void decompile(Path compiledJar, Path sourcesDestination, Path linemapDestination, DecompilationMetadata metaData);
/**
* Add additional classpath entries to the decompiler classpath, can return a configuration.
*/
@Nullable
default FileCollection getBootstrapClasspath(Project project) {
return null;
}
}

View file

@ -24,6 +24,7 @@
package net.fabricmc.loom.configuration;
import java.io.File;
import java.nio.charset.StandardCharsets;
import org.gradle.api.NamedDomainObjectProvider;
@ -33,6 +34,7 @@ import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.tasks.AbstractCopyTask;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.TaskContainer;
import org.gradle.api.tasks.compile.JavaCompile;
import org.gradle.api.tasks.javadoc.Javadoc;
@ -44,6 +46,8 @@ import net.fabricmc.loom.configuration.providers.LaunchProvider;
import net.fabricmc.loom.configuration.providers.MinecraftProviderImpl;
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
import net.fabricmc.loom.extension.MixinExtension;
import net.fabricmc.loom.task.GenerateSourcesTask;
import net.fabricmc.loom.task.UnpickJarTask;
import net.fabricmc.loom.util.Constants;
public final class CompileConfiguration {
@ -125,10 +129,10 @@ public final class CompileConfiguration {
final JavaPluginExtension javaPluginExtension = p.getExtensions().getByType(JavaPluginExtension.class);
LoomGradleExtension extension = LoomGradleExtension.get(p);
SourceSet main = javaPluginExtension.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME);
Javadoc javadoc = (Javadoc) p.getTasks().getByName(JavaPlugin.JAVADOC_TASK_NAME);
javadoc.setClasspath(main.getOutput().plus(main.getCompileClasspath()));
p.getTasks().named(JavaPlugin.JAVADOC_TASK_NAME, Javadoc.class).configure(javadoc -> {
final SourceSet main = javaPluginExtension.getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME);
javadoc.setClasspath(main.getOutput().plus(main.getCompileClasspath()));
});
p.afterEvaluate(project -> {
LoomDependencyManager dependencyManager = new LoomDependencyManager();
@ -140,10 +144,6 @@ public final class CompileConfiguration {
dependencyManager.handleDependencies(project);
project.getTasks().getByName("idea").finalizedBy(project.getTasks().getByName("genIdeaWorkspace"));
project.getTasks().getByName("eclipse").finalizedBy(project.getTasks().getByName("genEclipseRuns"));
project.getTasks().getByName("cleanEclipse").finalizedBy(project.getTasks().getByName("cleanEclipseRuns"));
extension.getRemapArchives().finalizeValue();
MixinExtension mixin = LoomGradleExtension.get(project).getMixin();
@ -151,10 +151,16 @@ public final class CompileConfiguration {
if (mixin.getUseLegacyMixinAp().get()) {
setupMixinAp(project, mixin);
}
configureDecompileTasks(project);
});
finalizedBy(p, "idea", "genIdeaWorkspace");
finalizedBy(p, "eclipse", "genEclipseRuns");
finalizedBy(p, "cleanEclipse", "cleanEclipseRuns");
// Add the "dev" jar to the "namedElements" configuration
p.artifacts(artifactHandler -> artifactHandler.add(Constants.Configurations.NAMED_ELEMENTS, p.getTasks().getByName("jar")));
p.artifacts(artifactHandler -> artifactHandler.add(Constants.Configurations.NAMED_ELEMENTS, p.getTasks().named("jar")));
// Ensure that the encoding is set to UTF-8, no matter what the system default is
// this fixes some edge cases with special characters not displaying correctly
@ -191,7 +197,47 @@ public final class CompileConfiguration {
}
}
private static void configureDecompileTasks(Project project) {
final TaskContainer tasks = project.getTasks();
final LoomGradleExtension extension = LoomGradleExtension.get(project);
MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
File mappedJar = mappingsProvider.mappedProvider.getMappedJar();
if (mappingsProvider.hasUnpickDefinitions()) {
File outputJar = mappingsProvider.mappedProvider.getUnpickedJar();
tasks.register("unpickJar", UnpickJarTask.class, unpickJarTask -> {
unpickJarTask.getUnpickDefinitions().set(mappingsProvider.getUnpickDefinitionsFile());
unpickJarTask.getInputJar().set(mappingsProvider.mappedProvider.getMappedJar());
unpickJarTask.getOutputJar().set(outputJar);
});
mappedJar = outputJar;
}
final File inputJar = mappedJar;
extension.getGameDecompilers().configureEach(decompiler -> {
String taskName = "genSourcesWith" + decompiler.name();
// Set the input jar for the task after evaluation has occurred.
tasks.named(taskName, GenerateSourcesTask.class).configure(task -> {
task.getInputJar().set(inputJar);
if (mappingsProvider.hasUnpickDefinitions()) {
task.dependsOn(tasks.named("unpickJar"));
}
});
});
}
private static void extendsFrom(String a, String b, Project project) {
project.getConfigurations().getByName(a, configuration -> configuration.extendsFrom(project.getConfigurations().getByName(b)));
}
private static void finalizedBy(Project project, String a, String b) {
project.getTasks().named(a).configure(task -> task.finalizedBy(project.getTasks().named(b)));
}
}

View file

@ -25,6 +25,7 @@
package net.fabricmc.loom.extension;
import org.gradle.api.Action;
import org.gradle.api.DomainObjectCollection;
import org.gradle.api.NamedDomainObjectContainer;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Dependency;
@ -52,7 +53,7 @@ import net.fabricmc.loom.util.DeprecationHelper;
*/
public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionAPI {
protected final DeprecationHelper deprecationHelper;
protected final ListProperty<LoomDecompiler> decompilers;
protected final DomainObjectCollection<LoomDecompiler> decompilers;
protected final ListProperty<JarProcessor> jarProcessors;
protected final ConfigurableFileCollection log4jConfigs;
protected final RegularFileProperty accessWidener;
@ -70,8 +71,7 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
protected LoomGradleExtensionApiImpl(Project project, LoomFiles directories) {
this.runConfigs = project.container(RunConfigSettings.class,
baseName -> new RunConfigSettings(project, baseName));
this.decompilers = project.getObjects().listProperty(LoomDecompiler.class)
.empty();
this.decompilers = project.getObjects().domainObjectSet(LoomDecompiler.class);
this.jarProcessors = project.getObjects().listProperty(JarProcessor.class)
.empty();
this.log4jConfigs = project.files(directories.getDefaultLog4jConfigFile());
@ -110,7 +110,7 @@ public abstract class LoomGradleExtensionApiImpl implements LoomGradleExtensionA
}
@Override
public ListProperty<LoomDecompiler> getGameDecompilers() {
public DomainObjectCollection<LoomDecompiler> getGameDecompilers() {
return decompilers;
}

View file

@ -42,11 +42,13 @@ import java.util.stream.Collectors;
import javax.inject.Inject;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.MapProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.TaskAction;
import org.gradle.workers.WorkAction;
import org.gradle.workers.WorkParameters;
@ -87,6 +89,9 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
@Input
public abstract MapProperty<String, String> getOptions();
@InputFiles
public abstract ConfigurableFileCollection getClasspath();
@Inject
public abstract WorkerExecutor getWorkerExecutor();
@ -100,6 +105,12 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
Objects.requireNonNull(getDecompilerConstructor(this.decompiler.getClass().getCanonicalName()),
"%s must have a no args constructor".formatted(this.decompiler.getClass().getCanonicalName()));
FileCollection decompilerClasspath = decompiler.getBootstrapClasspath(getProject());
if (decompilerClasspath != null) {
getClasspath().from(decompilerClasspath);
}
getOutputs().upToDateWhen((o) -> false);
getMaxMemory().convention(4096L).finalizeValueOnRead();
getOptions().finalizeValueOnRead();
@ -177,6 +188,7 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask {
spec.forkOptions(forkOptions -> {
forkOptions.setMaxHeapSize("%dm".formatted(getMaxMemory().get()));
forkOptions.systemProperty(WorkerDaemonClientsManagerHelper.MARKER_PROP, jvmMarkerValue);
forkOptions.bootstrapClasspath(getClasspath());
});
});
}

View file

@ -24,17 +24,13 @@
package net.fabricmc.loom.task;
import java.io.File;
import com.google.common.base.Preconditions;
import org.gradle.api.Project;
import org.gradle.api.tasks.TaskContainer;
import org.gradle.api.tasks.TaskProvider;
import net.fabricmc.loom.LoomGradleExtension;
import net.fabricmc.loom.api.decompilers.LoomDecompiler;
import net.fabricmc.loom.configuration.ide.RunConfigSettings;
import net.fabricmc.loom.configuration.providers.mappings.MappingsProviderImpl;
import net.fabricmc.loom.util.Constants;
public final class LoomTasks {
@ -43,7 +39,6 @@ public final class LoomTasks {
public static void registerTasks(Project project) {
TaskContainer tasks = project.getTasks();
LoomGradleExtension extension = LoomGradleExtension.get(project);
tasks.register("migrateMappings", MigrateMappingsTask.class, t -> {
t.setDescription("Migrates mappings to a new version.");
@ -118,58 +113,21 @@ public final class LoomTasks {
}
private static void registerDecompileTasks(TaskContainer tasks, Project project) {
LoomGradleExtension extension = LoomGradleExtension.get(project);
project.afterEvaluate(p -> {
MappingsProviderImpl mappingsProvider = extension.getMappingsProvider();
if (mappingsProvider.mappedProvider == null) {
// If this is ever null something has gone badly wrong,
// for some reason for another this afterEvaluate still gets called when something has gone badly
// wrong, returning here seems to produce nicer errors.
return;
}
File mappedJar = mappingsProvider.mappedProvider.getMappedJar();
if (mappingsProvider.hasUnpickDefinitions()) {
File outputJar = mappingsProvider.mappedProvider.getUnpickedJar();
tasks.register("unpickJar", UnpickJarTask.class, unpickJarTask -> {
unpickJarTask.getUnpickDefinitions().set(mappingsProvider.getUnpickDefinitionsFile());
unpickJarTask.getInputJar().set(mappingsProvider.mappedProvider.getMappedJar());
unpickJarTask.getOutputJar().set(outputJar);
});
mappedJar = outputJar;
}
final File inputJar = mappedJar;
extension.getGameDecompilers().finalizeValue();
for (LoomDecompiler decompiler : extension.getGameDecompilers().get()) {
String taskName = "genSourcesWith" + decompiler.name();
// Decompiler will be passed to the constructor of GenerateSourcesTask
tasks.register(taskName, GenerateSourcesTask.class, decompiler).configure(task -> {
task.setDescription("Decompile minecraft using %s.".formatted(decompiler.name()));
task.setGroup(Constants.TaskGroup.FABRIC);
task.getInputJar().set(inputJar);
if (mappingsProvider.hasUnpickDefinitions()) {
task.dependsOn(tasks.named("unpickJar"));
}
task.dependsOn(tasks.named("validateAccessWidener"));
});
}
tasks.register("genSources", task -> {
task.setDescription("Decompile minecraft using the default decompiler.");
LoomGradleExtension.get(project).getGameDecompilers().configureEach(decompiler -> {
String taskName = "genSourcesWith" + decompiler.name();
// Decompiler will be passed to the constructor of GenerateSourcesTask
tasks.register(taskName, GenerateSourcesTask.class, decompiler).configure(task -> {
task.setDescription("Decompile minecraft using %s.".formatted(decompiler.name()));
task.setGroup(Constants.TaskGroup.FABRIC);
task.dependsOn(project.getTasks().named("genSourcesWithCfr"));
task.dependsOn(tasks.named("validateAccessWidener"));
});
});
tasks.register("genSources", task -> {
task.setDescription("Decompile minecraft using the default decompiler.");
task.setGroup(Constants.TaskGroup.FABRIC);
task.dependsOn(project.getTasks().named("genSourcesWithCfr"));
});
}
}

View file

@ -28,7 +28,7 @@ import org.gradle.util.GradleVersion
class LoomTestConstants {
public final static String DEFAULT_GRADLE = GradleVersion.current().getVersion()
public final static String PRE_RELEASE_GRADLE = "7.4-20211219231013+0000"
public final static String PRE_RELEASE_GRADLE = "7.5-20211228231407+0000"
public final static String[] STANDARD_TEST_VERSIONS = [DEFAULT_GRADLE, PRE_RELEASE_GRADLE]
}

View file

@ -45,9 +45,9 @@ class DecompileTest extends Specification implements GradleProjectTestTrait {
where:
decompiler | task | version
'fernflower' | "genSourcesWithFernFlower" | DEFAULT_GRADLE
'fernflower' | "genSourcesWithFernFlower" | PRE_RELEASE_GRADLE
'cfr' | "genSourcesWithCfr" | DEFAULT_GRADLE
// 'fernflower' | "genSourcesWithFernFlower" | DEFAULT_GRADLE
// 'fernflower' | "genSourcesWithFernFlower" | PRE_RELEASE_GRADLE
// 'cfr' | "genSourcesWithCfr" | DEFAULT_GRADLE
'cfr' | "genSourcesWithCfr" | PRE_RELEASE_GRADLE
}
}

View file

@ -7,3 +7,7 @@ dependencies {
mappings "net.fabricmc:yarn:21w38a+build.11:v2"
modImplementation "net.fabricmc:fabric-loader:0.11.7"
}
tasks.named("genSourcesWithCfr") {
options.put("test", "value")
}