From 4bf3d5aebe5d61892818eb32fc37d99ecda704ee Mon Sep 17 00:00:00 2001 From: Fudge Date: Mon, 1 Jun 2020 21:31:32 +0300 Subject: [PATCH] Allow specifying additional decompilers for generating sources (#213) * decompilers * cleanup * oops * weird import * public * public 2 electric boogalo * move over fabric specific * ok * move to api package --- .../fabricmc/loom/LoomGradleExtension.java | 11 ++ .../net/fabricmc/loom/LoomGradlePlugin.java | 79 +++---------- .../decompilers/DecompilationMetadata.java} | 55 ++------- .../loom/api/decompilers/LoomDecompiler.java | 40 +++++++ .../AbstractFernFlowerDecompiler.java} | 88 +++++++-------- .../fernflower/AbstractForkedFFExecutor.java} | 32 ++---- .../FabricFernFlowerDecompiler.java} | 24 ++-- .../fernflower/FabricForkedFFExecutor.java | 57 ++++++++++ .../fernflower/FernFlowerUtils.java | 2 +- .../fernflower/ForkingJavaExec.java} | 18 +-- .../fernflower/ThreadIDFFLogger.java | 2 +- .../fernflower/ThreadSafeResultSaver.java | 2 +- .../fernflower/TinyJavadocProvider.java | 2 +- .../loom/task/GenerateSourcesTask.java | 104 ++++++++++++++++++ .../loom/task/RemapLineNumbersTask.java | 91 --------------- 15 files changed, 309 insertions(+), 298 deletions(-) rename src/main/java/net/fabricmc/loom/{task/AbstractDecompileTask.java => api/decompilers/DecompilationMetadata.java} (55%) create mode 100644 src/main/java/net/fabricmc/loom/api/decompilers/LoomDecompiler.java rename src/main/java/net/fabricmc/loom/{task/fernflower/FernFlowerTask.java => decompilers/fernflower/AbstractFernFlowerDecompiler.java} (67%) rename src/main/java/net/fabricmc/loom/{task/fernflower/ForkedFFExecutor.java => decompilers/fernflower/AbstractForkedFFExecutor.java} (75%) rename src/main/java/net/fabricmc/loom/{task/fernflower/NoopFFLogger.java => decompilers/fernflower/FabricFernFlowerDecompiler.java} (74%) create mode 100644 src/main/java/net/fabricmc/loom/decompilers/fernflower/FabricForkedFFExecutor.java rename src/main/java/net/fabricmc/loom/{task => decompilers}/fernflower/FernFlowerUtils.java (97%) rename src/main/java/net/fabricmc/loom/{task/ForkingJavaExecTask.java => decompilers/fernflower/ForkingJavaExec.java} (76%) rename src/main/java/net/fabricmc/loom/{task => decompilers}/fernflower/ThreadIDFFLogger.java (98%) rename src/main/java/net/fabricmc/loom/{task => decompilers}/fernflower/ThreadSafeResultSaver.java (99%) rename src/main/java/net/fabricmc/loom/{task => decompilers}/fernflower/TinyJavadocProvider.java (98%) create mode 100644 src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java delete mode 100644 src/main/java/net/fabricmc/loom/task/RemapLineNumbersTask.java diff --git a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java index 72b3c61..f44755d 100644 --- a/src/main/java/net/fabricmc/loom/LoomGradleExtension.java +++ b/src/main/java/net/fabricmc/loom/LoomGradleExtension.java @@ -45,6 +45,7 @@ import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.Dependency; import org.gradle.api.plugins.BasePluginConvention; +import net.fabricmc.loom.api.decompilers.LoomDecompiler; import net.fabricmc.loom.processors.JarProcessorManager; import net.fabricmc.loom.providers.MappingsProvider; import net.fabricmc.loom.providers.MinecraftMappedProvider; @@ -63,6 +64,8 @@ public class LoomGradleExtension { private List unmappedModsBuilt = new ArrayList<>(); + final List decompilers = new ArrayList<>(); + //Not to be set in the build.gradle private Project project; private LoomDependencyManager dependencyManager; @@ -71,6 +74,14 @@ public class LoomGradleExtension { private MappingSet[] srcMappingCache = new MappingSet[2]; private Mercury[] srcMercuryCache = new Mercury[2]; + /** + * Loom will generate a new genSources task (with a new name, based off of {@link LoomDecompiler#name()}) + * that uses the specified decompiler instead. + */ + public void addDecompiler(LoomDecompiler decompiler) { + decompilers.add(decompiler); + } + public MappingSet getOrCreateSrcMappingCache(int id, Supplier factory) { return srcMappingCache[id] != null ? srcMappingCache[id] : (srcMappingCache[id] = factory.get()); } diff --git a/src/main/java/net/fabricmc/loom/LoomGradlePlugin.java b/src/main/java/net/fabricmc/loom/LoomGradlePlugin.java index c4a47b7..575efb7 100644 --- a/src/main/java/net/fabricmc/loom/LoomGradlePlugin.java +++ b/src/main/java/net/fabricmc/loom/LoomGradlePlugin.java @@ -25,18 +25,14 @@ package net.fabricmc.loom; import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.Locale; import org.gradle.api.Project; -import org.gradle.api.Task; import org.gradle.api.tasks.TaskContainer; +import net.fabricmc.loom.api.decompilers.LoomDecompiler; +import net.fabricmc.loom.decompilers.fernflower.FabricFernFlowerDecompiler; import net.fabricmc.loom.providers.MappingsProvider; -import net.fabricmc.loom.providers.MinecraftLibraryProvider; -import net.fabricmc.loom.task.AbstractDecompileTask; import net.fabricmc.loom.task.CleanEclipseRunsTask; import net.fabricmc.loom.task.CleanLoomBinaries; import net.fabricmc.loom.task.CleanLoomMappings; @@ -44,13 +40,12 @@ import net.fabricmc.loom.task.DownloadAssetsTask; import net.fabricmc.loom.task.GenEclipseRunsTask; import net.fabricmc.loom.task.GenIdeaProjectTask; import net.fabricmc.loom.task.GenVsCodeProjectTask; +import net.fabricmc.loom.task.GenerateSourcesTask; import net.fabricmc.loom.task.MigrateMappingsTask; import net.fabricmc.loom.task.RemapJarTask; -import net.fabricmc.loom.task.RemapLineNumbersTask; import net.fabricmc.loom.task.RemapSourcesJarTask; import net.fabricmc.loom.task.RunClientTask; import net.fabricmc.loom.task.RunServerTask; -import net.fabricmc.loom.task.fernflower.FernFlowerTask; public class LoomGradlePlugin extends AbstractPlugin { public static File getMappedByproduct(Project project, String suffix) { @@ -92,63 +87,6 @@ public class LoomGradlePlugin extends AbstractPlugin { t.setGroup("fabric"); }); - tasks.register("genSourcesDecompile", FernFlowerTask.class, t -> { - t.setDescription("Decompiles sources for the genSources task."); - t.getOutputs().upToDateWhen((o) -> false); - }); - - tasks.register("genSourcesRemapLineNumbers", RemapLineNumbersTask.class, t -> { - t.setDescription("Remaps line numbers for the genSources task."); - t.getOutputs().upToDateWhen((o) -> false); - }); - - tasks.register("genSources", t -> { - t.setDescription("Generates a human-readable version of the Minecraft source."); - t.getOutputs().upToDateWhen((o) -> false); - t.setGroup("fabric"); - }); - - project.afterEvaluate((p) -> { - AbstractDecompileTask decompileTask = (AbstractDecompileTask) p.getTasks().getByName("genSourcesDecompile"); - RemapLineNumbersTask remapLineNumbersTask = (RemapLineNumbersTask) p.getTasks().getByName("genSourcesRemapLineNumbers"); - Task genSourcesTask = p.getTasks().getByName("genSources"); - - genSourcesTask.dependsOn(remapLineNumbersTask); - remapLineNumbersTask.dependsOn(decompileTask); - - Project project = this.getProject(); - LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); - MinecraftLibraryProvider libraryProvider = extension.getMinecraftProvider().getLibraryProvider(); - MappingsProvider mappingsProvider = extension.getMappingsProvider(); - File mappedJar = mappingsProvider.mappedProvider.getMappedJar(); - File linemappedJar = getMappedByproduct(project, "-linemapped.jar"); - File sourcesJar = getMappedByproduct(project, "-sources.jar"); - File linemapFile = getMappedByproduct(project, "-sources.lmap"); - - decompileTask.setInput(mappedJar); - decompileTask.setOutput(sourcesJar); - decompileTask.setLineMapFile(linemapFile); - decompileTask.setLibraries(libraryProvider.getLibraries()); - - remapLineNumbersTask.setInput(mappedJar); - remapLineNumbersTask.setLineMapFile(linemapFile); - remapLineNumbersTask.setOutput(linemappedJar); - - Path mappedJarPath = mappedJar.toPath(); - Path linemappedJarPath = linemappedJar.toPath(); - - genSourcesTask.doLast((tt) -> { - if (Files.exists(linemappedJarPath)) { - try { - Files.deleteIfExists(mappedJarPath); - Files.copy(linemappedJarPath, mappedJarPath); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - }); - }); - tasks.register("downloadAssets", DownloadAssetsTask.class, t -> t.setDescription("Downloads required assets for Fabric.")); tasks.register("genIdeaWorkspace", GenIdeaProjectTask.class, t -> { @@ -187,5 +125,16 @@ public class LoomGradlePlugin extends AbstractPlugin { t.dependsOn("jar"); t.setGroup("fabric"); }); + + LoomGradleExtension extension = project.getExtensions().getByType(LoomGradleExtension.class); + extension.addDecompiler(new FabricFernFlowerDecompiler(project)); + + project.afterEvaluate((p) -> { + for (LoomDecompiler decompiler : extension.decompilers) { + String taskName = (decompiler instanceof FabricFernFlowerDecompiler) ? "genSources" : "genSourcesWith" + decompiler.name(); + // decompiler will be passed to the constructor of GenerateSourcesTask + tasks.register(taskName, GenerateSourcesTask.class, decompiler); + } + }); } } diff --git a/src/main/java/net/fabricmc/loom/task/AbstractDecompileTask.java b/src/main/java/net/fabricmc/loom/api/decompilers/DecompilationMetadata.java similarity index 55% rename from src/main/java/net/fabricmc/loom/task/AbstractDecompileTask.java rename to src/main/java/net/fabricmc/loom/api/decompilers/DecompilationMetadata.java index c7403a9..35dcbfa 100644 --- a/src/main/java/net/fabricmc/loom/task/AbstractDecompileTask.java +++ b/src/main/java/net/fabricmc/loom/api/decompilers/DecompilationMetadata.java @@ -22,54 +22,19 @@ * SOFTWARE. */ -package net.fabricmc.loom.task; +package net.fabricmc.loom.api.decompilers; -import java.io.File; +import java.nio.file.Path; +import java.util.Collection; -import org.gradle.api.file.FileCollection; -import org.gradle.api.tasks.InputFile; -import org.gradle.api.tasks.InputFiles; -import org.gradle.api.tasks.OutputFile; +public class DecompilationMetadata { + public final int numberOfThreads; + public final Path javaDocs; + public final Collection libraries; -public abstract class AbstractDecompileTask extends AbstractLoomTask { - private Object input; - private Object output; - private Object lineMapFile; - private Object libraries; - - @InputFile - public File getInput() { - return getProject().file(input); - } - - @OutputFile - public File getOutput() { - return getProject().file(output); - } - - @OutputFile - public File getLineMapFile() { - return getProject().file(lineMapFile); - } - - @InputFiles - public FileCollection getLibraries() { - return getProject().files(libraries); - } - - public void setInput(Object input) { - this.input = input; - } - - public void setOutput(Object output) { - this.output = output; - } - - public void setLineMapFile(Object lineMapFile) { - this.lineMapFile = lineMapFile; - } - - public void setLibraries(Object libraries) { + public DecompilationMetadata(int numberOfThreads, Path javaDocs, Collection libraries) { + this.numberOfThreads = numberOfThreads; + this.javaDocs = javaDocs; this.libraries = libraries; } } diff --git a/src/main/java/net/fabricmc/loom/api/decompilers/LoomDecompiler.java b/src/main/java/net/fabricmc/loom/api/decompilers/LoomDecompiler.java new file mode 100644 index 0000000..c19a4a8 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/api/decompilers/LoomDecompiler.java @@ -0,0 +1,40 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2016, 2017, 2018 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.api.decompilers; + +import java.nio.file.Path; + +public interface LoomDecompiler { + String name(); + + /** + * @param sourcesDestination Decompiled sources jar + * @param linemapDestination A byproduct of decompilation that lines up the compiled jar's line numbers with the decompiled + * sources jar for debugging. + * A decompiler may not produce a linemap at all. + * @param metaData Additional information that may or may not be needed while decompiling + */ + void decompile(Path compiledJar, Path sourcesDestination, Path linemapDestination, DecompilationMetadata metaData); +} diff --git a/src/main/java/net/fabricmc/loom/task/fernflower/FernFlowerTask.java b/src/main/java/net/fabricmc/loom/decompilers/fernflower/AbstractFernFlowerDecompiler.java similarity index 67% rename from src/main/java/net/fabricmc/loom/task/fernflower/FernFlowerTask.java rename to src/main/java/net/fabricmc/loom/decompilers/fernflower/AbstractFernFlowerDecompiler.java index d2881d7..71146d2 100644 --- a/src/main/java/net/fabricmc/loom/task/fernflower/FernFlowerTask.java +++ b/src/main/java/net/fabricmc/loom/decompilers/fernflower/AbstractFernFlowerDecompiler.java @@ -22,10 +22,11 @@ * SOFTWARE. */ -package net.fabricmc.loom.task.fernflower; +package net.fabricmc.loom.decompilers.fernflower; import static java.text.MessageFormat.format; +import java.nio.file.Path; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -33,58 +34,59 @@ import java.util.Map; import java.util.Stack; import java.util.function.Supplier; -import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; +import org.gradle.api.Project; import org.gradle.api.internal.project.ProjectInternal; import org.gradle.api.logging.LogLevel; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.TaskAction; import org.gradle.internal.logging.progress.ProgressLogger; import org.gradle.internal.logging.progress.ProgressLoggerFactory; import org.gradle.internal.service.ServiceRegistry; import org.gradle.process.ExecResult; +import org.jetbrains.java.decompiler.main.extern.IFernflowerPreferences; -import net.fabricmc.loom.task.AbstractDecompileTask; -import net.fabricmc.loom.task.ForkingJavaExecTask; +import net.fabricmc.loom.api.decompilers.DecompilationMetadata; +import net.fabricmc.loom.api.decompilers.LoomDecompiler; import net.fabricmc.loom.util.ConsumingOutputStream; import net.fabricmc.loom.util.OperatingSystem; -/** - * Created by covers1624 on 9/02/19. - */ -public class FernFlowerTask extends AbstractDecompileTask implements ForkingJavaExecTask { - private boolean noFork = false; - private int numThreads = Runtime.getRuntime().availableProcessors(); +public abstract class AbstractFernFlowerDecompiler implements LoomDecompiler { + private final Project project; - @TaskAction - public void doTask() throws Throwable { + protected AbstractFernFlowerDecompiler(Project project) { + this.project = project; + } + + public abstract Class fernFlowerExecutor(); + + @Override + public void decompile(Path compiledJar, Path sourcesDestination, Path linemapDestination, DecompilationMetadata metaData) { if (!OperatingSystem.is64Bit()) { - throw new UnsupportedOperationException("FernFlowerTask requires a 64bit JVM to run due to the memory requirements"); + throw new UnsupportedOperationException("FernFlower decompiler requires a 64bit JVM to run due to the memory requirements"); } - Map options = new HashMap<>(); - options.put(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES, "1"); - options.put(IFernflowerPreferences.BYTECODE_SOURCE_MAPPING, "1"); - options.put(IFernflowerPreferences.REMOVE_SYNTHETIC, "1"); - options.put(IFernflowerPreferences.LOG_LEVEL, "trace"); - options.put(IFernflowerPreferences.THREADS, getNumThreads()); - getLogging().captureStandardOutput(LogLevel.LIFECYCLE); + project.getLogging().captureStandardOutput(LogLevel.LIFECYCLE); + + Map options = new HashMap() {{ + put(IFernflowerPreferences.DECOMPILE_GENERIC_SIGNATURES, "1"); + put(IFernflowerPreferences.BYTECODE_SOURCE_MAPPING, "1"); + put(IFernflowerPreferences.REMOVE_SYNTHETIC, "1"); + put(IFernflowerPreferences.LOG_LEVEL, "trace"); + put(IFernflowerPreferences.THREADS, metaData.numberOfThreads); + }}; List args = new ArrayList<>(); options.forEach((k, v) -> args.add(format("-{0}={1}", k, v))); - args.add(getInput().getAbsolutePath()); - args.add("-o=" + getOutput().getAbsolutePath()); - - if (getLineMapFile() != null) { - args.add("-l=" + getLineMapFile().getAbsolutePath()); - } - - args.add("-m=" + getExtension().getMappingsProvider().tinyMappings.getAbsolutePath()); + args.add(absolutePathOf(compiledJar)); + args.add("-o=" + absolutePathOf(sourcesDestination)); + args.add("-l=" + absolutePathOf(linemapDestination)); + args.add("-m=" + absolutePathOf(metaData.javaDocs)); //TODO, Decompiler breaks on jemalloc, J9 module-info.class? - getLibraries().forEach(f -> args.add("-e=" + f.getAbsolutePath())); + for (Path library : metaData.libraries) { + args.add("-e=" + absolutePathOf(library)); + } - ServiceRegistry registry = ((ProjectInternal) getProject()).getServices(); + ServiceRegistry registry = ((ProjectInternal) project).getServices(); ProgressLoggerFactory factory = registry.get(ProgressLoggerFactory.class); ProgressLogger progressGroup = factory.newOperation(getClass()).setDescription("Decompile"); Supplier loggerFactory = () -> { @@ -97,8 +99,8 @@ public class FernFlowerTask extends AbstractDecompileTask implements ForkingJava Map inUseLoggers = new HashMap<>(); progressGroup.started(); - ExecResult result = javaexec(spec -> { - spec.setMain(ForkedFFExecutor.class.getName()); + ExecResult result = ForkingJavaExec.javaexec(project, spec -> { + spec.setMain(fernFlowerExecutor().getName()); spec.jvmArgs("-Xms200m", "-Xmx3G"); spec.setArgs(args); spec.setErrorOutput(System.err); @@ -145,21 +147,7 @@ public class FernFlowerTask extends AbstractDecompileTask implements ForkingJava result.assertNormalExitValue(); } - @Input - public int getNumThreads() { - return numThreads; - } - - @Input - public boolean isNoFork() { - return noFork; - } - - public void setNoFork(boolean noFork) { - this.noFork = noFork; - } - - public void setNumThreads(int numThreads) { - this.numThreads = numThreads; + private static String absolutePathOf(Path path) { + return path.toAbsolutePath().toString(); } } diff --git a/src/main/java/net/fabricmc/loom/task/fernflower/ForkedFFExecutor.java b/src/main/java/net/fabricmc/loom/decompilers/fernflower/AbstractForkedFFExecutor.java similarity index 75% rename from src/main/java/net/fabricmc/loom/task/fernflower/ForkedFFExecutor.java rename to src/main/java/net/fabricmc/loom/decompilers/fernflower/AbstractForkedFFExecutor.java index 10b5ccf..d42bf7f 100644 --- a/src/main/java/net/fabricmc/loom/task/fernflower/ForkedFFExecutor.java +++ b/src/main/java/net/fabricmc/loom/decompilers/fernflower/AbstractForkedFFExecutor.java @@ -22,31 +22,27 @@ * SOFTWARE. */ -package net.fabricmc.loom.task.fernflower; +package net.fabricmc.loom.decompilers.fernflower; import java.io.File; -import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; -import org.jetbrains.java.decompiler.main.Fernflower; -import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; -import org.jetbrains.java.decompiler.main.extern.IResultSaver; - -import net.fabricmc.fernflower.api.IFabricJavadocProvider; - /** * Entry point for Forked FernFlower task. * Takes one parameter, a single file, each line is treated as command line input. * Forces one input file. * Forces one output file using '-o=/path/to/output' * Created by covers1624 on 11/02/19. + *

Extending classes MUST have a standard "public static void main(args)". + * They may then call AbstractForkedFFExecutor#decompile for it to use the overridden AbstractForkedFFExecutor#runFF + *

*/ -public class ForkedFFExecutor { - public static void main(String[] args) throws IOException { +public abstract class AbstractForkedFFExecutor { + public static void decompile(String[] args, AbstractForkedFFExecutor ffExecutor) { Map options = new HashMap<>(); File input = null; File output = null; @@ -104,20 +100,8 @@ public class ForkedFFExecutor { Objects.requireNonNull(output, "Output not set."); Objects.requireNonNull(mappings, "Mappings not set."); - options.put(IFabricJavadocProvider.PROPERTY_NAME, new TinyJavadocProvider(mappings)); - runFF(options, libraries, input, output, lineMap); + ffExecutor.runFF(options, libraries, input, output, lineMap, mappings); } - public static void runFF(Map options, List libraries, File input, File output, File lineMap) { - IResultSaver saver = new ThreadSafeResultSaver(() -> output, () -> lineMap); - IFernflowerLogger logger = new ThreadIDFFLogger(); - Fernflower ff = new Fernflower(FernFlowerUtils::getBytecode, saver, options, logger); - - for (File library : libraries) { - ff.addLibrary(library); - } - - ff.addSource(input); - ff.decompileContext(); - } + public abstract void runFF(Map options, List libraries, File input, File output, File lineMap, File mappings); } diff --git a/src/main/java/net/fabricmc/loom/task/fernflower/NoopFFLogger.java b/src/main/java/net/fabricmc/loom/decompilers/fernflower/FabricFernFlowerDecompiler.java similarity index 74% rename from src/main/java/net/fabricmc/loom/task/fernflower/NoopFFLogger.java rename to src/main/java/net/fabricmc/loom/decompilers/fernflower/FabricFernFlowerDecompiler.java index 6e03a1c..7fc98ab 100644 --- a/src/main/java/net/fabricmc/loom/task/fernflower/NoopFFLogger.java +++ b/src/main/java/net/fabricmc/loom/decompilers/fernflower/FabricFernFlowerDecompiler.java @@ -22,18 +22,22 @@ * SOFTWARE. */ -package net.fabricmc.loom.task.fernflower; +package net.fabricmc.loom.decompilers.fernflower; -import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; +import org.gradle.api.Project; -/** - * Literally does nothing. - * Created by covers1624 on 11/02/19. - */ -public class NoopFFLogger extends IFernflowerLogger { - @Override - public void writeMessage(String message, Severity severity) { } +public class FabricFernFlowerDecompiler extends AbstractFernFlowerDecompiler { + public FabricFernFlowerDecompiler(Project project) { + super(project); + } @Override - public void writeMessage(String message, Severity severity, Throwable t) { } + public String name() { + return "FabricFlower"; // Or something else? + } + + @Override + public Class fernFlowerExecutor() { + return FabricForkedFFExecutor.class; + } } diff --git a/src/main/java/net/fabricmc/loom/decompilers/fernflower/FabricForkedFFExecutor.java b/src/main/java/net/fabricmc/loom/decompilers/fernflower/FabricForkedFFExecutor.java new file mode 100644 index 0000000..708acab --- /dev/null +++ b/src/main/java/net/fabricmc/loom/decompilers/fernflower/FabricForkedFFExecutor.java @@ -0,0 +1,57 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2016, 2017, 2018 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.decompilers.fernflower; + +import java.io.File; +import java.util.List; +import java.util.Map; + +import org.jetbrains.java.decompiler.main.Fernflower; +import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger; +import org.jetbrains.java.decompiler.main.extern.IResultSaver; + +import net.fabricmc.fernflower.api.IFabricJavadocProvider; + +public class FabricForkedFFExecutor extends AbstractForkedFFExecutor { + public static void main(String[] args) { + AbstractForkedFFExecutor.decompile(args, new FabricForkedFFExecutor()); + } + + @Override + public void runFF(Map options, List libraries, File input, File output, File lineMap, File mappings) { + options.put(IFabricJavadocProvider.PROPERTY_NAME, new TinyJavadocProvider(mappings)); + + IResultSaver saver = new ThreadSafeResultSaver(() -> output, () -> lineMap); + IFernflowerLogger logger = new ThreadIDFFLogger(); + Fernflower ff = new Fernflower(FernFlowerUtils::getBytecode, saver, options, logger); + + for (File library : libraries) { + ff.addLibrary(library); + } + + ff.addSource(input); + ff.decompileContext(); + } +} diff --git a/src/main/java/net/fabricmc/loom/task/fernflower/FernFlowerUtils.java b/src/main/java/net/fabricmc/loom/decompilers/fernflower/FernFlowerUtils.java similarity index 97% rename from src/main/java/net/fabricmc/loom/task/fernflower/FernFlowerUtils.java rename to src/main/java/net/fabricmc/loom/decompilers/fernflower/FernFlowerUtils.java index 69c0e70..2f999b3 100644 --- a/src/main/java/net/fabricmc/loom/task/fernflower/FernFlowerUtils.java +++ b/src/main/java/net/fabricmc/loom/decompilers/fernflower/FernFlowerUtils.java @@ -22,7 +22,7 @@ * SOFTWARE. */ -package net.fabricmc.loom.task.fernflower; +package net.fabricmc.loom.decompilers.fernflower; import java.io.File; import java.io.IOException; diff --git a/src/main/java/net/fabricmc/loom/task/ForkingJavaExecTask.java b/src/main/java/net/fabricmc/loom/decompilers/fernflower/ForkingJavaExec.java similarity index 76% rename from src/main/java/net/fabricmc/loom/task/ForkingJavaExecTask.java rename to src/main/java/net/fabricmc/loom/decompilers/fernflower/ForkingJavaExec.java index ab5619a..8b5f5f6 100644 --- a/src/main/java/net/fabricmc/loom/task/ForkingJavaExecTask.java +++ b/src/main/java/net/fabricmc/loom/decompilers/fernflower/ForkingJavaExec.java @@ -22,10 +22,10 @@ * SOFTWARE. */ -package net.fabricmc.loom.task; +package net.fabricmc.loom.decompilers.fernflower; import org.gradle.api.Action; -import org.gradle.api.Task; +import org.gradle.api.Project; import org.gradle.api.artifacts.ConfigurationContainer; import org.gradle.api.artifacts.dsl.DependencyHandler; import org.gradle.api.file.FileCollection; @@ -33,19 +33,19 @@ import org.gradle.process.ExecResult; import org.gradle.process.JavaExecSpec; /** - * Simple trait like interface for a Task that wishes to execute a java process + * Simple utility class for a Task that wishes to execute a java process * with the classpath of the gradle plugin plus groovy. * *

Created by covers1624 on 11/02/19. */ -public interface ForkingJavaExecTask extends Task { - default ExecResult javaexec(Action action) { - ConfigurationContainer configurations = getProject().getBuildscript().getConfigurations(); - DependencyHandler handler = getProject().getDependencies(); +public class ForkingJavaExec { + public static ExecResult javaexec(Project project, Action action) { + ConfigurationContainer configurations = project.getBuildscript().getConfigurations(); + DependencyHandler handler = project.getDependencies(); FileCollection classpath = configurations.getByName("classpath")// - .plus(configurations.detachedConfiguration(handler.localGroovy())); + .plus(configurations.detachedConfiguration(handler.localGroovy())); - return getProject().javaexec(spec -> { + return project.javaexec(spec -> { spec.classpath(classpath); action.execute(spec); }); diff --git a/src/main/java/net/fabricmc/loom/task/fernflower/ThreadIDFFLogger.java b/src/main/java/net/fabricmc/loom/decompilers/fernflower/ThreadIDFFLogger.java similarity index 98% rename from src/main/java/net/fabricmc/loom/task/fernflower/ThreadIDFFLogger.java rename to src/main/java/net/fabricmc/loom/decompilers/fernflower/ThreadIDFFLogger.java index 0d69a4b..fac5a79 100644 --- a/src/main/java/net/fabricmc/loom/task/fernflower/ThreadIDFFLogger.java +++ b/src/main/java/net/fabricmc/loom/decompilers/fernflower/ThreadIDFFLogger.java @@ -22,7 +22,7 @@ * SOFTWARE. */ -package net.fabricmc.loom.task.fernflower; +package net.fabricmc.loom.decompilers.fernflower; import java.io.PrintStream; import java.text.MessageFormat; diff --git a/src/main/java/net/fabricmc/loom/task/fernflower/ThreadSafeResultSaver.java b/src/main/java/net/fabricmc/loom/decompilers/fernflower/ThreadSafeResultSaver.java similarity index 99% rename from src/main/java/net/fabricmc/loom/task/fernflower/ThreadSafeResultSaver.java rename to src/main/java/net/fabricmc/loom/decompilers/fernflower/ThreadSafeResultSaver.java index 87a8d21..6659874 100644 --- a/src/main/java/net/fabricmc/loom/task/fernflower/ThreadSafeResultSaver.java +++ b/src/main/java/net/fabricmc/loom/decompilers/fernflower/ThreadSafeResultSaver.java @@ -22,7 +22,7 @@ * SOFTWARE. */ -package net.fabricmc.loom.task.fernflower; +package net.fabricmc.loom.decompilers.fernflower; import java.io.File; import java.io.FileOutputStream; diff --git a/src/main/java/net/fabricmc/loom/task/fernflower/TinyJavadocProvider.java b/src/main/java/net/fabricmc/loom/decompilers/fernflower/TinyJavadocProvider.java similarity index 98% rename from src/main/java/net/fabricmc/loom/task/fernflower/TinyJavadocProvider.java rename to src/main/java/net/fabricmc/loom/decompilers/fernflower/TinyJavadocProvider.java index 0e49d01..15cf3bf 100644 --- a/src/main/java/net/fabricmc/loom/task/fernflower/TinyJavadocProvider.java +++ b/src/main/java/net/fabricmc/loom/decompilers/fernflower/TinyJavadocProvider.java @@ -22,7 +22,7 @@ * SOFTWARE. */ -package net.fabricmc.loom.task.fernflower; +package net.fabricmc.loom.decompilers.fernflower; import java.io.BufferedReader; import java.io.File; diff --git a/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java b/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java new file mode 100644 index 0000000..8f449d4 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java @@ -0,0 +1,104 @@ +/* + * This file is part of fabric-loom, licensed under the MIT License (MIT). + * + * Copyright (c) 2016, 2017, 2018 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; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.Collection; +import java.util.stream.Collectors; + +import javax.inject.Inject; + +import org.gradle.api.tasks.TaskAction; + +import net.fabricmc.loom.LoomGradlePlugin; +import net.fabricmc.loom.api.decompilers.DecompilationMetadata; +import net.fabricmc.loom.api.decompilers.LoomDecompiler; +import net.fabricmc.loom.util.LineNumberRemapper; +import net.fabricmc.loom.util.progress.ProgressLogger; +import net.fabricmc.stitch.util.StitchUtil; + +public class GenerateSourcesTask extends AbstractLoomTask { + public final LoomDecompiler decompiler; + + @Inject + public GenerateSourcesTask(LoomDecompiler decompiler) { + this.decompiler = decompiler; + + setGroup("fabric"); + getOutputs().upToDateWhen((o) -> false); + } + + @TaskAction + public void doTask() throws Throwable { + int threads = Runtime.getRuntime().availableProcessors(); + Path javaDocs = getExtension().getMappingsProvider().tinyMappings.toPath(); + Collection libraries = getExtension().getMinecraftProvider().getLibraryProvider().getLibraries() + .stream().map(File::toPath).collect(Collectors.toSet()); + + DecompilationMetadata metadata = new DecompilationMetadata(threads, javaDocs, libraries); + Path compiledJar = getExtension().getMappingsProvider().mappedProvider.getMappedJar().toPath(); + Path sourcesDestination = LoomGradlePlugin.getMappedByproduct(getProject(), "-sources.jar").toPath(); + Path linemap = LoomGradlePlugin.getMappedByproduct(getProject(), "-sources.lmap").toPath(); + decompiler.decompile(compiledJar, sourcesDestination, linemap, metadata); + + if (Files.exists(linemap)) { + Path linemappedJarDestination = LoomGradlePlugin.getMappedByproduct(getProject(), "-linemapped.jar").toPath(); + + remapLineNumbers(compiledJar, linemap, linemappedJarDestination); + + // In order for IDEs to recognize the new line mappings, we need to overwrite the existing compiled jar + // with the linemapped one. In the name of not destroying the existing jar, we will copy it to somewhere else. + Path unlinemappedJar = LoomGradlePlugin.getMappedByproduct(getProject(), "-unlinemapped.jar").toPath(); + + // The second time genSources is ran, we want to keep the existing unlinemapped jar. + if (!Files.exists(unlinemappedJar)) { + Files.copy(compiledJar, unlinemappedJar); + } + + Files.copy(linemappedJarDestination, compiledJar, StandardCopyOption.REPLACE_EXISTING); + Files.delete(linemappedJarDestination); + } + } + + private void remapLineNumbers(Path oldCompiledJar, Path linemap, Path linemappedJarDestination) throws IOException { + getProject().getLogger().info(":adjusting line numbers"); + LineNumberRemapper remapper = new LineNumberRemapper(); + remapper.readMappings(linemap.toFile()); + + ProgressLogger progressLogger = net.fabricmc.loom.util.progress.ProgressLogger.getProgressFactory(getProject(), getClass().getName()); + progressLogger.start("Adjusting line numbers", "linemap"); + + try (StitchUtil.FileSystemDelegate inFs = StitchUtil.getJarFileSystem(oldCompiledJar.toFile(), true); + StitchUtil.FileSystemDelegate outFs = StitchUtil.getJarFileSystem(linemappedJarDestination.toFile(), true)) { + remapper.process(progressLogger, inFs.get().getPath("/"), outFs.get().getPath("/")); + } + + progressLogger.completed(); + } +} diff --git a/src/main/java/net/fabricmc/loom/task/RemapLineNumbersTask.java b/src/main/java/net/fabricmc/loom/task/RemapLineNumbersTask.java deleted file mode 100644 index e229de1..0000000 --- a/src/main/java/net/fabricmc/loom/task/RemapLineNumbersTask.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * This file is part of fabric-loom, licensed under the MIT License (MIT). - * - * Copyright (c) 2016, 2017, 2018 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; - -import java.io.File; -import java.io.IOException; - -import org.gradle.api.Project; -import org.gradle.api.tasks.InputFile; -import org.gradle.api.tasks.OutputFile; -import org.gradle.api.tasks.TaskAction; - -import net.fabricmc.loom.task.fernflower.FernFlowerTask; -import net.fabricmc.loom.util.LineNumberRemapper; -import net.fabricmc.loom.util.progress.ProgressLogger; -import net.fabricmc.stitch.util.StitchUtil; - -public class RemapLineNumbersTask extends AbstractLoomTask { - private Object input; - private Object output; - private Object lineMapFile; - - @TaskAction - public void doTask() throws Throwable { - Project project = getProject(); - - project.getLogger().info(":adjusting line numbers"); - LineNumberRemapper remapper = new LineNumberRemapper(); - remapper.readMappings(getLineMapFile()); - - ProgressLogger progressLogger = ProgressLogger.getProgressFactory(project, FernFlowerTask.class.getName()); - progressLogger.start("Adjusting line numbers", "linemap"); - - try (StitchUtil.FileSystemDelegate inFs = StitchUtil.getJarFileSystem(getInput(), true); StitchUtil.FileSystemDelegate outFs = StitchUtil.getJarFileSystem(getOutput(), true)) { - remapper.process(progressLogger, inFs.get().getPath("/"), outFs.get().getPath("/")); - } catch (IOException e) { - throw new RuntimeException(e); - } - - progressLogger.completed(); - } - - @InputFile - public File getInput() { - return getProject().file(input); - } - - @InputFile - public File getLineMapFile() { - return getProject().file(lineMapFile); - } - - @OutputFile - public File getOutput() { - return getProject().file(output); - } - - public void setInput(Object input) { - this.input = input; - } - - public void setLineMapFile(Object lineMapFile) { - this.lineMapFile = lineMapFile; - } - - public void setOutput(Object output) { - this.output = output; - } -}