Paper/build.gradle.kts

328 lines
12 KiB
Plaintext
Raw Normal View History

2023-12-06 04:35:33 +01:00
import io.papermc.paperweight.util.*
2024-12-20 09:37:00 +01:00
import io.papermc.paperweight.util.constants.*
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent
import java.io.IOException
import java.net.URI
import java.nio.file.FileVisitResult
import java.nio.file.Files
import java.nio.file.SimpleFileVisitor
2023-12-06 04:35:33 +01:00
import kotlin.io.path.*
import java.nio.file.Path
2024-12-13 17:04:25 +01:00
import kotlin.random.Random
plugins {
id("io.papermc.paperweight.core") version "2.0.0-beta.8" apply false
}
2024-12-06 22:02:39 +01:00
subprojects {
apply(plugin = "java-library")
2021-08-18 00:11:04 +02:00
apply(plugin = "maven-publish")
2024-12-06 22:02:39 +01:00
extensions.configure<JavaPluginExtension> {
toolchain {
2024-04-23 19:02:08 +02:00
languageVersion = JavaLanguageVersion.of(21)
}
}
2024-12-06 22:46:41 +01:00
tasks.withType<AbstractArchiveTask>().configureEach {
isPreserveFileTimestamps = false
isReproducibleFileOrder = true
}
}
val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/"
subprojects {
tasks.withType<JavaCompile> {
options.encoding = Charsets.UTF_8.name()
2024-04-23 19:02:08 +02:00
options.release = 21
options.isFork = true
}
tasks.withType<Javadoc> {
options.encoding = Charsets.UTF_8.name()
}
tasks.withType<ProcessResources> {
filteringCharset = Charsets.UTF_8.name()
}
tasks.withType<Test> {
testLogging {
showStackTraces = true
exceptionFormat = TestExceptionFormat.FULL
events(TestLogEvent.STANDARD_OUT)
}
}
repositories {
mavenCentral()
maven(paperMavenPublicUrl)
}
2021-08-18 00:11:04 +02:00
2024-12-06 22:02:39 +01:00
extensions.configure<PublishingExtension> {
2021-08-18 00:11:04 +02:00
repositories {
maven("https://repo.papermc.io/repository/maven-snapshots/") {
2021-08-18 00:11:04 +02:00
name = "paperSnapshots"
credentials(PasswordCredentials::class)
}
}
}
}
tasks.register("printMinecraftVersion") {
2024-12-12 12:22:30 +01:00
val mcVersion = providers.gradleProperty("mcVersion")
doLast {
2024-12-12 12:22:30 +01:00
println(mcVersion.get().trim())
}
}
2022-03-04 10:41:03 +01:00
tasks.register("printPaperVersion") {
2024-12-12 12:22:30 +01:00
val paperVersion = provider { project.version }
2022-03-04 10:41:03 +01:00
doLast {
2024-12-12 12:22:30 +01:00
println(paperVersion.get())
2022-03-04 10:41:03 +01:00
}
}
2023-12-06 04:35:33 +01:00
tasks.register("gibWork") {
val issue = providers.gradleProperty("updateTaskListIssue").get()
val patchesFolder = layout.projectDirectory.dir("paper-server/patches/").convertToPath()
val storage = layout.cache.resolve("last-updating-folder").also { it.parent.createDirectories() }
doLast {
val html = URI(issue).toURL().readText()
val beginMarker = "```[tasklist]"
val start = html.indexOf(beginMarker)
val end = html.indexOf("```", start + beginMarker.length)
val taskList = html.substring(start + beginMarker.length, end)
2024-12-13 17:04:25 +01:00
// Extract all incomplete tasks and select a random one
val incompleteTasks = taskList.split("\\n").filter { it.startsWith("- [ ]") }.map { it.replace("- [ ] ", "") }
if (incompleteTasks.isEmpty()) {
error("No incomplete tasks found in the task list.")
}
val next = incompleteTasks[Random.nextInt(incompleteTasks.size)]
println("checking out $next...")
val dir = patchesFolder.resolve("unapplied").resolve(next)
if (!dir.exists()) {
error("Unapplied patch folder $next does not exist, did someone else already check it out and forgot to mark it?")
}
dir.listDirectoryEntries("*.patch").forEach { patch ->
patch.copyTo(patchesFolder.resolve("sources").resolve(next).resolve(patch.fileName).also { it.createDirectories() }, overwrite = true)
patch.deleteIfExists()
}
if (dir.listDirectoryEntries().isEmpty()) {
dir.deleteIfExists()
}
storage.writeText(next)
println("please tick the box in the issue: $issue")
println("if you don't finish it, uncheck the task again after you commited")
}
}
tasks.register("showWork") {
val patchDir = layout.projectDirectory.dir("paper-server/patches/unapplied/").convertToPath()
doLast {
Files.walkFileTree(patchDir, object : SimpleFileVisitor<Path>() {
override fun postVisitDirectory(dir: Path?, exc: IOException?): FileVisitResult {
dir?.takeIf { it.listDirectoryEntries("*.patch").isNotEmpty() }?.let {
println("- [ ] ${patchDir.relativize(it).pathString.replace("\\", "/")}")
}
return FileVisitResult.CONTINUE
}
})
}
}
tasks.register("checkWork") {
2024-12-13 18:24:26 +01:00
notCompatibleWithConfigurationCache("This task is interactive")
2024-12-12 12:22:30 +01:00
fun expandUserHome(path: String): Path {
return Path.of(path.replaceFirst("^~".toRegex(), System.getProperty("user.home")))
}
2024-12-20 09:37:00 +01:00
val input = providers.fileContents(layout.projectDirectory.file("$CACHE_PATH/last-updating-folder")).asText.map { it.trim() }
val patchFolder = layout.projectDirectory.dir("paper-server/patches/sources").dir(input)
2024-12-22 11:45:15 +01:00
val sourceFolder = layout.projectDirectory.dir("paper-server/src/minecraft/java").dir(input)
2024-12-20 09:37:00 +01:00
val targetFolder = providers.gradleProperty("cleanPaperRepo").map {
expandUserHome(it).resolve(input.get())
}
fun copy(back: Boolean = false) {
2024-12-20 09:37:00 +01:00
patchFolder.path.listDirectoryEntries().forEach {
val relative = patchFolder.path.relativize(it).toString().replace(".patch", "")
val source = sourceFolder.path.resolve(relative)
val target = targetFolder.get().resolve(relative)
2024-12-13 17:38:42 +01:00
if (target.isDirectory()) { return@forEach }
if (back) {
target.copyTo(source, overwrite = true)
} else {
source.copyTo(target, overwrite = true)
}
}
}
doLast {
2024-12-20 09:37:00 +01:00
if (!targetFolder.isPresent) {
error("cleanPaperRepo is required, define it in gradle.properties")
}
copy()
2024-12-20 09:37:00 +01:00
val files = patchFolder.path.listDirectoryEntries().map { it.fileName.toString().replace(".patch", "") }
println("Copied $files from $sourceFolder to $targetFolder")
println("Make the files compile, then press enter to copy them back!")
System.`in`.read()
copy(back = true)
println("copied back!")
}
}
2023-12-06 04:35:33 +01:00
// see gradle.properties
2024-12-06 22:02:39 +01:00
/*
2023-12-06 04:35:33 +01:00
if (providers.gradleProperty("updatingMinecraft").getOrElse("false").toBoolean()) {
tasks.collectAtsFromPatches {
2023-12-06 19:48:37 +01:00
val dir = layout.projectDirectory.dir("patches/unapplied/server")
if (dir.path.isDirectory()) {
extraPatchDir = dir
}
2023-12-06 04:35:33 +01:00
}
tasks.withType<io.papermc.paperweight.tasks.RebuildGitPatches>().configureEach {
2023-12-06 19:48:37 +01:00
filterPatches = false
2023-12-06 04:35:33 +01:00
}
tasks.register("continueServerUpdate", RebasePatches::class) {
2023-12-06 05:59:31 +01:00
description = "Moves the next X patches from unapplied to applied, and applies them. X being the number of patches that apply cleanly, plus the terminal failure if any."
2023-12-06 04:35:33 +01:00
projectDir = project.projectDir
appliedPatches = file("patches/server")
unappliedPatches = file("patches/unapplied/server")
2023-12-06 19:48:37 +01:00
applyTaskName = "applyServerPatches"
2024-04-23 20:44:28 +02:00
patchedDir = "Paper-Server"
2023-12-06 04:35:33 +01:00
}
}
@UntrackedTask(because = "Does not make sense to track state")
abstract class RebasePatches : BaseTask() {
@get:Internal
abstract val projectDir: DirectoryProperty
@get:InputFiles
abstract val appliedPatches: DirectoryProperty
@get:InputFiles
abstract val unappliedPatches: DirectoryProperty
2023-12-06 19:48:37 +01:00
@get:Input
abstract val applyTaskName: Property<String>
2024-04-23 20:44:28 +02:00
@get:Input
abstract val patchedDir: Property<String>
2023-12-06 04:35:33 +01:00
private fun unapplied(): List<Path> =
unappliedPatches.path.listDirectoryEntries("*.patch").sortedBy { it.name }
2023-12-06 05:46:41 +01:00
private fun appliedLoc(patch: Path): Path = appliedPatches.path.resolve(unappliedPatches.path.relativize(patch))
companion object {
val regex = Pattern.compile("Patch failed at ([0-9]{4}) (.*)")
val continuationRegex = Pattern.compile("^\\s{1}.+\$")
2023-12-06 05:46:41 +01:00
const val subjectPrefix = "Subject: [PATCH] "
}
2023-12-06 04:35:33 +01:00
@TaskAction
fun run() {
val patchedDirPath = projectDir.path.resolve(patchedDir.get())
if (patchedDirPath.isDirectory()) {
val status = Git(patchedDirPath)("status").getText()
if (status.contains("You are in the middle of an am session.")) {
throw PaperweightException("Cannot continue update when $patchedDirPath is in the middle of an am session.")
}
}
2023-12-06 05:46:41 +01:00
val unapplied = unapplied()
for (patch in unapplied) {
patch.copyTo(appliedLoc(patch))
}
2023-12-06 04:35:33 +01:00
2023-12-06 05:46:41 +01:00
val out = ByteArrayOutputStream()
val proc = ProcessBuilder()
.directory(projectDir.path)
2023-12-06 19:48:37 +01:00
.command("./gradlew", applyTaskName.get())
2023-12-06 05:46:41 +01:00
.redirectErrorStream(true)
.start()
val f = redirect(proc.inputStream, out)
2023-12-06 05:46:41 +01:00
val exit = proc.waitFor()
f.get()
2023-12-06 05:46:41 +01:00
if (exit != 0) {
val outStr = String(out.toByteArray())
val matcher = regex.matcher(outStr)
if (!matcher.find()) error("Could not determine failure point")
val failedSubjectFragment = matcher.group(2)
val failed = unapplied.single { p ->
p.useLines { lines ->
val collect = mutableListOf<String>()
for (line in lines) {
if (line.startsWith(subjectPrefix)) {
collect += line
} else if (collect.size == 1) {
if (continuationRegex.matcher(line).matches()) {
collect += line
} else {
break
}
}
}
val subjectLine = collect.joinToString("").substringAfter(subjectPrefix)
2023-12-06 05:46:41 +01:00
subjectLine.startsWith(failedSubjectFragment)
}
}
// delete successful & failure point from unapplied patches dir
for (path in unapplied) {
path.deleteIfExists()
if (path == failed) {
break
}
}
2023-12-06 04:35:33 +01:00
2023-12-06 05:46:41 +01:00
// delete failed from patches dir
var started = false
for (path in unapplied) {
if (path == failed) {
started = true
continue
}
if (started) {
appliedLoc(path).deleteIfExists()
}
}
2024-04-23 20:44:28 +02:00
// Delete the build file before resetting the AM session in case it has compilation errors
patchedDirPath.resolve("build.gradle.kts").deleteIfExists()
2023-12-06 05:46:41 +01:00
// Apply again to reset the am session (so it ends on the failed patch, to allow us to rebuild after fixing it)
val apply2 = ProcessBuilder()
2023-12-06 04:35:33 +01:00
.directory(projectDir.path)
2023-12-06 19:48:37 +01:00
.command("./gradlew", applyTaskName.get())
2023-12-06 04:35:33 +01:00
.redirectErrorStream(true)
.start()
val f1 = redirect(apply2.inputStream, System.out)
2023-12-06 21:24:41 +01:00
apply2.waitFor()
f1.get()
2023-12-06 04:35:33 +01:00
2023-12-06 05:46:41 +01:00
logger.lifecycle(outStr)
logger.lifecycle("Patch failed at $failed; See Git output above.")
} else {
unapplied.forEach { it.deleteIfExists() }
logger.lifecycle("All patches applied!")
2023-12-06 04:35:33 +01:00
}
2023-12-06 05:46:41 +01:00
val git = Git(projectDir.path)
git("add", appliedPatches.path.toString() + "/*").runSilently()
git("add", unappliedPatches.path.toString() + "/*").runSilently()
2023-12-06 04:35:33 +01:00
}
}
2024-12-06 22:02:39 +01:00
*/