Update Toothpick

This commit is contained in:
jmp
2021-01-19 19:56:37 -08:00
parent 7e8bf667fa
commit cd18335858
24 changed files with 47 additions and 888 deletions

View File

@@ -1,7 +1,10 @@
import xyz.jpenilla.toothpick.gitCmd
import xyz.jpenilla.toothpick.toothpick
plugins { plugins {
`java-library` `java-library`
`maven-publish` `maven-publish`
toothpick id("xyz.jpenilla.toothpick") version "1.0.0-SNAPSHOT"
} }
toothpick { toothpick {

View File

@@ -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"
}
}
}

View File

@@ -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"])
}
}
}
}

View File

@@ -1,2 +0,0 @@
const val taskGroup = "toothpick"
const val internalTaskGroup = "toothpick_internal"

View File

@@ -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)
}
}
}

View File

@@ -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()
}

View File

@@ -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")
)

View File

@@ -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)
}
}

View File

@@ -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}")
}

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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

View File

@@ -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")
}
}
}

View File

@@ -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")
}
}

View File

@@ -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")
}
}
}

View File

@@ -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")
}
}

View File

@@ -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")
}
}
}

View File

@@ -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))
}
}

View File

@@ -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))
}
}

View File

@@ -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
View 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"
}
]
}

View File

@@ -1,5 +1,13 @@
import java.util.Locale import java.util.Locale
pluginManagement {
repositories {
mavenCentral()
jcenter()
maven("https://repo.jpenilla.xyz/snapshots")
}
}
val forkName = "Purpur" val forkName = "Purpur"
val forkNameLowercase = forkName.toLowerCase(Locale.ENGLISH) val forkNameLowercase = forkName.toLowerCase(Locale.ENGLISH)

View File

@@ -1,3 +1,6 @@
import xyz.jpenilla.toothpick.loadDependencies
import xyz.jpenilla.toothpick.loadRepositories
repositories { repositories {
loadRepositories(project) loadRepositories(project)
} }

View File

@@ -1,3 +1,6 @@
import xyz.jpenilla.toothpick.loadDependencies
import xyz.jpenilla.toothpick.loadRepositories
repositories { repositories {
loadRepositories(project) loadRepositories(project)
} }