mirror of
https://github.com/PurpurMC/Purpur.git
synced 2026-02-17 08:27:43 +01:00
Update Toothpick
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
import xyz.jpenilla.toothpick.gitCmd
|
||||
import xyz.jpenilla.toothpick.toothpick
|
||||
|
||||
plugins {
|
||||
`java-library`
|
||||
`maven-publish`
|
||||
toothpick
|
||||
id("xyz.jpenilla.toothpick") version "1.0.0-SNAPSHOT"
|
||||
}
|
||||
|
||||
toothpick {
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
val kotlinxDomVersion = "0.0.10"
|
||||
val shadowVersion = "6.1.0"
|
||||
|
||||
plugins {
|
||||
`kotlin-dsl`
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
maven("https://plugins.gradle.org/m2/")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation("org.jetbrains.kotlinx:kotlinx.dom:$kotlinxDomVersion")
|
||||
implementation("com.github.jengelman.gradle.plugins:shadow:$shadowVersion")
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
register("Toothpick") {
|
||||
id = "toothpick"
|
||||
implementationClass = "Toothpick"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
import com.github.jengelman.gradle.plugins.shadow.ShadowPlugin
|
||||
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
import com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCacheFileTransformer
|
||||
import kotlinx.dom.elements
|
||||
import kotlinx.dom.parseXml
|
||||
import kotlinx.dom.search
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.JavaLibraryPlugin
|
||||
import org.gradle.api.publish.PublishingExtension
|
||||
import org.gradle.api.publish.maven.MavenPublication
|
||||
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin
|
||||
import org.gradle.api.publish.maven.tasks.GenerateMavenPom
|
||||
import org.gradle.api.tasks.bundling.Jar
|
||||
import org.gradle.api.tasks.compile.JavaCompile
|
||||
import org.gradle.api.tasks.javadoc.Javadoc
|
||||
import org.gradle.api.tasks.testing.Test
|
||||
import org.gradle.kotlin.dsl.apply
|
||||
import org.gradle.kotlin.dsl.attributes
|
||||
import org.gradle.kotlin.dsl.configure
|
||||
import org.gradle.kotlin.dsl.create
|
||||
import org.gradle.kotlin.dsl.get
|
||||
import org.gradle.kotlin.dsl.getByName
|
||||
import org.gradle.kotlin.dsl.getValue
|
||||
import org.gradle.kotlin.dsl.getting
|
||||
import org.gradle.kotlin.dsl.withType
|
||||
import java.nio.charset.StandardCharsets.UTF_8
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
|
||||
internal fun Project.configureSubprojects() {
|
||||
subprojects {
|
||||
apply<JavaLibraryPlugin>()
|
||||
apply<MavenPublishPlugin>()
|
||||
|
||||
tasks.withType<JavaCompile> {
|
||||
options.encoding = UTF_8.name()
|
||||
}
|
||||
tasks.withType<Javadoc> {
|
||||
options.encoding = UTF_8.name()
|
||||
}
|
||||
|
||||
extensions.configure<PublishingExtension> {
|
||||
publications {
|
||||
create<MavenPublication>("mavenJava") {
|
||||
groupId = rootProject.group as String
|
||||
version = rootProject.version as String
|
||||
pom {
|
||||
name.set(project.name)
|
||||
url.set(toothpick.forkUrl)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when {
|
||||
project.name.endsWith("server") -> configureServerProject()
|
||||
project.name.endsWith("api") -> configureApiProject()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Project.configureServerProject() {
|
||||
apply<ShadowPlugin>()
|
||||
|
||||
val generatePomFileForMavenJavaPublication by tasks.getting(GenerateMavenPom::class) {
|
||||
destination = project.buildDir.resolve("tmp/pom.xml")
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
val test by tasks.getting(Test::class) {
|
||||
// didn't bother to look into why these fail. paper excludes them in paperweight as well though
|
||||
exclude("org/bukkit/craftbukkit/inventory/ItemStack*Test.class")
|
||||
}
|
||||
|
||||
val shadowJar by tasks.getting(ShadowJar::class) {
|
||||
archiveClassifier.set("") // ShadowJar is the main server artifact
|
||||
dependsOn(generatePomFileForMavenJavaPublication)
|
||||
transform(Log4j2PluginsCacheFileTransformer::class.java)
|
||||
mergeServiceFiles()
|
||||
manifest {
|
||||
attributes(
|
||||
"Main-Class" to "org.bukkit.craftbukkit.Main",
|
||||
"Implementation-Title" to "CraftBukkit",
|
||||
"Implementation-Version" to toothpick.forkVersion,
|
||||
"Implementation-Vendor" to SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(Date()),
|
||||
"Specification-Title" to "Bukkit",
|
||||
"Specification-Version" to "${project.version}",
|
||||
"Specification-Vendor" to "Bukkit Team"
|
||||
)
|
||||
}
|
||||
from(project.buildDir.resolve("tmp/pom.xml")) {
|
||||
// dirty hack to make "java -Dpaperclip.install=true -jar paperclip.jar" work without forking paperclip
|
||||
into("META-INF/maven/io.papermc.paper/paper")
|
||||
}
|
||||
|
||||
// Don't like to do this but sadly have to do this for compatibility reasons
|
||||
relocate("org.bukkit.craftbukkit", "org.bukkit.craftbukkit.v${toothpick.nmsPackage}") {
|
||||
exclude("org.bukkit.craftbukkit.Main*")
|
||||
}
|
||||
relocate("net.minecraft.server", "net.minecraft.server.v${toothpick.nmsPackage}")
|
||||
|
||||
// Make sure we relocate deps the same as Paper et al.
|
||||
val pomFile = project.projectDir.resolve("pom.xml")
|
||||
if (!pomFile.exists()) return@getting
|
||||
val dom = parseXml(pomFile)
|
||||
val buildSection = dom.search("build").first()
|
||||
val plugins = buildSection.search("plugins").first()
|
||||
plugins.elements("plugin").filter {
|
||||
val artifactId = it.search("artifactId").first().textContent
|
||||
artifactId == "maven-shade-plugin"
|
||||
}.forEach {
|
||||
it.search("executions").first()
|
||||
.search("execution").first()
|
||||
.search("configuration").first()
|
||||
.search("relocations").first()
|
||||
.elements("relocation").forEach { relocation ->
|
||||
val pattern = relocation.search("pattern").first().textContent
|
||||
val shadedPattern = relocation.search("shadedPattern").first().textContent
|
||||
if (pattern != "org.bukkit.craftbukkit" && pattern != "net.minecraft.server") { // We handle these ourselves above
|
||||
logger.debug("Imported relocation to server project shadowJar from ${pomFile.absolutePath}: $pattern to $shadedPattern")
|
||||
relocate(pattern, shadedPattern)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.getByName("build") {
|
||||
dependsOn(shadowJar)
|
||||
}
|
||||
|
||||
extensions.configure<PublishingExtension> {
|
||||
publications {
|
||||
getByName<MavenPublication>("mavenJava") {
|
||||
artifactId = rootProject.name
|
||||
artifact(tasks["shadowJar"])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
private fun Project.configureApiProject() {
|
||||
val jar by this.tasks.getting(Jar::class) {
|
||||
doFirst {
|
||||
buildDir.resolve("tmp/pom.properties")
|
||||
.writeText("version=${project.version}")
|
||||
}
|
||||
from(buildDir.resolve("tmp/pom.properties")) {
|
||||
into("META-INF/maven/${project.group}/${project.name}")
|
||||
}
|
||||
manifest {
|
||||
attributes("Automatic-Module-Name" to "org.bukkit")
|
||||
}
|
||||
}
|
||||
|
||||
extensions.configure<PublishingExtension> {
|
||||
publications {
|
||||
getByName<MavenPublication>("mavenJava") {
|
||||
artifactId = project.name
|
||||
from(components["java"])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
const val taskGroup = "toothpick"
|
||||
const val internalTaskGroup = "toothpick_internal"
|
||||
@@ -1,64 +0,0 @@
|
||||
import kotlinx.dom.elements
|
||||
import kotlinx.dom.parseXml
|
||||
import kotlinx.dom.search
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.dsl.RepositoryHandler
|
||||
import org.gradle.kotlin.dsl.DependencyHandlerScope
|
||||
import org.gradle.kotlin.dsl.maven
|
||||
import org.gradle.kotlin.dsl.project
|
||||
|
||||
fun RepositoryHandler.loadRepositories(project: Project) {
|
||||
val pomFile = project.projectDir.resolve("pom.xml")
|
||||
if (!pomFile.exists()) return
|
||||
val dom = parseXml(pomFile)
|
||||
val repositoriesBlock = dom.search("repositories").firstOrNull() ?: return
|
||||
|
||||
// Load repositories
|
||||
repositoriesBlock.elements("repository").forEach { repositoryElem ->
|
||||
val url = repositoryElem.search("url").firstOrNull()?.textContent ?: return@forEach
|
||||
maven(url)
|
||||
}
|
||||
}
|
||||
|
||||
fun DependencyHandlerScope.loadDependencies(project: Project) {
|
||||
val pomFile = project.projectDir.resolve("pom.xml")
|
||||
if (!pomFile.exists()) return
|
||||
val dom = parseXml(pomFile)
|
||||
|
||||
val dependenciesBlock = dom.search("dependencies").firstOrNull() ?: return
|
||||
|
||||
// Load dependencies
|
||||
dependenciesBlock.elements("dependency").forEach { dependencyElem ->
|
||||
val groupId = dependencyElem.search("groupId").first().textContent
|
||||
val artifactId = dependencyElem.search("artifactId").first().textContent
|
||||
val version = dependencyElem.search("version").first().textContent.applyReplacements(
|
||||
"project.version" to project.version.toString(),
|
||||
"minecraft.version" to project.toothpick.minecraftVersion
|
||||
)
|
||||
val scope = dependencyElem.search("scope").firstOrNull()?.textContent
|
||||
val classifier = dependencyElem.search("classifier").firstOrNull()?.textContent
|
||||
|
||||
val dependencyString = "${groupId}:${artifactId}:${version}${classifier?.run { ":$this" } ?: ""}"
|
||||
project.logger.debug("Read dependency '{}' from '{}'", dependencyString, pomFile.absolutePath)
|
||||
|
||||
// Special case API
|
||||
if (artifactId == "${project.toothpick.forkNameLowercase}-api"
|
||||
|| artifactId == "${project.toothpick.upstreamLowercase}-api"
|
||||
) {
|
||||
if (project.name.endsWith("-server")) {
|
||||
add("api", project(":${project.toothpick.forkNameLowercase}-api"))
|
||||
}
|
||||
return@forEach
|
||||
}
|
||||
|
||||
when (scope) {
|
||||
"compile", null -> add("api", dependencyString)
|
||||
"provided" -> {
|
||||
add("compileOnly", dependencyString)
|
||||
add("testImplementation", dependencyString)
|
||||
}
|
||||
"runtime" -> add("runtimeOnly", dependencyString)
|
||||
"test" -> add("testImplementation", dependencyString)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
import org.gradle.api.Project
|
||||
import task.createApplyPatchesTask
|
||||
import task.createImportMCDevTask
|
||||
import task.createInitGitSubmodulesTask
|
||||
import task.createPaperclipTask
|
||||
import task.createRebuildPatchesTask
|
||||
import task.createSetupUpstreamTask
|
||||
import task.createUpdateUpstreamTask
|
||||
import task.createUpstreamCommitTask
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
internal fun Project.initToothpickTasks() {
|
||||
if (project.hasProperty("fast")) {
|
||||
gradle.taskGraph.whenReady {
|
||||
gradle.taskGraph.allTasks.filter {
|
||||
it.name.contains("test", ignoreCase = true) || it.name.contains("javadoc", ignoreCase = true)
|
||||
}.forEach {
|
||||
it.onlyIf { false }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.getByName("build") {
|
||||
doFirst {
|
||||
val readyToBuild =
|
||||
upstreamDir.resolve(".git").exists()
|
||||
&& toothpick.subprojects.values.all { it.projectDir.exists() && it.baseDir.exists() }
|
||||
if (!readyToBuild) {
|
||||
error("Workspace has not been setup. Try running `./gradlew applyPatches` first")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val initGitSubmodules = createInitGitSubmodulesTask()
|
||||
|
||||
val setupUpstream = createSetupUpstreamTask {
|
||||
dependsOn(initGitSubmodules)
|
||||
}
|
||||
|
||||
val importMCDev = createImportMCDevTask {
|
||||
mustRunAfter(setupUpstream)
|
||||
}
|
||||
|
||||
val paperclip = createPaperclipTask {
|
||||
val shadowJar = toothpick.serverProject.project.tasks.getByName("shadowJar")
|
||||
dependsOn(shadowJar)
|
||||
inputs.file(shadowJar.outputs.files.singleFile)
|
||||
}
|
||||
|
||||
val applyPatches = createApplyPatchesTask {
|
||||
// If Paper has not been setup yet or if we modified the submodule (i.e. upstream update), patch
|
||||
if (!lastUpstream.exists()
|
||||
|| !upstreamDir.resolve(".git").exists()
|
||||
|| lastUpstream.readText() != gitHash(upstreamDir)
|
||||
) {
|
||||
dependsOn(setupUpstream)
|
||||
}
|
||||
mustRunAfter(setupUpstream)
|
||||
dependsOn(importMCDev)
|
||||
}
|
||||
|
||||
val rebuildPatches = createRebuildPatchesTask()
|
||||
|
||||
val updateUpstream = createUpdateUpstreamTask {
|
||||
finalizedBy(setupUpstream)
|
||||
}
|
||||
|
||||
val upstreamCommit = createUpstreamCommitTask()
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/**
|
||||
* This is the set of extra NMS files which will be imported as part of the patch process
|
||||
*
|
||||
* See `./Paper/work/Minecraft/$MCVER/net/minecraft/server` for a list of possible files
|
||||
*
|
||||
* The `.java` extension is always assumed and should be excluded
|
||||
*
|
||||
* NOTE: Do not commit changes to this set! Instead make changes, rebuild patches, and commit the modified patches.
|
||||
* Files already modified in existing patches will be imported automatically.
|
||||
*/
|
||||
val nmsImports = setOf<String>(
|
||||
// ex:
|
||||
//"EntityZombieVillager"
|
||||
)
|
||||
|
||||
data class LibraryImport(val group: String, val library: String, val prefix: String, val file: String)
|
||||
|
||||
/**
|
||||
* This is the set of extra files to import into the server workspace from libraries
|
||||
*
|
||||
* Changes to this set should be committed to the repo, as these won't be automatically imported.
|
||||
*/
|
||||
val libraryImports = setOf<LibraryImport>(
|
||||
LibraryImport("com.mojang", "brigadier", "com/mojang/brigadier", "CommandDispatcher"),
|
||||
LibraryImport("com.mojang", "brigadier", "com/mojang/brigadier/tree", "LiteralCommandNode"),
|
||||
LibraryImport("com.mojang", "brigadier", "com/mojang/brigadier/suggestion", "SuggestionsBuilder"),
|
||||
LibraryImport("com.mojang", "brigadier", "com/mojang/brigadier/arguments", "BoolArgumentType")
|
||||
)
|
||||
@@ -1,9 +0,0 @@
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.kotlin.dsl.create
|
||||
|
||||
class Toothpick : Plugin<Project> {
|
||||
override fun apply(project: Project) {
|
||||
project.extensions.create<ToothpickExtension>("toothpick", project.objects)
|
||||
}
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import java.io.File
|
||||
import java.util.Locale
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
open class ToothpickExtension(objects: ObjectFactory) {
|
||||
lateinit var project: Project
|
||||
lateinit var forkName: String
|
||||
val forkNameLowercase
|
||||
get() = forkName.toLowerCase(Locale.ENGLISH)
|
||||
lateinit var forkUrl: String
|
||||
lateinit var forkVersion: String
|
||||
lateinit var groupId: String
|
||||
lateinit var minecraftVersion: String
|
||||
lateinit var nmsRevision: String
|
||||
lateinit var nmsPackage: String
|
||||
|
||||
lateinit var upstream: String
|
||||
val upstreamLowercase
|
||||
get() = upstream.toLowerCase(Locale.ENGLISH)
|
||||
lateinit var upstreamBranch: String
|
||||
|
||||
var paperclipName: String = ""
|
||||
get(): String = if (field.isEmpty()) {
|
||||
"$forkNameLowercase-paperclip.jar"
|
||||
} else "$field.jar"
|
||||
|
||||
lateinit var serverProject: ToothpickSubproject
|
||||
fun server(receiver: ToothpickSubproject.() -> Unit) {
|
||||
serverProject = ToothpickSubproject()
|
||||
receiver(serverProject)
|
||||
}
|
||||
|
||||
lateinit var apiProject: ToothpickSubproject
|
||||
fun api(receiver: ToothpickSubproject.() -> Unit) {
|
||||
apiProject = ToothpickSubproject()
|
||||
receiver(apiProject)
|
||||
}
|
||||
|
||||
val subprojects: Map<String, ToothpickSubproject>
|
||||
get() = if (::forkName.isInitialized) mapOf(
|
||||
"$forkName-API" to apiProject,
|
||||
"$forkName-Server" to serverProject
|
||||
) else emptyMap()
|
||||
|
||||
val paperDir: File by lazy {
|
||||
if (upstream == "Paper") {
|
||||
project.upstreamDir
|
||||
} else {
|
||||
project.upstreamDir.walk().find {
|
||||
it.name == "Paper" && it.isDirectory
|
||||
&& it.resolve("work/Minecraft/${minecraftVersion}").exists()
|
||||
} ?: error("Failed to find Paper directory!")
|
||||
}
|
||||
}
|
||||
|
||||
val paperWorkDir: File
|
||||
get() = paperDir.resolve("work/Minecraft/${minecraftVersion}")
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.kotlin.dsl.findByType
|
||||
import java.io.File
|
||||
|
||||
val Project.toothpick: ToothpickExtension
|
||||
get() = rootProject.extensions.findByType(ToothpickExtension::class)!!
|
||||
|
||||
fun Project.toothpick(receiver: ToothpickExtension.() -> Unit) {
|
||||
toothpick.project = this
|
||||
receiver(toothpick)
|
||||
allprojects {
|
||||
group = toothpick.groupId
|
||||
version = "${toothpick.minecraftVersion}-${toothpick.nmsRevision}"
|
||||
}
|
||||
configureSubprojects()
|
||||
initToothpickTasks()
|
||||
}
|
||||
|
||||
val Project.lastUpstream: File
|
||||
get() = rootProject.projectDir.resolve("last-${toothpick.upstreamLowercase}")
|
||||
|
||||
val Project.rootProjectDir: File
|
||||
get() = rootProject.projectDir
|
||||
|
||||
val Project.upstreamDir: File
|
||||
get() = rootProject.projectDir.resolve(toothpick.upstream)
|
||||
@@ -1,20 +0,0 @@
|
||||
import org.gradle.api.Project
|
||||
import java.io.File
|
||||
|
||||
class ToothpickSubproject {
|
||||
lateinit var project: Project
|
||||
|
||||
val baseDir: File by lazy {
|
||||
val name = project.name
|
||||
val upstream = project.toothpick.upstream
|
||||
val suffix = if (name.endsWith("server")) "Server" else "API"
|
||||
project.upstreamDir.resolve("$upstream-$suffix")
|
||||
}
|
||||
val projectDir: File
|
||||
get() = project.projectDir
|
||||
lateinit var patchesDir: File
|
||||
|
||||
operator fun component1(): File = baseDir
|
||||
operator fun component2(): File = projectDir
|
||||
operator fun component3(): File = patchesDir
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
import org.gradle.api.Project
|
||||
import java.io.File
|
||||
import java.util.LinkedList
|
||||
import kotlin.streams.asSequence
|
||||
|
||||
data class CmdResult(val exitCode: Int, val output: String?)
|
||||
|
||||
fun Project.cmd(
|
||||
vararg args: String,
|
||||
dir: File = rootProject.projectDir,
|
||||
printOut: Boolean = false
|
||||
): CmdResult {
|
||||
val process = ProcessBuilder()
|
||||
.command(*args)
|
||||
.redirectErrorStream(true)
|
||||
.directory(dir)
|
||||
.start()
|
||||
val output = process.inputStream.bufferedReader().use { reader ->
|
||||
reader.lines().asSequence()
|
||||
.onEach {
|
||||
if (printOut) {
|
||||
logger.lifecycle(it)
|
||||
} else {
|
||||
logger.debug(it)
|
||||
}
|
||||
}
|
||||
.toCollection(LinkedList())
|
||||
.joinToString(separator = "\n")
|
||||
}
|
||||
val exit = process.waitFor()
|
||||
return CmdResult(exit, output)
|
||||
}
|
||||
|
||||
fun ensureSuccess(
|
||||
cmd: CmdResult,
|
||||
errorHandler: CmdResult.() -> Unit = {}
|
||||
): String? {
|
||||
val (exit, output) = cmd
|
||||
if (exit != 0) {
|
||||
errorHandler(cmd)
|
||||
error("Failed to run command, exit code is $exit")
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
fun Project.gitCmd(
|
||||
vararg args: String,
|
||||
dir: File = rootProject.projectDir,
|
||||
printOut: Boolean = false
|
||||
): CmdResult =
|
||||
cmd("git", *args, dir = dir, printOut = printOut)
|
||||
|
||||
fun Project.bashCmd(
|
||||
vararg args: String,
|
||||
dir: File = rootProject.projectDir,
|
||||
printOut: Boolean = false
|
||||
): CmdResult =
|
||||
cmd("bash", "-c", *args, dir = dir, printOut = printOut)
|
||||
|
||||
internal fun String.applyReplacements(
|
||||
vararg replacements: Pair<String, String>
|
||||
): String {
|
||||
var result = this
|
||||
for ((key, value) in replacements) {
|
||||
result = result.replace("\${$key}", value)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun Project.gitSigningEnabled(repo: File): Boolean =
|
||||
gitCmd("config", "commit.gpgsign", dir = repo).output?.toBoolean() == true
|
||||
|
||||
internal fun Project.temporarilyDisableGitSigning(repo: File): Boolean {
|
||||
val isCurrentlyEnabled = gitSigningEnabled(repo)
|
||||
if (isCurrentlyEnabled) {
|
||||
gitCmd("config", "commit.gpgsign", "false", dir = repo)
|
||||
}
|
||||
return isCurrentlyEnabled
|
||||
}
|
||||
|
||||
internal fun Project.reEnableGitSigning(repo: File) {
|
||||
gitCmd("config", "commit.gpgsign", "true", dir = repo)
|
||||
}
|
||||
|
||||
fun Project.gitHash(repo: File): String =
|
||||
gitCmd("rev-parse", "HEAD", dir = repo).output ?: ""
|
||||
|
||||
val jenkins = System.getenv("JOB_NAME") != null
|
||||
@@ -1,53 +0,0 @@
|
||||
package task
|
||||
|
||||
import ensureSuccess
|
||||
import gitCmd
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import reEnableGitSigning
|
||||
import taskGroup
|
||||
import temporarilyDisableGitSigning
|
||||
import toothpick
|
||||
import java.nio.file.Files
|
||||
|
||||
internal fun Project.createApplyPatchesTask(
|
||||
receiver: Task.() -> Unit = {}
|
||||
): Task = tasks.create("applyPatches") {
|
||||
receiver(this)
|
||||
group = taskGroup
|
||||
doLast {
|
||||
for ((name, subproject) in toothpick.subprojects) {
|
||||
val (sourceRepo, projectDir, patchesDir) = subproject
|
||||
|
||||
// Reset or initialize subproject
|
||||
logger.lifecycle(">>> Resetting subproject $name")
|
||||
if (projectDir.exists()) {
|
||||
ensureSuccess(gitCmd("fetch", "origin", dir = projectDir))
|
||||
ensureSuccess(gitCmd("reset", "--hard", "origin/master", dir = projectDir))
|
||||
} else {
|
||||
ensureSuccess(gitCmd("clone", sourceRepo.absolutePath, projectDir.absolutePath))
|
||||
}
|
||||
logger.lifecycle(">>> Done resetting subproject $name")
|
||||
|
||||
// Apply patches
|
||||
val patchPaths = Files.newDirectoryStream(patchesDir.toPath())
|
||||
.map { it.toFile() }
|
||||
.filter { it.name.endsWith(".patch") }
|
||||
.sorted()
|
||||
.takeIf { it.isNotEmpty() } ?: continue
|
||||
val patches = patchPaths.map { it.absolutePath }.toTypedArray()
|
||||
|
||||
val wasGitSigningEnabled = temporarilyDisableGitSigning(projectDir)
|
||||
|
||||
logger.lifecycle(">>> Applying patches to $name")
|
||||
|
||||
val gitCommand = arrayListOf("am", "--3way", "--ignore-whitespace", *patches)
|
||||
ensureSuccess(gitCmd(*gitCommand.toTypedArray(), dir = projectDir, printOut = true)) {
|
||||
if (wasGitSigningEnabled) reEnableGitSigning(projectDir)
|
||||
}
|
||||
|
||||
if (wasGitSigningEnabled) reEnableGitSigning(projectDir)
|
||||
logger.lifecycle(">>> Done applying patches to $name")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
package task
|
||||
|
||||
import LibraryImport
|
||||
import ensureSuccess
|
||||
import gitCmd
|
||||
import internalTaskGroup
|
||||
import libraryImports
|
||||
import nmsImports
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import toothpick
|
||||
|
||||
internal fun Project.createImportMCDevTask(
|
||||
receiver: Task.() -> Unit = {}
|
||||
): Task = tasks.create("importMCDev") {
|
||||
receiver(this)
|
||||
group = internalTaskGroup
|
||||
val upstreamServer = toothpick.serverProject.baseDir
|
||||
val importLog = arrayListOf("Extra mc-dev imports")
|
||||
|
||||
fun importNMS(className: String) {
|
||||
logger.lifecycle("Importing n.m.s.$className")
|
||||
importLog.add("Imported n.m.s.$className")
|
||||
val source = toothpick.paperWorkDir.resolve("spigot/net/minecraft/server/$className.java")
|
||||
if (!source.exists()) error("Missing NMS: $className")
|
||||
val target = upstreamServer.resolve("src/main/java/net/minecraft/server/$className.java")
|
||||
source.copyTo(target)
|
||||
}
|
||||
|
||||
fun importLibrary(import: LibraryImport) {
|
||||
val (group, lib, prefix, file) = import
|
||||
logger.lifecycle("Importing $group.$lib $prefix/$file")
|
||||
importLog.add("Imported $group.$lib $prefix/$file")
|
||||
val source = toothpick.paperWorkDir.resolve("libraries/$group/$lib/$prefix/$file.java")
|
||||
if (!source.exists()) error("Missing Base: $lib $prefix/$file")
|
||||
val targetDir = upstreamServer.resolve("src/main/java/$prefix")
|
||||
val target = targetDir.resolve("$file.java")
|
||||
targetDir.mkdirs()
|
||||
source.copyTo(target)
|
||||
}
|
||||
|
||||
doLast {
|
||||
logger.lifecycle(">>> Importing mc-dev")
|
||||
val lastCommitIsMCDev = gitCmd(
|
||||
"log", "-1", "--oneline",
|
||||
dir = upstreamServer
|
||||
).output?.contains("Extra mc-dev imports") == true
|
||||
if (lastCommitIsMCDev) {
|
||||
ensureSuccess(
|
||||
gitCmd(
|
||||
"reset", "--hard", "HEAD~1",
|
||||
dir = upstreamServer,
|
||||
printOut = true
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
(toothpick.serverProject.patchesDir.listFiles() ?: error("No patches in server?")).asSequence()
|
||||
.flatMap { it.readLines().asSequence() }
|
||||
.filter { it.startsWith("+++ b/src/main/java/net/minecraft/server/") }
|
||||
.distinct()
|
||||
.map { it.substringAfter("/server/").substringBefore(".java") }
|
||||
.filter { !upstreamServer.resolve("src/main/java/net/minecraft/server/$it.java").exists() }
|
||||
.map { toothpick.paperWorkDir.resolve("spigot/net/minecraft/server/$it.java") }
|
||||
.filter {
|
||||
val exists = it.exists()
|
||||
if (!it.exists()) logger.lifecycle("NMS ${it.nameWithoutExtension} is either missing, or is a new file added through a patch")
|
||||
exists
|
||||
}
|
||||
.map { it.nameWithoutExtension }
|
||||
.forEach(::importNMS)
|
||||
|
||||
// Imports from MCDevImports.kt
|
||||
nmsImports.forEach(::importNMS)
|
||||
libraryImports.forEach(::importLibrary)
|
||||
|
||||
val add = gitCmd("add", ".", "-A", dir = upstreamServer).exitCode == 0
|
||||
val commit = gitCmd("commit", "-m", importLog.joinToString("\n"), dir = upstreamServer).exitCode == 0
|
||||
if (!add || !commit) {
|
||||
logger.lifecycle(">>> Didn't import any extra files")
|
||||
}
|
||||
logger.lifecycle(">>> Done importing mc-dev")
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package task
|
||||
|
||||
import gitCmd
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import taskGroup
|
||||
import upstreamDir
|
||||
|
||||
internal fun Project.createInitGitSubmodulesTask(
|
||||
receiver: Task.() -> Unit = {}
|
||||
): Task = tasks.create("initGitSubmodules") {
|
||||
receiver(this)
|
||||
group = taskGroup
|
||||
onlyIf { !upstreamDir.resolve(".git").exists() }
|
||||
doLast {
|
||||
val exit = gitCmd("submodule", "update", "--init", "--recursive", printOut = true).exitCode
|
||||
if (exit != 0) {
|
||||
error("Failed to checkout git submodules: git exited with code $exit")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package task
|
||||
|
||||
import cmd
|
||||
import ensureSuccess
|
||||
import jenkins
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import rootProjectDir
|
||||
import taskGroup
|
||||
import toothpick
|
||||
|
||||
internal fun Project.createPaperclipTask(
|
||||
receiver: Task.() -> Unit = {}
|
||||
): Task = tasks.create("paperclip") {
|
||||
receiver(this)
|
||||
group = taskGroup
|
||||
doLast {
|
||||
val workDir = toothpick.paperDir.resolve("work")
|
||||
val paperclipDir = workDir.resolve("Paperclip")
|
||||
val vanillaJarPath =
|
||||
workDir.resolve("Minecraft/${toothpick.minecraftVersion}/${toothpick.minecraftVersion}.jar").absolutePath
|
||||
val patchedJarPath = inputs.files.singleFile.absolutePath
|
||||
logger.lifecycle(">>> Building paperclip")
|
||||
val paperclipCmd = arrayListOf(
|
||||
"mvn", "clean", "package",
|
||||
"-Dmcver=${toothpick.minecraftVersion}",
|
||||
"-Dpaperjar=$patchedJarPath",
|
||||
"-Dvanillajar=$vanillaJarPath"
|
||||
)
|
||||
if (jenkins) paperclipCmd.add("-Dstyle.color=never")
|
||||
ensureSuccess(cmd(*paperclipCmd.toTypedArray(), dir = paperclipDir, printOut = true))
|
||||
val paperClip = paperclipDir.resolve("assembly/target/paperclip-${toothpick.minecraftVersion}.jar")
|
||||
val destination = rootProjectDir.resolve(toothpick.paperclipName)
|
||||
paperClip.copyTo(destination, overwrite = true)
|
||||
logger.lifecycle(">>> ${toothpick.paperclipName} saved to root project directory")
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package task
|
||||
|
||||
import ensureSuccess
|
||||
import gitCmd
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import taskGroup
|
||||
import toothpick
|
||||
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
internal fun Project.createRebuildPatchesTask(
|
||||
receiver: Task.() -> Unit = {}
|
||||
): Task = tasks.create("rebuildPatches") {
|
||||
receiver(this)
|
||||
group = taskGroup
|
||||
doLast {
|
||||
for ((name, subproject) in toothpick.subprojects) {
|
||||
val (sourceRepo, projectDir, patchesDir) = subproject
|
||||
|
||||
if (!patchesDir.exists()) {
|
||||
patchesDir.mkdirs()
|
||||
}
|
||||
|
||||
logger.lifecycle(">>> Rebuilding patches for $name")
|
||||
|
||||
// Nuke old patches
|
||||
patchesDir.listFiles()
|
||||
?.filter { it.name.endsWith(".patch") }
|
||||
?.forEach { it.delete() }
|
||||
|
||||
// And generate new
|
||||
ensureSuccess(
|
||||
gitCmd(
|
||||
"format-patch",
|
||||
"--no-stat", "--zero-commit", "--full-index", "--no-signature", "-N",
|
||||
"-o", patchesDir.absolutePath, "origin/master",
|
||||
dir = projectDir,
|
||||
printOut = true
|
||||
)
|
||||
)
|
||||
|
||||
logger.lifecycle(">>> Done rebuilding patches for $name")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package task
|
||||
|
||||
import bashCmd
|
||||
import gitHash
|
||||
import lastUpstream
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import taskGroup
|
||||
import toothpick
|
||||
import upstreamDir
|
||||
|
||||
internal fun Project.createSetupUpstreamTask(
|
||||
receiver: Task.() -> Unit = {}
|
||||
): Task = tasks.create("setupUpstream") {
|
||||
receiver(this)
|
||||
group = taskGroup
|
||||
doLast {
|
||||
val setupUpstreamCommand = if (upstreamDir.resolve(toothpick.upstreamLowercase).exists()) {
|
||||
"./${toothpick.upstreamLowercase} patch"
|
||||
} else if (
|
||||
upstreamDir.resolve("build.gradle.kts").exists()
|
||||
&& upstreamDir.resolve("subprojects/server.gradle.kts").exists()
|
||||
&& upstreamDir.resolve("subprojects/api.gradle.kts").exists()
|
||||
) {
|
||||
"./gradlew applyPatches"
|
||||
} else {
|
||||
error("Don't know how to setup upstream!")
|
||||
}
|
||||
val result = bashCmd(setupUpstreamCommand, dir = upstreamDir, printOut = true)
|
||||
if (result.exitCode != 0) {
|
||||
error("Failed to apply upstream patches: script exited with code ${result.exitCode}")
|
||||
}
|
||||
lastUpstream.writeText(gitHash(upstreamDir))
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package task
|
||||
|
||||
import ensureSuccess
|
||||
import gitCmd
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import rootProjectDir
|
||||
import taskGroup
|
||||
import toothpick
|
||||
import upstreamDir
|
||||
|
||||
internal fun Project.createUpdateUpstreamTask(
|
||||
receiver: Task.() -> Unit = {}
|
||||
): Task = tasks.create("updateUpstream") {
|
||||
receiver(this)
|
||||
group = taskGroup
|
||||
doLast {
|
||||
ensureSuccess(gitCmd("fetch", dir = upstreamDir, printOut = true))
|
||||
ensureSuccess(gitCmd("reset", "--hard", toothpick.upstreamBranch, dir = upstreamDir, printOut = true))
|
||||
ensureSuccess(gitCmd("add", toothpick.upstream, dir = rootProjectDir, printOut = true))
|
||||
ensureSuccess(gitCmd("submodule", "update", "--init", "--recursive", dir = upstreamDir, printOut = true))
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package task
|
||||
|
||||
import ensureSuccess
|
||||
import gitCmd
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import taskGroup
|
||||
import toothpick
|
||||
import upstreamDir
|
||||
|
||||
internal fun Project.createUpstreamCommitTask(
|
||||
receiver: Task.() -> Unit = {}
|
||||
): Task = tasks.create("upstreamCommit") {
|
||||
receiver(this)
|
||||
group = taskGroup
|
||||
doLast {
|
||||
val oldRev = ensureSuccess(gitCmd("ls-tree", "HEAD", toothpick.upstream))
|
||||
?.substringAfter("commit ")?.substringBefore("\t")
|
||||
val gitChangelog =
|
||||
ensureSuccess(gitCmd("log", "--oneline", "$oldRev...HEAD", printOut = true, dir = upstreamDir)) {
|
||||
logger.lifecycle("No upstream changes to commit?")
|
||||
}
|
||||
val commitMessage = """
|
||||
|Updated Upstream (${toothpick.upstream})
|
||||
|
|
||||
|Upstream has released updates that appear to apply and compile correctly
|
||||
|
|
||||
|${toothpick.upstream} Changes:
|
||||
|$gitChangelog
|
||||
""".trimMargin()
|
||||
ensureSuccess(gitCmd("commit", "-m", commitMessage, printOut = true))
|
||||
}
|
||||
}
|
||||
29
mcdevimports.json
Normal file
29
mcdevimports.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"nmsImports": [],
|
||||
"libraryImports": [
|
||||
{
|
||||
"group": "com.mojang",
|
||||
"library": "brigadier",
|
||||
"prefix": "com/mojang/brigadier",
|
||||
"file": "CommandDispatcher"
|
||||
},
|
||||
{
|
||||
"group": "com.mojang",
|
||||
"library": "brigadier",
|
||||
"prefix": "com/mojang/brigadier/tree",
|
||||
"file": "LiteralCommandNode"
|
||||
},
|
||||
{
|
||||
"group": "com.mojang",
|
||||
"library": "brigadier",
|
||||
"prefix": "com/mojang/brigadier/suggestion",
|
||||
"file": "SuggestionsBuilder"
|
||||
},
|
||||
{
|
||||
"group": "com.mojang",
|
||||
"library": "brigadier",
|
||||
"prefix": "com/mojang/brigadier/arguments",
|
||||
"file": "BoolArgumentType"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,5 +1,13 @@
|
||||
import java.util.Locale
|
||||
|
||||
pluginManagement {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
jcenter()
|
||||
maven("https://repo.jpenilla.xyz/snapshots")
|
||||
}
|
||||
}
|
||||
|
||||
val forkName = "Purpur"
|
||||
val forkNameLowercase = forkName.toLowerCase(Locale.ENGLISH)
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import xyz.jpenilla.toothpick.loadDependencies
|
||||
import xyz.jpenilla.toothpick.loadRepositories
|
||||
|
||||
repositories {
|
||||
loadRepositories(project)
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import xyz.jpenilla.toothpick.loadDependencies
|
||||
import xyz.jpenilla.toothpick.loadRepositories
|
||||
|
||||
repositories {
|
||||
loadRepositories(project)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user