From 754562481ddf57b51f3215f7bdfe465e2fdc45f8 Mon Sep 17 00:00:00 2001 From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> Date: Thu, 4 Apr 2024 13:53:18 -0700 Subject: [PATCH] Make patched file filtering incremental & compile against filtered jar (#237) * Make patched file filtering incremental This makes it more reasonable to compile against * Compile against the filtered jar * Add missing `$` to inner class glob patterns * Fix base path being split by collection add function --- .../paperweight/tasks/FilterPatchedFiles.kt | 161 ++++++++++++++++++ .../paperweight/tasks/FilterProjectDir.kt | 94 ---------- .../papermc/paperweight/util/project-util.kt | 4 +- 3 files changed, 163 insertions(+), 96 deletions(-) create mode 100644 paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/FilterPatchedFiles.kt delete mode 100644 paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/FilterProjectDir.kt diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/FilterPatchedFiles.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/FilterPatchedFiles.kt new file mode 100644 index 0000000..6f27895 --- /dev/null +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/FilterPatchedFiles.kt @@ -0,0 +1,161 @@ +/* + * paperweight is a Gradle plugin for the PaperMC project. + * + * Copyright (c) 2023 Kyle Wood (DenWav) + * Contributors + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 only, no later versions. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + * USA + */ + +package io.papermc.paperweight.tasks + +import io.papermc.paperweight.util.* +import java.nio.file.Files +import java.nio.file.Path +import java.util.stream.Collectors +import kotlin.io.path.* +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.tasks.InputDirectory +import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.OutputFile +import org.gradle.api.tasks.TaskAction +import org.gradle.work.ChangeType +import org.gradle.work.Incremental +import org.gradle.work.InputChanges + +abstract class FilterPatchedFiles : BaseTask() { + + @get:InputDirectory + @get:Incremental + abstract val inputSrcDir: DirectoryProperty + + @get:InputDirectory + @get:Incremental + abstract val inputResourcesDir: DirectoryProperty + + @get:InputFile + abstract val vanillaJar: RegularFileProperty + + @get:OutputFile + abstract val outputJar: RegularFileProperty + + override fun init() { + outputJar.convention(defaultOutput()) + } + + @TaskAction + fun run(changes: InputChanges) { + if (!changes.isIncremental) { + return runFull() + } + val srcAdded = changes.added(inputSrcDir) + val srcRemoved = changes.removed(inputSrcDir) + val resourceAdded = changes.added(inputResourcesDir) + val resourceRemoved = changes.removed(inputResourcesDir) + if (srcAdded.isEmpty() && srcRemoved.isEmpty() && resourceAdded.isEmpty() && resourceRemoved.isEmpty()) { + logger.info("No adds or removes, not doing work.") + didWork = false + return + } + vanillaJar.path.openZip().use { vanillaFs -> + val vanillaRoot = vanillaFs.rootDirectories.single() + outputJar.path.openZip().use { outputFs -> + val outputRoot = outputFs.rootDirectories.single() + + for (add in resourceAdded) { + if (vanillaRoot.resolve(add).exists()) { + outputRoot.resolve(add).deleteIfExists() + } + } + for (del in resourceRemoved) { + val vanilla = vanillaRoot.resolve(del) + if (vanilla.exists()) { + val out = outputRoot.resolve(del) + out.parent.createDirectories() + out.deleteIfExists() + vanilla.copyTo(out) + } + } + + for (add in srcAdded) { + val p = add.removeSuffix(".java") + ".class" + val vanilla = vanillaRoot.resolve(p) + if (vanilla.exists()) { + val outFile = outputRoot.resolve(p) + val outDir = outFile.parent + val paths = outDir.listDirectoryEntries("${vanilla.name.removeSuffix(".class")}$*.class").toMutableList() + paths.add(outFile) + paths.forEach { it.deleteIfExists() } + } + } + for (del in srcRemoved) { + val p = del.removeSuffix(".java") + ".class" + val vanillaFile = vanillaRoot.resolve(p) + if (vanillaFile.exists()) { + val paths = vanillaFile.parent.listDirectoryEntries("${vanillaFile.name.removeSuffix(".class")}$*.class").toMutableList() + paths.add(vanillaFile) + paths.forEach { + val out = outputRoot.resolve(it.relativeTo(vanillaRoot)) + out.parent.createDirectories() + out.deleteIfExists() + it.copyTo(out) + } + } + } + } + } + } + + private fun runFull() { + val srcFiles = collectFiles(inputSrcDir.path) + val resourceFiles = collectFiles(inputResourcesDir.path) + filterJar( + vanillaJar.path, + outputJar.path, + listOf() + ) { + if (!it.isRegularFile()) { + false + } else if (it.nameCount > 1) { + val path = it.subpath(0, it.nameCount - 1).resolve(it.fileName.toString().split("$")[0].removeSuffix(".class")).toString() + !srcFiles.contains("$path.java") && !resourceFiles.contains(path) + } else { + true + } + } + } + + private fun collectFiles(dir: Path): Set { + return Files.walk(dir).use { stream -> + stream.filter { it.isRegularFile() } + .map { it.relativeTo(dir).invariantSeparatorsPathString } + .collect(Collectors.toUnmodifiableSet()) + } + } + + private fun InputChanges.added(baseDir: DirectoryProperty): Set { + return getFileChanges(baseDir).filter { it.changeType == ChangeType.ADDED } + .map { it.file.toPath().relativeTo(baseDir.path).invariantSeparatorsPathString } + .toSet() + } + + private fun InputChanges.removed(baseDir: DirectoryProperty): Set { + return getFileChanges(baseDir).filter { it.changeType == ChangeType.REMOVED } + .map { it.file.toPath().relativeTo(baseDir.path).invariantSeparatorsPathString } + .toSet() + } +} diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/FilterProjectDir.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/FilterProjectDir.kt deleted file mode 100644 index 2c22216..0000000 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/FilterProjectDir.kt +++ /dev/null @@ -1,94 +0,0 @@ -/* - * paperweight is a Gradle plugin for the PaperMC project. - * - * Copyright (c) 2023 Kyle Wood (DenWav) - * Contributors - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 only, no later versions. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -package io.papermc.paperweight.tasks - -import io.papermc.paperweight.util.* -import java.nio.file.Files -import java.nio.file.Path -import java.util.stream.Collectors -import kotlin.io.path.* -import org.gradle.api.file.DirectoryProperty -import org.gradle.api.file.RegularFileProperty -import org.gradle.api.tasks.InputDirectory -import org.gradle.api.tasks.InputFile -import org.gradle.api.tasks.OutputFile -import org.gradle.api.tasks.TaskAction - -abstract class FilterProjectDir : BaseTask() { - - @get:InputDirectory - abstract val inputSrcDir: DirectoryProperty - - @get:InputDirectory - abstract val inputResourcesDir: DirectoryProperty - - @get:InputFile - abstract val vanillaJar: RegularFileProperty - - @get:OutputFile - abstract val outputJar: RegularFileProperty - - override fun init() { - outputJar.convention(defaultOutput()) - } - - @TaskAction - fun run() { - val output = outputJar.path - val target = output.resolveSibling("${output.name}.dir") - target.createDirectories() - - vanillaJar.path.openZip().use { zip -> - val srcFiles = collectFiles(inputSrcDir.path) - val resourceFiles = collectFiles(inputResourcesDir.path) - - zip.walk().use { stream -> - stream - .filter { it.isRegularFile() } - .filter { - if (it.nameCount > 1) { - val path = it.subpath(0, it.nameCount - 1).resolve(it.fileName.toString().split("$")[0].removeSuffix(".class")).toString() - !srcFiles.contains("$path.java") && !resourceFiles.contains(path) - } else { - true - } - }.forEach { f -> - val targetFile = target.resolve(f.invariantSeparatorsPathString.substring(1)) - targetFile.parent.createDirectories() - f.copyTo(targetFile) - } - } - } - - zip(target, output) - target.deleteRecursive() - } - - private fun collectFiles(dir: Path): Set { - return Files.walk(dir).use { stream -> - stream.filter { it.isRegularFile() } - .map { it.relativeTo(dir).invariantSeparatorsPathString } - .collect(Collectors.toUnmodifiableSet()) - } - } -} diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/project-util.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/project-util.kt index c719fa4..5473398 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/project-util.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/project-util.kt @@ -61,7 +61,7 @@ fun Project.setupServerProject( exportRuntimeClasspathTo(parent) @Suppress("UNUSED_VARIABLE", "KotlinRedundantDiagnosticSuppress") - val filterProjectDir by tasks.registering { + val filterPatchedFiles by tasks.registering { inputSrcDir.set(file("src/main/java")) inputResourcesDir.set(file("src/main/resources")) vanillaJar.set( @@ -82,7 +82,7 @@ fun Project.setupServerProject( layout.projectDirectory.path ) - add(create(parent.files(remappedJar))) + add(create(parent.files(filterPatchedFiles.flatMap { it.outputJar }))) } } }