diff --git a/buildSrc/src/main/java/quilt/internal/QuiltMappingsPlugin.java b/buildSrc/src/main/java/quilt/internal/QuiltMappingsPlugin.java index 96aa69d555..4c32b78a99 100644 --- a/buildSrc/src/main/java/quilt/internal/QuiltMappingsPlugin.java +++ b/buildSrc/src/main/java/quilt/internal/QuiltMappingsPlugin.java @@ -53,6 +53,7 @@ import quilt.internal.tasks.diff.DownloadTargetMappingJarTask; import quilt.internal.tasks.diff.DownloadTargetMetaFileTask; import quilt.internal.tasks.diff.ExtractTargetMappingJarTask; +import quilt.internal.tasks.diff.DiffDirectoriesTask; import quilt.internal.tasks.diff.RemapTargetMinecraftJarTask; import quilt.internal.tasks.diff.RemapTargetUnpickDefinitionsTask; import quilt.internal.tasks.diff.TargetVersionConsumingTask; @@ -845,7 +846,7 @@ public void apply(@NotNull Project project) { } ); - tasks.register( + final var decompileVineflower = tasks.register( DecompileVineflowerTask.DECOMPILE_VINEFLOWER_TASK_NAME, DecompileVineflowerTask.class, task -> { @@ -859,7 +860,7 @@ public void apply(@NotNull Project project) { insertAutoGeneratedMappings.flatMap(AddProposedMappingsTask::getOutputMappings) )); - // TODO move this once generateDiff task eliminates magic strings + // TODO move this to build/ once generate-diff.yml uses generateDiff task.getOutput().convention(projectDir.dir("namedSrc")); } ); @@ -1002,7 +1003,7 @@ public void apply(@NotNull Project project) { } ); - tasks.register( + final var decompileTargetVineflower = tasks.register( DecompileTargetVineflowerTask.DECOMPILE_TARGET_VINEFLOWER_TASK_NAME, DecompileTargetVineflowerTask.class, task -> { @@ -1017,12 +1018,25 @@ public void apply(@NotNull Project project) { .map(dest -> dest.dir("mappings").file("mappings.tiny")) )); - // TODO move this once generateDiff task eliminates magic strings - task.getOutput().convention(projectDir.dir("namedTargetSrc")); - }); + // TODO move this to build/ once generate-diff.yml uses generateDiff + task.getOutput().convention(projectDir.dir("namedTargetSrc")); + } + ); + + // TODO use this in generate-diff.yml + tasks.register( + DiffDirectoriesTask.GENERATE_DIFF_TASK_NAME, + DiffDirectoriesTask.class, + task -> { + task.getAdditionalArgs().add("-bur"); + + task.getFirst().convention(decompileTargetVineflower.flatMap(DecompileTargetVineflowerTask::getOutput)); - // TODO add generateDiff task, - // allow passing its output location on command line and pass it in generate-diff.yml + task.getSecond().convention(decompileVineflower.flatMap(DecompileVineflowerTask::getOutput)); + + task.getDest().convention(buildDir.file("target.diff")); + } + ); // sources are added in build.gradle because they're from a project source set tasks.register(SourcesJarTask.SOURCES_JAR_TASK_NAME, SourcesJarTask.class); diff --git a/buildSrc/src/main/java/quilt/internal/tasks/diff/DiffDirectoriesTask.java b/buildSrc/src/main/java/quilt/internal/tasks/diff/DiffDirectoriesTask.java new file mode 100644 index 0000000000..f81048888e --- /dev/null +++ b/buildSrc/src/main/java/quilt/internal/tasks/diff/DiffDirectoriesTask.java @@ -0,0 +1,121 @@ +package quilt.internal.tasks.diff; + +import org.gradle.api.GradleException; +import org.gradle.api.file.Directory; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.specs.Specs; +import org.gradle.api.tasks.Exec; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputDirectory; +import org.gradle.api.tasks.Optional; +import org.gradle.api.tasks.OutputFile; +import org.gradle.api.tasks.TaskAction; +import org.gradle.api.tasks.options.Option; +import quilt.internal.Constants.Groups; +import quilt.internal.tasks.MappingsTask; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static quilt.internal.util.ProviderUtil.toOptional; + +public abstract class DiffDirectoriesTask extends Exec implements MappingsTask { + public static final String GENERATE_DIFF_TASK_NAME = "generateDiff"; + + public static final String DIFF_COMMAND = "diff"; + + private static final String EXIT_VALUE_1_ERROR = + "Process 'command '" + DIFF_COMMAND + "'' finished with non-zero exit value 1"; + + @Option( + option = "args", + description = "Additional args passed to the " + DIFF_COMMAND + " command." + ) + @Optional + @Input + public abstract ListProperty getAdditionalArgs(); + + @Option( + option = "first", + description = "The first file passed to the " + DIFF_COMMAND + " command." + ) + @InputDirectory + public abstract DirectoryProperty getFirst(); + + @Option( + option = "second", + description = "The second file passed to the " + DIFF_COMMAND + " command." + ) + @InputDirectory + public abstract DirectoryProperty getSecond(); + + @Option( + option = "dest", + description = "The location to save the " + DIFF_COMMAND + " command output to." + ) + @OutputFile + public abstract RegularFileProperty getDest(); + + public DiffDirectoriesTask() { + this.setGroup(Groups.DIFF); + + this.setExecutable(DIFF_COMMAND); + + this.getOutputs().cacheIf( + "Re-enable caching because Exec has @DisableCachingByDefault", + Specs.satisfyAll() + ); + + this.getArgumentProviders().add(() -> { + // require neither directory is empty so the diff isn't just the full contents of one of them + final Directory first = this.getFirst().get(); + if (first.getAsFileTree().isEmpty()) { + throw new GradleException("first directory is empty"); + } + + final Directory second = this.getSecond().get(); + if (second.getAsFileTree().isEmpty()) { + throw new GradleException("second directory is empty"); + } + + final List args = new ArrayList<>(); + + toOptional(this.getAdditionalArgs()).ifPresent(args::addAll); + + args.add(first.getAsFile().getAbsolutePath()); + args.add(second.getAsFile().getAbsolutePath()); + + return args; + }); + } + + @Override + @TaskAction + public void exec() { + try { + final File dest = this.getDest().get().getAsFile(); + + dest.getParentFile().mkdirs(); + + dest.createNewFile(); + + this.setStandardOutput(new FileOutputStream(dest.getAbsolutePath())); + } catch (IOException e) { + throw new GradleException("Failed to access destination file", e); + } + + try { + super.exec(); + } catch (GradleException e) { + // ignore exit value 1 which just means there was a difference between the inputs + if (!e.getMessage().equals(EXIT_VALUE_1_ERROR)) { + throw new GradleException("Error executing " + DIFF_COMMAND, e); + } + } + } +}