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
This commit is contained in:
		
							parent
							
								
									2baf39ad1c
								
							
						
					
					
						commit
						4bf3d5aebe
					
				
					 15 changed files with 309 additions and 298 deletions
				
			
		|  | @ -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<Path> unmappedModsBuilt = new ArrayList<>(); | ||||
| 
 | ||||
| 	final List<LoomDecompiler> 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<MappingSet> factory) { | ||||
| 		return srcMappingCache[id] != null ? srcMappingCache[id] : (srcMappingCache[id] = factory.get()); | ||||
| 	} | ||||
|  |  | |||
|  | @ -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); | ||||
| 			} | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -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<Path> 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<Path> libraries) { | ||||
| 		this.numberOfThreads = numberOfThreads; | ||||
| 		this.javaDocs = javaDocs; | ||||
| 		this.libraries = libraries; | ||||
| 	} | ||||
| } | ||||
|  | @ -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); | ||||
| } | ||||
|  | @ -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<? extends AbstractForkedFFExecutor> 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<String, Object> 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<String, Object> options = new HashMap<String, Object>() {{ | ||||
| 				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<String> 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<ProgressLogger> loggerFactory = () -> { | ||||
|  | @ -97,8 +99,8 @@ public class FernFlowerTask extends AbstractDecompileTask implements ForkingJava | |||
| 		Map<String, ProgressLogger> 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(); | ||||
| 	} | ||||
| } | ||||
|  | @ -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. | ||||
|  * <p>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 | ||||
|  * </p> | ||||
|  */ | ||||
| public class ForkedFFExecutor { | ||||
| 	public static void main(String[] args) throws IOException { | ||||
| public abstract class AbstractForkedFFExecutor { | ||||
| 	public static void decompile(String[] args, AbstractForkedFFExecutor ffExecutor) { | ||||
| 		Map<String, Object> 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<String, Object> options, List<File> 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<String, Object> options, List<File> libraries, File input, File output, File lineMap, File mappings); | ||||
| } | ||||
|  | @ -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<? extends AbstractForkedFFExecutor> fernFlowerExecutor() { | ||||
| 		return FabricForkedFFExecutor.class; | ||||
| 	} | ||||
| } | ||||
|  | @ -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<String, Object> options, List<File> 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(); | ||||
| 	} | ||||
| } | ||||
|  | @ -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; | ||||
|  | @ -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. | ||||
|  * | ||||
|  * <p>Created by covers1624 on 11/02/19. | ||||
|  */ | ||||
| public interface ForkingJavaExecTask extends Task { | ||||
| 	default ExecResult javaexec(Action<? super JavaExecSpec> action) { | ||||
| 		ConfigurationContainer configurations = getProject().getBuildscript().getConfigurations(); | ||||
| 		DependencyHandler handler = getProject().getDependencies(); | ||||
| public class ForkingJavaExec { | ||||
| 	public static ExecResult javaexec(Project project, Action<? super JavaExecSpec> 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); | ||||
| 		}); | ||||
|  | @ -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; | ||||
|  | @ -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; | ||||
|  | @ -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; | ||||
							
								
								
									
										104
									
								
								src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java
									
									
									
									
									
										Normal file
									
								
							|  | @ -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<Path> 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(); | ||||
| 	} | ||||
| } | ||||
|  | @ -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; | ||||
| 	} | ||||
| } | ||||
		Loading…
	
		Reference in a new issue