Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mechanism for bringing in Git history from an old Minecraft version when updating Minecraft #284

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,15 @@ import io.papermc.paperweight.core.extension.PaperweightCoreExtension
import io.papermc.paperweight.core.taskcontainers.CoreTasks
import io.papermc.paperweight.core.taskcontainers.DevBundleTasks
import io.papermc.paperweight.core.taskcontainers.PaperclipTasks
import io.papermc.paperweight.core.tasks.patchroulette.PatchRouletteTasks
import io.papermc.paperweight.core.util.coreExt
import io.papermc.paperweight.core.util.createBuildTasks
import io.papermc.paperweight.tasks.*
import io.papermc.paperweight.util.*
import io.papermc.paperweight.util.constants.*
import io.papermc.paperweight.util.data.mache.*
import javax.inject.Inject
import kotlin.io.path.*
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.dsl.DependencyFactory
Expand Down Expand Up @@ -191,6 +194,22 @@ abstract class PaperweightCore : Plugin<Project> {
devBundleTasks.configureAfterEvaluate(
includeMappings.flatMap { it.outputJar },
)

if (coreExt.updatingMinecraft.oldPaperCommit.isPresent) {
tasks.paperPatchingTasks.applySourcePatches.configure {
additionalRemote = layout.cache.resolve(
"$OLD_PAPER_PATH/${coreExt.updatingMinecraft.oldPaperCommit.get()}/paper-server/src/minecraft/java"
).absolutePathString()
}
}
// TODO move into above 'if'
PatchRouletteTasks(
target,
"paper",
coreExt.minecraftVersion,
coreExt.paper.sourcePatchDir, // TODO use reject dir
layout.projectDirectory.dir("src/minecraft/java"),
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import javax.inject.Inject
import org.gradle.api.Action
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
Expand All @@ -42,8 +41,8 @@ abstract class PaperweightCoreExtension @Inject constructor(objects: ObjectFacto

val macheRepo: Property<String> = objects.property<String>().convention(PAPER_MAVEN_REPO_URL)

val macheOldPath: DirectoryProperty = objects.directoryProperty()
val gitFilePatches: Property<Boolean> = objects.property<Boolean>().convention(false)
val filterPatches: Property<Boolean> = objects.property<Boolean>().convention(true)

val vanillaJarIncludes: ListProperty<String> = objects.listProperty<String>().convention(
listOf("/*.class", "/net/minecraft/**", "/com/mojang/math/**")
Expand All @@ -69,4 +68,10 @@ abstract class PaperweightCoreExtension @Inject constructor(objects: ObjectFacto
}

val activeFork: Property<ForkConfig> = objects.property()

val updatingMinecraft = objects.newInstance<UpdatingMinecraftExtension>()

fun updatingMinecraft(action: Action<UpdatingMinecraftExtension>) {
action.execute(updatingMinecraft)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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.extension

import org.gradle.api.provider.Property

interface UpdatingMinecraftExtension {
val oldPaperCommit: Property<String>
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ class CoreTasks(
val mache: Property<MacheMeta>,
tasks: TaskContainer = project.tasks
) : AllTasks(project) {
lateinit var paperPatchingTasks: MinecraftPatchingTasks

val macheRemapJar by tasks.registering(RunCodebook::class) {
serverJar.set(extractFromBundler.flatMap { it.serverJar })
serverMappings.set(downloadMappings.flatMap { it.outputFile })
Expand Down Expand Up @@ -95,7 +97,7 @@ class CoreTasks(

private fun SetupMinecraftSources.configureSetupMacheSources() {
mache.from(project.configurations.named(MACHE_CONFIG))
macheOld.set(project.coreExt.macheOldPath)
oldPaperCommit.convention(project.coreExt.updatingMinecraft.oldPaperCommit)
inputFile.set(macheDecompileJar.flatMap { it.outputJar })
predicate.set { Files.isRegularFile(it) && it.toString().endsWith(".java") }
}
Expand Down Expand Up @@ -161,7 +163,7 @@ class CoreTasks(
} else {
project.layout.projectDirectory.path
}
val paperPatchingTasks = MinecraftPatchingTasks(
paperPatchingTasks = MinecraftPatchingTasks(
project,
"paper",
true,
Expand All @@ -175,6 +177,7 @@ class CoreTasks(
setupMacheSources.flatMap { it.outputDir },
setupMacheResources.flatMap { it.outputDir },
project.coreExt.gitFilePatches,
project.coreExt.filterPatches,
paperOutputRoot,
)

Expand Down Expand Up @@ -210,6 +213,7 @@ class CoreTasks(
upstreamTasks.first.applyFeaturePatches.flatMap { it.repo },
upstreamTasks.first.applyResourcePatches.flatMap { it.output },
project.coreExt.gitFilePatches,
project.coreExt.filterPatches,
outputRoot,
)

Expand All @@ -231,6 +235,7 @@ class CoreTasks(
"upstream server patching"
},
project.coreExt.gitFilePatches,
project.coreExt.filterPatches,
null,
upstreamTasks.second,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class MinecraftPatchingTasks(
private val baseSources: Provider<Directory>,
private val baseResources: Provider<Directory>,
private val gitFilePatches: Provider<Boolean>,
private val filterPatches: Provider<Boolean>,
outputRoot: Path,
private val outputSrc: Path = outputRoot.resolve("src/minecraft/java"),
private val outputResources: Path = outputRoot.resolve("src/minecraft/resources"),
Expand Down Expand Up @@ -237,6 +238,7 @@ class MinecraftPatchingTasks(
inputDir.set(outputSrc)
patchDir.set(featurePatchDir)
baseRef.set("file")
filterPatches.set([email protected])
}

val rebuildPatches = tasks.register<Task>(rebuildPatchesName) {
Expand All @@ -260,5 +262,13 @@ class MinecraftPatchingTasks(
repo.set(outputResources)
upstream.set("upstream/main")
}

val applyOrMoveSourcePatches = tasks.register<ApplyFilePatches>("applyOrMove${namePart}SourcePatches") {
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."
gitFilePatches = true
moveFailedGitPatchesToRejects = true
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class PatchingTasks(
private val featurePatchDir: DirectoryProperty,
private val baseDir: Provider<Directory>,
private val gitFilePatches: Provider<Boolean>,
private val filterPatches: Provider<Boolean>,
private val outputDir: Path,
private val tasks: TaskContainer = project.tasks,
) {
Expand Down Expand Up @@ -146,12 +147,21 @@ class PatchingTasks(
inputDir.set(outputDir)
patchDir.set(featurePatchDir)
baseRef.set("file")
filterPatches.set([email protected])
}

val rebuildPatches = tasks.register<Task>(rebuildPatchesName) {
group = taskGroup
description = "Rebuilds all $patchSetName patches"
dependsOn(rebuildFilePatches, rebuildFeaturePatches)
}

val applyOrMoveFilePatches = tasks.register<ApplyFilePatches>("applyOrMove${namePart}FilePatches") {
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."
gitFilePatches = true
moveFailedGitPatchesToRejects = true
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class UpstreamConfigTasks(
private val readOnly: Boolean,
private val taskGroup: String,
private val gitFilePatches: Provider<Boolean>,
private val filterPatches: Provider<Boolean>,
private val setupUpstream: TaskProvider<out RunNestedBuild>?,
private val upstreamTasks: UpstreamConfigTasks?,
) {
Expand Down Expand Up @@ -132,6 +133,7 @@ class UpstreamConfigTasks(
cfg.featurePatchDir,
base,
gitFilePatches,
filterPatches,
cfg.outputDir.path,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,13 @@ package io.papermc.paperweight.core.tasks
import codechicken.diffpatch.cli.PatchOperation
import codechicken.diffpatch.util.LoggingOutputStream
import codechicken.diffpatch.util.archiver.ArchiveFormat
import io.papermc.paperweight.PaperweightException
import io.papermc.paperweight.core.util.ApplySourceATs
import io.papermc.paperweight.tasks.*
import io.papermc.paperweight.util.*
import io.papermc.paperweight.util.constants.*
import java.nio.file.Path
import java.util.concurrent.TimeUnit
import java.util.function.Predicate
import kotlin.io.path.*
import org.eclipse.jgit.api.Git
Expand Down Expand Up @@ -64,8 +67,8 @@ abstract class SetupMinecraftSources : JavaLauncherTask() {
abstract val mache: ConfigurableFileCollection

@get:Optional
@get:InputDirectory
abstract val macheOld: DirectoryProperty
@get:Input
abstract val oldPaperCommit: Property<String>

@get:Nested
val ats: ApplySourceATs = objects.newInstance()
Expand All @@ -79,7 +82,26 @@ abstract class SetupMinecraftSources : JavaLauncherTask() {
val outputPath = outputDir.convertToPath()

val git: Git
if (outputPath.resolve(".git/HEAD").isRegularFile()) {
if (oldPaperCommit.isPresent) {
val oldPaperDir = setupOldPaper()

if (outputPath.exists()) {
outputPath.deleteRecursive()
}

outputPath.createDirectories()

git = Git.cloneRepository()
.setDirectory(outputPath.toFile())
.setRemote("old")
.setURI(oldPaperDir.resolve("paper-server/src/minecraft/java").absolutePathString())
.call()
git.reset().setMode(ResetCommand.ResetType.HARD).setRef("ATs").call()

// Now delete all MC sources so that when we copy in current and commit, it creates an 'update commit'
outputPath.resolve("com/mojang").deleteRecursive()
outputPath.resolve("net/minecraft").deleteRecursive()
} else if (outputPath.resolve(".git/HEAD").isRegularFile()) {
git = Git.open(outputPath.toFile())
git.reset().setRef("ROOT").setMode(ResetCommand.ResetType.HARD).call()
} else {
Expand All @@ -96,16 +118,6 @@ abstract class SetupMinecraftSources : JavaLauncherTask() {
git.tag().setName("ROOT").setTagger(rootIdent).setSigned(false).call()
}

if (macheOld.isPresent) {
println("Using ${macheOld.convertToPath().absolutePathString()} as starting point")
git.remoteRemove().setRemoteName("old").call()
git.remoteAdd().setName("old").setUri(URIish(macheOld.convertToPath().absolutePathString())).call()
git.fetch().setRemote("old").call()
git.checkout().setName("old/mache").call()
git.branchDelete().setBranchNames("main").setForce(true).call()
git.checkout().setName("main").setCreateBranch(true).call()
}

println("Copy initial sources...")
inputFile.path.openZip().use { inputFileFs ->
inputFileFs.walkSequence()
Expand All @@ -128,8 +140,7 @@ abstract class SetupMinecraftSources : JavaLauncherTask() {
}

println("Setup git repo...")
if (!macheOld.isPresent) {
// skip this if we are diffing against old, since it would be a commit without mache patches
if (!oldPaperCommit.isPresent) {
commitAndTag(git, "Vanilla")
}

Expand All @@ -147,7 +158,9 @@ abstract class SetupMinecraftSources : JavaLauncherTask() {
.build()
.operate()

commitAndTag(git, "Mache")
if (!oldPaperCommit.isPresent) {
commitAndTag(git, "Mache")
}

if (result.exit != 0) {
throw Exception("Failed to apply ${result.summary.failedMatches} mache patches")
Expand All @@ -165,7 +178,13 @@ abstract class SetupMinecraftSources : JavaLauncherTask() {
atFile.path,
temporaryDir.toPath(),
)
commitAndTag(git, "ATs", "paper ATs")
if (!oldPaperCommit.isPresent) {
commitAndTag(git, "ATs", "paper ATs")
}
}

if (oldPaperCommit.isPresent) {
commitAndTag(git, "Vanilla", "Vanilla, Mache, & paper ATs (Squashed for better Git history during updates)")
}

if (libraryImports.isPresent) {
Expand All @@ -176,6 +195,56 @@ abstract class SetupMinecraftSources : JavaLauncherTask() {

git.close()
}

private fun setupOldPaper(): Path {
logger.lifecycle("Setting up Paper commit ${oldPaperCommit.get()} to use as base for constructing Git repo...")

val rootProjectDir = layout.projectDirectory.dir("../").path
val oldPaperDir = layout.cache.resolve("$OLD_PAPER_PATH/${oldPaperCommit.get()}")
val oldPaperLog = layout.cache.resolve("$OLD_PAPER_PATH/${oldPaperCommit.get()}.log")

val oldPaperGit: Git
if (oldPaperDir.exists()) {
oldPaperGit = Git.open(oldPaperDir.toFile())
} else {
oldPaperDir.createParentDirectories()
oldPaperGit = Git.init()
.setDirectory(oldPaperDir.toFile())
.setInitialBranch("main")
.call()
oldPaperGit.remoteRemove().setRemoteName("origin").call()
oldPaperGit.remoteAdd().setName("origin").setUri(URIish(rootProjectDir.absolutePathString())).call()
}

oldPaperGit.fetch().setDepth(1).setRemote("origin").setRefSpecs(oldPaperCommit.get()).call()
oldPaperGit.reset().setMode(ResetCommand.ResetType.HARD).setRef(oldPaperCommit.get()).call()
oldPaperGit.close()

oldPaperLog.outputStream().use { logOut ->
val processBuilder = ProcessBuilder(
"./gradlew",
"applyPatches",
"--console",
"plain",
"--stacktrace",
"-Dpaperweight.debug=true"
)
processBuilder.directory(oldPaperDir)
val process = processBuilder.start()

val outFuture = redirect(process.inputStream, logOut)
val errFuture = redirect(process.errorStream, logOut)

val exit = process.waitFor()
outFuture.get(500L, TimeUnit.MILLISECONDS)
errFuture.get(500L, TimeUnit.MILLISECONDS)

if (exit != 0) {
throw PaperweightException("Failed to apply old Paper, see log at $oldPaperLog")
}
}
return oldPaperDir
}
}

fun commitAndTag(git: Git, name: String, message: String = name) {
Expand Down
Loading
Loading