diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/ForkConfig.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/ForkConfig.kt index 176352ca0..5f37079e0 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/ForkConfig.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/ForkConfig.kt @@ -45,7 +45,7 @@ abstract class ForkConfig @Inject constructor( return configName } - val rootDirectory: DirectoryProperty = objects.directoryProperty().convention(project.rootProject.layout.projectDirectory).finalizedOnRead() + val rootDirectory: DirectoryProperty = objects.directoryProperty().convention(project.rootProject.layout.projectDirectory) val serverDirectory: DirectoryProperty = objects.dirFrom(rootDirectory, providers.provider { "$name-server" }) val serverPatchesDir: DirectoryProperty = objects.dirFrom(serverDirectory, "minecraft-patches") val rejectsDir: DirectoryProperty = objects.dirFrom(serverPatchesDir, "rejected") diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/CoreTasks.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/CoreTasks.kt index 119f9aa41..bf3472bd9 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/CoreTasks.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/CoreTasks.kt @@ -24,12 +24,15 @@ package io.papermc.paperweight.core.taskcontainers import io.papermc.paperweight.PaperweightException import io.papermc.paperweight.core.extension.ForkConfig +import io.papermc.paperweight.core.tasks.CheckoutRepo import io.papermc.paperweight.core.tasks.ExtractMinecraftSources import io.papermc.paperweight.core.tasks.ImportLibraryFiles import io.papermc.paperweight.core.tasks.IndexLibraryFiles +import io.papermc.paperweight.core.tasks.RunNestedBuild import io.papermc.paperweight.core.tasks.SetupMinecraftSources import io.papermc.paperweight.core.tasks.SetupPaperScript import io.papermc.paperweight.core.util.coreExt +import io.papermc.paperweight.patcher.extension.PaperweightPatcherExtension import io.papermc.paperweight.tasks.* import io.papermc.paperweight.tasks.mache.DecompileJar import io.papermc.paperweight.tasks.mache.RunCodebook @@ -38,7 +41,9 @@ import io.papermc.paperweight.util.constants.* import io.papermc.paperweight.util.data.mache.* import java.nio.file.Files import org.gradle.api.Project +import org.gradle.api.file.Directory import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider import org.gradle.api.tasks.TaskContainer import org.gradle.kotlin.dsl.* @@ -144,18 +149,29 @@ class CoreTasks( setupPatchingTasks() } + private fun upstreamRootDirectory(name: String): Provider = with(project.rootProject) { + val isNestedUpstream = extensions.findByType()?.upstreams?.findByName(name)?.applyUpstreamNested?.orNull == true + if (isNestedUpstream) { + val applyUpstreamTask = tasks.namedOrNull("applyUpstream") + if (applyUpstreamTask != null) return applyUpstreamTask.flatMap { it.outputDir } + } + + return tasks.namedOrNull("checkout${name.capitalized()}Repo")?.flatMap { it.outputDir } + ?: project.upstreamsDirectory().map { it.dir(name) } + } + private fun setupPatchingTasks() { val hasFork = project.coreExt.forks.isNotEmpty() if (hasFork) { project.coreExt.paper.rootDirectory.set( - project.upstreamsDirectory().map { it.dir("paper") } + upstreamRootDirectory("paper") ) project.coreExt.forks.forEach { fork -> val activeFork = project.coreExt.activeFork.get().name == fork.name if (!activeFork) { fork.rootDirectory.set( - project.upstreamsDirectory().map { it.dir(fork.name) } + upstreamRootDirectory(fork.name) ) } } diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/MinecraftPatchingTasks.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/MinecraftPatchingTasks.kt index 8de9acb5a..0e7e56f6a 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/MinecraftPatchingTasks.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/MinecraftPatchingTasks.kt @@ -64,6 +64,8 @@ class MinecraftPatchingTasks( private val outputSrcFile: Path = outputRoot.resolve("file/src/minecraft/java"), private val tasks: TaskContainer = project.tasks ) { + private val gitMutationLockService = project.gitMutationLockService + private val taskGroup = if (readOnly) "upstream minecraft patching" else "minecraft patching" private fun Task.group() { group = taskGroup @@ -89,10 +91,16 @@ class MinecraftPatchingTasks( val applySourcePatches = tasks.register("apply${namePart}SourcePatches") { configureApplyFilePatches() + if (!readOnly) { + usesService(gitMutationLockService) + } } val applySourcePatchesFuzzy = tasks.register("apply${namePart}SourcePatchesFuzzy") { configureApplyFilePatches() + if (!readOnly) { + usesService(gitMutationLockService) + } } val applyResourcePatches = tasks.register("apply${namePart}ResourcePatches") { @@ -103,6 +111,9 @@ class MinecraftPatchingTasks( output.set(outputResources) patches.set(resourcePatchDir.fileExists()) // TODO rejects? + if (!readOnly) { + usesService(gitMutationLockService) + } gitFilePatches.set(this@MinecraftPatchingTasks.gitFilePatches) identifier = configName } @@ -120,6 +131,8 @@ class MinecraftPatchingTasks( if (readOnly) { base.set(applySourcePatches.flatMap { it.output }) + } else { + usesService(gitMutationLockService) } repo.set(outputSrc) patches.set(featurePatchDir.fileExists()) @@ -202,6 +215,7 @@ class MinecraftPatchingTasks( val rebuildSourcePatches = tasks.register(rebuildSourcePatchesName) { group() description = "Rebuilds $configName file patches to the Minecraft sources" + usesService(gitMutationLockService) base.set(baseSources) input.set(outputSrc) @@ -217,6 +231,7 @@ class MinecraftPatchingTasks( val rebuildResourcePatches = tasks.register(rebuildResourcePatchesName) { group() description = "Rebuilds $configName file patches to the Minecraft resources" + usesService(gitMutationLockService) base.set(baseResources) input.set(outputResources) @@ -234,6 +249,7 @@ class MinecraftPatchingTasks( group() description = "Rebuilds all $configName feature patches to the Minecraft sources" dependsOn(rebuildFilePatches) + usesService(gitMutationLockService) inputDir.set(outputSrc) patchDir.set(featurePatchDir) @@ -250,6 +266,7 @@ class MinecraftPatchingTasks( val fixupSourcePatches = tasks.register("fixup${namePart}SourcePatches") { group() description = "Puts the currently tracked source changes into the $configName Minecraft sources file patches commit" + usesService(gitMutationLockService) repo.set(outputSrc) upstream.set("upstream/main") @@ -258,6 +275,7 @@ class MinecraftPatchingTasks( val fixupResourcePatches = tasks.register("fixup${namePart}ResourcePatches") { group() description = "Puts the currently tracked resource changes into the $configName Minecraft resources file patches commit" + usesService(gitMutationLockService) repo.set(outputResources) upstream.set("upstream/main") @@ -267,6 +285,7 @@ class MinecraftPatchingTasks( configureApplyFilePatches() description = "Applies $configName file patches to the Minecraft sources as Git patches, moving any failed patches to the rejects dir. " + "Useful when updating to a new Minecraft version." + usesService(gitMutationLockService) gitFilePatches = true moveFailedGitPatchesToRejects = true } diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/PatchingTasks.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/PatchingTasks.kt index d9cf03739..ea8ee7afc 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/PatchingTasks.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/PatchingTasks.kt @@ -51,10 +51,11 @@ class PatchingTasks( private val baseDir: Provider, private val gitFilePatches: Provider, private val filterPatches: Provider, - private val outputDir: Path, + private val outputDir: DirectoryProperty, private val tasks: TaskContainer = project.tasks, ) { private val namePart: String = if (readOnly) "${forkName.capitalized()}${patchSetName.capitalized()}" else patchSetName.capitalized() + private val gitMutationLockService = project.gitMutationLockService private fun ApplyFilePatches.configureApplyFilePatches() { group = taskGroup @@ -75,10 +76,16 @@ class PatchingTasks( val applyFilePatches = tasks.register("apply${namePart}FilePatches") { configureApplyFilePatches() + if (!readOnly) { + usesService(gitMutationLockService) + } } val applyFilePatchesFuzzy = tasks.register("apply${namePart}FilePatchesFuzzy") { configureApplyFilePatches() + if (!readOnly) { + usesService(gitMutationLockService) + } } val applyFeaturePatches = tasks.register("apply${namePart}FeaturePatches") { @@ -89,6 +96,8 @@ class PatchingTasks( repo.set(outputDir) if (readOnly) { base.set(applyFilePatches.flatMap { it.output }) + } else { + usesService(gitMutationLockService) } patches.set(featurePatchDir.fileExists()) } @@ -124,6 +133,7 @@ class PatchingTasks( val rebuildFilePatches = tasks.register(rebuildFilePatchesName) { group = taskGroup description = "Rebuilds $patchSetName file patches" + usesService(gitMutationLockService) base.set(baseDir) input.set(outputDir) @@ -134,6 +144,7 @@ class PatchingTasks( val fixupFilePatches = tasks.register(fixupFilePatchesName) { group = taskGroup description = "Puts the currently tracked source changes into the $patchSetName file patches commit" + usesService(gitMutationLockService) repo.set(outputDir) upstream.set("base") @@ -143,6 +154,7 @@ class PatchingTasks( group = taskGroup description = "Rebuilds $patchSetName feature patches" dependsOn(rebuildFilePatches) + usesService(gitMutationLockService) inputDir.set(outputDir) patchDir.set(featurePatchDir) @@ -160,6 +172,7 @@ class PatchingTasks( configureApplyFilePatches() description = "Applies $patchSetName file patches as Git patches, moving any failed patches to the rejects dir. " + "Useful when updating to a new Minecraft version." + usesService(gitMutationLockService) gitFilePatches = true moveFailedGitPatchesToRejects = true } diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/UpstreamConfigTasks.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/UpstreamConfigTasks.kt index ab22724d8..eb7f02f9b 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/UpstreamConfigTasks.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/UpstreamConfigTasks.kt @@ -29,7 +29,6 @@ import io.papermc.paperweight.core.tasks.RunNestedBuild import io.papermc.paperweight.core.tasks.patching.ApplySingleFilePatches import io.papermc.paperweight.core.tasks.patching.RebuildSingleFilePatches import io.papermc.paperweight.util.* -import kotlin.io.path.* import org.gradle.api.Project import org.gradle.api.file.Directory import org.gradle.api.provider.Provider @@ -48,10 +47,17 @@ class UpstreamConfigTasks( private val setupUpstream: TaskProvider?, private val upstreamTasks: UpstreamConfigTasks?, ) { + private fun upstreamBaseDir(): Provider = + if (upstreamCfg.applyUpstreamNested.get()) { + setupUpstream?.flatMap { it.outputDir } ?: upstreamDir + } else { + upstreamDir + } + private fun ApplySingleFilePatches.configureApplySingleFilePatches() { group = taskGroup description = "Applies all ${upstreamCfg.name} single-file patches" - upstream.set(upstreamDir) + upstream.set(upstreamBaseDir()) val patches = upstreamCfg.singleFilePatchSets.map { it.map { cfg -> ApplySingleFilePatches.Patch.patch(target.objects, upstream) { @@ -89,14 +95,14 @@ class UpstreamConfigTasks( target.tasks.register("rebuild${upstreamCfg.name.capitalized()}SingleFilePatches") { group = taskGroup description = "Rebuilds all ${upstreamCfg.name} single-file patches" - upstream.set(upstreamDir) + val upstream = objects.directoryProperty().convention(upstreamBaseDir()) val patches = upstreamCfg.singleFilePatchSets.map { it.map { cfg -> - val p = objects.newInstance() - p.path = cfg.path - p.patchFile = cfg.patchFile - p.outputFile = cfg.outputFile - p + RebuildSingleFilePatches.Patch.patch(objects, upstream) { + path = cfg.path + patchFile = cfg.patchFile + outputFile = cfg.outputFile + } } } this.patches.set(patches) @@ -130,7 +136,7 @@ class UpstreamConfigTasks( base, gitFilePatches, filterPatches, - cfg.outputDir.path, + cfg.outputDir, ) } @@ -146,7 +152,7 @@ class UpstreamConfigTasks( val input = patchingTasksForDir.applyFeaturePatches.flatMap { it.repo } inputDir.set(input) } else { - inputDir.set(upstreamDir.flatMap { it.dir(cfg.upstreamPath) }) + inputDir.set(upstreamBaseDir().flatMap { it.dir(cfg.upstreamPath) }) } excludes.set(cfg.excludes) setupUpstream?.let { dependsOn(it) } @@ -158,8 +164,9 @@ class UpstreamConfigTasks( val task = target.tasks.register( "filter${cfg.name.capitalized()}From${upstreamCfg.name.capitalized()}" ) { - inputDir.set(upstreamDir.flatMap { it.dir(cfg.upstreamPath) }) - gitDir.set(upstreamDir.map { it.dir(".git") }) + val upstreamBase = upstreamBaseDir() + inputDir.set(upstreamBase.flatMap { it.dir(cfg.upstreamPath) }) + gitDir.set(upstreamBase.map { it.dir(".git") }) excludes.set(cfg.excludes) } return task.flatMap { it.outputDir } diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/RunNestedBuild.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/RunNestedBuild.kt index 71a75ee27..465232454 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/RunNestedBuild.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/RunNestedBuild.kt @@ -35,6 +35,7 @@ import org.gradle.api.provider.SetProperty import org.gradle.api.tasks.Input import org.gradle.api.tasks.InputDirectory import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.UntrackedTask import org.gradle.internal.build.NestedRootBuildRunner @@ -49,12 +50,16 @@ abstract class RunNestedBuild : BaseTask() { @get:InputDirectory abstract val projectDir: DirectoryProperty + @get:OutputDirectory + abstract val outputDir: DirectoryProperty + @get:Internal abstract val workDir: DirectoryProperty override fun init() { super.init() workDir.convention(project.upstreamsDirectory()) + outputDir.convention(projectDir) } @TaskAction diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/RebuildSingleFilePatches.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/RebuildSingleFilePatches.kt index 45cd14d5b..0dd41cf07 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/RebuildSingleFilePatches.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/RebuildSingleFilePatches.kt @@ -27,30 +27,47 @@ import codechicken.diffpatch.util.LogLevel import io.papermc.paperweight.tasks.* import io.papermc.paperweight.util.* import java.io.PrintStream +import javax.inject.Inject import kotlin.io.path.* +import org.gradle.api.Action import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.RegularFileProperty +import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputDirectory import org.gradle.api.tasks.InputFile import org.gradle.api.tasks.Nested import org.gradle.api.tasks.OutputFile import org.gradle.api.tasks.TaskAction +import org.gradle.kotlin.dsl.* abstract class RebuildSingleFilePatches : BaseTask() { - - @get:InputDirectory - abstract val upstream: DirectoryProperty - @get:Nested abstract val patches: ListProperty - abstract class Patch { + abstract class Patch @Inject constructor( + objects: ObjectFactory, + upstream: DirectoryProperty, + ) { + companion object { + fun patch( + objects: ObjectFactory, + upstream: DirectoryProperty, + op: Action + ): Patch { + val patch = objects.newInstance(upstream) + op.execute(patch) + return patch + } + } + @get:Input abstract val path: Property + @get:InputFile + val upstreamFile: RegularFileProperty = objects.fileProperty().convention(upstream.file(path)) + @get:InputFile abstract val outputFile: RegularFileProperty @@ -73,7 +90,7 @@ abstract class RebuildSingleFilePatches : BaseTask() { tmpPatch.deleteRecursive() val baseFile = tmpA.resolve(patch.path.get()).createParentDirectories() - upstream.path.resolve(patch.path.get()).copyTo(baseFile, true) + patch.upstreamFile.path.copyTo(baseFile, true) val patchedFile = tmpB.resolve(patch.path.get()).createParentDirectories() patch.outputFile.path.copyTo(patchedFile, true) diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patchroulette/PatchRouletteTasks.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patchroulette/PatchRouletteTasks.kt index 7d3ad7ffb..2cfa064b1 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patchroulette/PatchRouletteTasks.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patchroulette/PatchRouletteTasks.kt @@ -54,6 +54,7 @@ class PatchRouletteTasks( minecraftVersion = minecraftVer patchDir = patchDirectory targetDir = targetDirectory + usesService(target.gitMutationLockService) config.pathProvider( minecraftVer.map { layout.cache.resolve(PATCH_ROULETTE_CONFIG_DIR).resolve("$namePrefix-$it.json") diff --git a/paperweight-core/src/test/kotlin/io/papermc/paperweight/FunctionalTest.kt b/paperweight-core/src/test/kotlin/io/papermc/paperweight/FunctionalTest.kt index a7ba0edc3..019d7f92e 100644 --- a/paperweight-core/src/test/kotlin/io/papermc/paperweight/FunctionalTest.kt +++ b/paperweight-core/src/test/kotlin/io/papermc/paperweight/FunctionalTest.kt @@ -27,8 +27,6 @@ import java.net.URL import java.nio.file.Path import java.nio.file.Paths import kotlin.io.path.* -import kotlin.io.path.readText -import kotlin.io.path.writeText import kotlin.test.Test import kotlin.test.assertContains import kotlin.test.assertEquals @@ -102,7 +100,7 @@ class FunctionalTest { Git(tempDir.resolve("test-server/src/minecraft/java")).let { git -> git("add", ".").executeSilently() git("commit", "--fixup", "file").executeSilently() - git("rebase", "--autosquash", "upstream/main").executeSilently() + git.withEnv(mapOf("GIT_SEQUENCE_EDITOR" to ":"))("rebase", "-i", "--autosquash", "upstream/main").executeSilently() } println("\nrunning rebuildPatches again\n") @@ -181,6 +179,95 @@ class FunctionalTest { assertEquals(result.task(":test-server:applyPatches")?.outcome, TaskOutcome.SUCCESS) } + @Test + fun `checkout task output is wired for inactive fork roots`(@TempDir(cleanup = CleanupMode.ON_SUCCESS) tempDir: Path) { + println("running in $tempDir") + setupMache("fake_mache", tempDir.resolve("mache.zip")) + setupMojang("fake_mojang", tempDir.resolve("fake_mojang")) + + val project = tempDir.copyProject("functional_patcher_fork") + val upstreamDir = tempDir.resolve("forkOfPaper-upstream") + Path("src/test/resources/functional_patcher_fork_upstream").copyRecursivelyTo(upstreamDir) + Git(upstreamDir).let { git -> + git("init").executeSilently() + git("config", "user.email", "test@example.com").executeSilently() + git("config", "user.name", "Test User").executeSilently() + git("add", ".").executeSilently() + git("commit", "-m", "Initial upstream").executeSilently() + } + + val result = project.gradleRunner() + .withArguments( + "checkoutForkOfPaperRepo", + ":forkOfFork-server:collectForkOfPaperATsFromPatches", + ":forkOfFork-server:filterForkOfPaperServerFromForkOfPaper", + "--stacktrace", + ) + .withDebug(debug) + .build() + + assertEquals( + expected = TaskOutcome.SUCCESS, + actual = result.task(":checkoutForkOfPaperRepo")?.outcome, + ) + assertEquals( + expected = TaskOutcome.SUCCESS, + actual = result.task(":forkOfFork-server:collectForkOfPaperATsFromPatches")?.outcome, + ) + assertEquals( + expected = TaskOutcome.SUCCESS, + actual = result.task(":forkOfFork-server:filterForkOfPaperServerFromForkOfPaper")?.outcome, + ) + assertEquals( + expected = "public net/minecraft/server/Something exampleField", + actual = project.resolve( + "forkOfFork-server/.gradle/caches/paperweight/taskCache/collectForkOfPaperATsFromPatches.at" + ).readText().trimEnd(), + ) + assertEquals( + expected = "\"fork of paper\" upstream repo", + actual = project.resolve( + "forkOfFork-server/.gradle/caches/paperweight/taskCache/filterForkOfPaperServerFromForkOfPaper/README.md" + ).readText().trimEnd(), + ) + } + + @Test + fun `rebuild single file patches only track the files they read`(@TempDir(cleanup = CleanupMode.ON_SUCCESS) tempDir: Path) { + println("running in $tempDir") + setupMache("fake_mache", tempDir.resolve("mache.zip")) + setupMojang("fake_mojang", tempDir.resolve("fake_mojang")) + + val project = tempDir.copyProject("functional_patcher_fork") + val upstreamDir = tempDir.resolve("forkOfPaper-upstream") + Path("src/test/resources/functional_patcher_fork_upstream").copyRecursivelyTo(upstreamDir) + Git(upstreamDir).let { git -> + git("init").executeSilently() + git("config", "user.email", "test@example.com").executeSilently() + git("config", "user.name", "Test User").executeSilently() + git("add", ".").executeSilently() + git("commit", "-m", "Initial upstream").executeSilently() + } + + val result = project.gradleRunner() + .withArguments( + "rebuildForkOfPaperSingleFilePatches", + "writeForkOfPaperNestedOutput", + "--stacktrace", + ) + .withDebug(debug) + .build() + + assertEquals( + expected = TaskOutcome.SUCCESS, + actual = result.task(":rebuildForkOfPaperSingleFilePatches")?.outcome, + ) + assertEquals( + expected = TaskOutcome.SUCCESS, + actual = result.task(":writeForkOfPaperNestedOutput")?.outcome, + ) + } + fun setupMache(macheName: String, target: Path) { val macheDir = Paths.get("src/test/resources/$macheName") zip(macheDir, target) diff --git a/paperweight-core/src/test/kotlin/io/papermc/paperweight/core/taskcontainers/GitMutationLockRegistrationTest.kt b/paperweight-core/src/test/kotlin/io/papermc/paperweight/core/taskcontainers/GitMutationLockRegistrationTest.kt new file mode 100644 index 000000000..f01248097 --- /dev/null +++ b/paperweight-core/src/test/kotlin/io/papermc/paperweight/core/taskcontainers/GitMutationLockRegistrationTest.kt @@ -0,0 +1,110 @@ +/* + * 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.core.taskcontainers + +import io.papermc.paperweight.core.tasks.patchroulette.PatchRouletteTasks +import io.papermc.paperweight.tasks.* +import kotlin.test.Test +import kotlin.test.assertEquals +import org.gradle.api.Task +import org.gradle.api.internal.TaskInternal + +class GitMutationLockRegistrationTest : TaskTest() { + private fun Task.requiredServicesCount(): Int = (this as TaskInternal).requiredServices.elements.size + + private fun setupPatchingTasks(readOnly: Boolean): Pair> { + val project = setupProject() + val patchingTasks = PatchingTasks( + project = project, + forkName = "testFork", + patchSetName = "testPatchSet", + taskGroup = "patching", + readOnly = readOnly, + filePatchDir = project.objects.directoryProperty().convention(project.layout.projectDirectory.dir("patches/files")), + rejectsDir = project.objects.directoryProperty().convention(project.layout.projectDirectory.dir("patches/rejected")), + featurePatchDir = project.objects.directoryProperty().convention(project.layout.projectDirectory.dir("patches/features")), + baseDir = project.provider { project.layout.projectDirectory.dir("base") }, + gitFilePatches = project.provider { false }, + filterPatches = project.provider { true }, + outputDir = project.objects.directoryProperty().convention(project.layout.projectDirectory.dir("worktree")), + ) + val tasks = buildList { + add(patchingTasks.applyFilePatches.get()) + add(patchingTasks.applyFilePatchesFuzzy.get()) + add(patchingTasks.applyFeaturePatches.get()) + if (!readOnly) { + add(project.tasks.named(patchingTasks.rebuildFilePatchesName).get()) + add(project.tasks.named(patchingTasks.fixupFilePatchesName).get()) + add(project.tasks.named(patchingTasks.rebuildFeaturePatchesName).get()) + add(project.tasks.named("applyOrMoveTestPatchSetFilePatches").get()) + } + } + return patchingTasks to tasks + } + + @Test + fun `writable patching tasks require git mutation lock service`() { + val (_, tasks) = setupPatchingTasks(readOnly = false) + + tasks.forEach { task -> + assertEquals( + expected = 1, + actual = task.requiredServicesCount(), + message = "Expected ${task.path} to require the git mutation lock service", + ) + } + } + + @Test + fun `read only patching tasks do not require git mutation lock service`() { + val (_, tasks) = setupPatchingTasks(readOnly = true) + + tasks.forEach { task -> + assertEquals( + expected = 0, + actual = task.requiredServicesCount(), + message = "Expected ${task.path} to avoid the git mutation lock service", + ) + } + } + + @Test + fun `patch roulette only locks apply task`() { + val project = setupProject() + PatchRouletteTasks( + target = project, + namePrefix = "paper", + minecraftVer = project.provider { "26.1.2" }, + patchDirectory = project.provider { project.layout.projectDirectory.dir("patches") }, + targetDirectory = project.layout.projectDirectory.dir("target"), + ) + + val apply = project.tasks.named("paperPatchRouletteApply").get() + val cancel = project.tasks.named("paperPatchRouletteCancel").get() + val finish = project.tasks.named("paperPatchRouletteFinish").get() + + assertEquals(expected = 1, actual = apply.requiredServicesCount()) + assertEquals(expected = 0, actual = cancel.requiredServicesCount()) + assertEquals(expected = 0, actual = finish.requiredServicesCount()) + } +} diff --git a/paperweight-core/src/test/resources/functional_patcher_fork/build.gradle.kts b/paperweight-core/src/test/resources/functional_patcher_fork/build.gradle.kts new file mode 100644 index 000000000..1afad448b --- /dev/null +++ b/paperweight-core/src/test/resources/functional_patcher_fork/build.gradle.kts @@ -0,0 +1,46 @@ +import io.papermc.paperweight.core.tasks.CheckoutRepo +import org.gradle.api.plugins.JavaPluginExtension + +plugins { + id("io.papermc.paperweight.patcher") +} + +subprojects { + plugins.apply("java") + extensions.configure { + toolchain { + languageVersion.set(JavaLanguageVersion.of(21)) + } + } + tasks.withType().configureEach { + options.release = 21 + } +} + +paperweight { + upstreams.register("forkOfPaper") { + repo = file("forkOfPaper-upstream").absolutePath + ref = "HEAD" + applyUpstreamNested = false + + patchFile { + path = "forkOfPaper-server/README.md" + outputFile = file("forkOfPaper-server/README.md") + patchFile = file("forkOfPaper-server/README.md.patch") + } + } +} + +tasks.register("writeForkOfPaperNestedOutput") { + val checkoutForkOfPaperRepo = tasks.named("checkoutForkOfPaperRepo") + val outputDir = checkoutForkOfPaperRepo.flatMap { it.outputDir.dir("forkOfPaper-server/generated") } + + outputs.dir(outputDir) + dependsOn(checkoutForkOfPaperRepo) + + doLast { + val outputFile = outputDir.get().file("generated.txt").asFile + outputFile.parentFile.mkdirs() + outputFile.writeText("generated") + } +} diff --git a/paperweight-core/src/test/resources/functional_patcher_fork/forkOfFork-server/build.gradle.kts b/paperweight-core/src/test/resources/functional_patcher_fork/forkOfFork-server/build.gradle.kts new file mode 100644 index 000000000..9a2e29809 --- /dev/null +++ b/paperweight-core/src/test/resources/functional_patcher_fork/forkOfFork-server/build.gradle.kts @@ -0,0 +1,41 @@ +plugins { + id("java") + id("io.papermc.paperweight.core") +} + +repositories { + mavenLocal() + mavenCentral() + maven("https://repo.papermc.io/repository/maven-public/") +} + +dependencies { + mache(files("../mache.zip")) +} + +paperweight { + minecraftVersion = "fake" + minecraftManifestUrl = "file://project/../fake_mojang/version_manifest.json" + + val forkOfPaper = forks.register("forkOfPaper") { + upstream.patchDir("paperServer") { + upstreamPath = "paper-server" + excludes = listOf("src/minecraft") + patchesDir = rootDirectory.dir("forkOfPaper-server/paper-patches") + outputDir = rootDirectory.dir("paper-server") + } + } + + val forkOfFork = forks.register("forkOfFork") { + forks = forkOfPaper + + upstream.patchDir("forkOfPaperServer") { + upstreamPath = "forkOfPaper-server" + excludes = listOf("src/minecraft") + patchesDir = rootDirectory.dir("forkOfFork-server/forkOfPaper-patches") + outputDir = rootDirectory.dir("forkOfPaper-server") + } + } + + activeFork = forkOfFork +} diff --git a/paperweight-core/src/test/resources/functional_patcher_fork/forkOfPaper-server/README.md b/paperweight-core/src/test/resources/functional_patcher_fork/forkOfPaper-server/README.md new file mode 100644 index 000000000..963435212 --- /dev/null +++ b/paperweight-core/src/test/resources/functional_patcher_fork/forkOfPaper-server/README.md @@ -0,0 +1 @@ +"fork of paper" upstream repo diff --git a/paperweight-core/src/test/resources/functional_patcher_fork/settings.gradle.kts b/paperweight-core/src/test/resources/functional_patcher_fork/settings.gradle.kts new file mode 100644 index 000000000..2f6e59129 --- /dev/null +++ b/paperweight-core/src/test/resources/functional_patcher_fork/settings.gradle.kts @@ -0,0 +1,16 @@ +pluginManagement { + repositories { + mavenLocal() + gradlePluginPortal() + maven("https://repo.papermc.io/repository/maven-public/") + maven("https://maven.parchmentmc.org") + } +} + +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "0.9.0" +} + +rootProject.name = "functional_patcher_fork" + +include("forkOfFork-server") diff --git a/paperweight-core/src/test/resources/functional_patcher_fork_upstream/forkOfPaper-server/README.md b/paperweight-core/src/test/resources/functional_patcher_fork_upstream/forkOfPaper-server/README.md new file mode 100644 index 000000000..963435212 --- /dev/null +++ b/paperweight-core/src/test/resources/functional_patcher_fork_upstream/forkOfPaper-server/README.md @@ -0,0 +1 @@ +"fork of paper" upstream repo diff --git a/paperweight-core/src/test/resources/functional_patcher_fork_upstream/forkOfPaper-server/minecraft-patches/features/0001-Collect-forkOfPaper-at.patch b/paperweight-core/src/test/resources/functional_patcher_fork_upstream/forkOfPaper-server/minecraft-patches/features/0001-Collect-forkOfPaper-at.patch new file mode 100644 index 000000000..884314a84 --- /dev/null +++ b/paperweight-core/src/test/resources/functional_patcher_fork_upstream/forkOfPaper-server/minecraft-patches/features/0001-Collect-forkOfPaper-at.patch @@ -0,0 +1,15 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Test +Date: Thu, 24 Apr 2026 00:00:00 +0000 +Subject: [PATCH] Collect forkOfPaper at + +== AT == +public net/minecraft/server/Something exampleField + +diff --git a/README.md b/README.md +index 0000000..1111111 100644 +--- a/README.md ++++ b/README.md +@@ -1 +1 @@ +-"fork of paper" upstream repo ++"fork of paper" upstream repo with AT diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/GitMutationLockService.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/GitMutationLockService.kt new file mode 100644 index 000000000..46051e7b0 --- /dev/null +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/GitMutationLockService.kt @@ -0,0 +1,28 @@ +/* + * 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 + +import org.gradle.api.services.BuildService +import org.gradle.api.services.BuildServiceParameters + +abstract class GitMutationLockService : BuildService diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/constants/constants.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/constants/constants.kt index fc8c114a3..5f870fa93 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/constants/constants.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/constants/constants.kt @@ -114,6 +114,7 @@ const val FINAL_REMAPPED_CODEBOOK_JAR = "$TASK_CACHE/codebook-minecraft.jar" const val FINAL_DECOMPILE_JAR = "$TASK_CACHE/decompileJar.jar" const val DOWNLOAD_SERVICE_NAME = "paperweightDownloadService" +const val GIT_MUTATION_LOCK_SERVICE_NAME = "paperweightGitMutationLockService" private const val MACHE_PATH = "$PAPER_PATH/mache" const val BASE_PROJECT = "$MACHE_PATH/base" diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/utils.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/utils.kt index 2a4246f24..f7788fd9b 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/utils.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/utils.kt @@ -26,6 +26,7 @@ import com.github.salomonbrys.kotson.fromJson import com.google.gson.* import dev.denwav.hypo.model.ClassProviderRoot import io.papermc.paperweight.DownloadService +import io.papermc.paperweight.GitMutationLockService import io.papermc.paperweight.PaperweightException import io.papermc.paperweight.tasks.* import io.papermc.paperweight.util.constants.* @@ -114,6 +115,11 @@ fun Provider.fileExists(): Provider { val Project.download: Provider get() = gradle.sharedServices.registrations.getByName(DOWNLOAD_SERVICE_NAME).service as Provider +val Project.gitMutationLockService: Provider + get() = gradle.sharedServices.registerIfAbsent(GIT_MUTATION_LOCK_SERVICE_NAME, GitMutationLockService::class) { + maxParallelUsages.set(1) + } + fun commentRegex(): Regex { return Regex("\\s*#.*") } @@ -292,6 +298,7 @@ fun emptyMergeResult(): MergeResult { inline fun TaskContainer.registering(noinline configuration: T.() -> Unit) = registering(T::class, configuration) inline fun TaskContainer.registering() = registering(T::class) +inline fun TaskContainer.namedOrNull(name: String) = if (name in names) named(name) else null enum class HashingAlgorithm(val algorithmName: String) { SHA256("SHA-256"), @@ -389,7 +396,6 @@ fun JavaToolchainService.defaultJavaLauncher(project: Project): Provider> P.changesDisallowed(): P = apply { disallowChanges() } -fun

> P.finalizedOnRead(): P = apply { finalizeValueOnRead() } fun FileCollection.toJarClassProviderRoots(): List = files.asSequence() .map { f -> f.toPath() }