Compare commits
5 commits
main
...
softspoon-
Author | SHA1 | Date | |
---|---|---|---|
|
aa75f2bbcf | ||
|
005e051b3c | ||
|
d569f38cef | ||
|
4564fe8a2d | ||
|
2d425efdef |
100 changed files with 3346 additions and 76 deletions
|
@ -83,3 +83,9 @@ ij_kotlin_field_annotation_wrap = split_into_lines
|
|||
ij_kotlin_finally_on_new_line = false
|
||||
ij_kotlin_if_rparen_on_new_line = true
|
||||
ij_kotlin_import_nested_classes = false
|
||||
|
||||
[*.patch]
|
||||
trim_trailing_whitespace=false
|
||||
|
||||
[*.patch]
|
||||
trim_trailing_whitespace=false
|
||||
|
|
4
.github/workflows/deploy-snapshot.yml
vendored
4
.github/workflows/deploy-snapshot.yml
vendored
|
@ -1,7 +1,7 @@
|
|||
name: Deploy Snapshot
|
||||
on:
|
||||
push:
|
||||
branches: [ 'main' ]
|
||||
branches: [ 'main', 'softspoon-v2' ]
|
||||
paths-ignore:
|
||||
- 'license/*'
|
||||
- 'readme.md'
|
||||
|
@ -29,7 +29,7 @@ jobs:
|
|||
echo version=$project_version >> $GITHUB_OUTPUT
|
||||
- name: Deploy snapshot version
|
||||
if: endsWith(steps.get_version.outputs.version, '-SNAPSHOT')
|
||||
run: ./gradlew -Dorg.gradle.parallel=true publish --no-daemon --stacktrace
|
||||
run: ./gradlew -Dorg.gradle.parallel=true publish --no-daemon --stacktrace -Dorg.gradle.internal.http.socketTimeout=90000 -Dorg.gradle.internal.http.connectionTimeout=90000
|
||||
env:
|
||||
ORG_GRADLE_PROJECT_paperUsername: ${{ secrets.DEPLOY_USER }}
|
||||
ORG_GRADLE_PROJECT_paperPassword: ${{ secrets.DEPLOY_PASS }}
|
||||
|
|
12
.github/workflows/test.yml
vendored
12
.github/workflows/test.yml
vendored
|
@ -19,4 +19,14 @@ jobs:
|
|||
- name: Setup Gradle
|
||||
uses: gradle/gradle-build-action@v2
|
||||
- name: Execute Gradle build
|
||||
run: ./gradlew build --no-daemon --stacktrace
|
||||
run: |
|
||||
git config --global user.email "no-reply@github.com"
|
||||
git config --global user.name "GitHub Actions"
|
||||
./gradlew build --no-daemon --stacktrace
|
||||
- name: Publish Test Report
|
||||
uses: mikepenz/action-junit-report@v4
|
||||
if: always()
|
||||
with:
|
||||
report_paths: '**/build/test-results/test/TEST-*.xml'
|
||||
detailed_summary: true
|
||||
annotate_notice: true
|
||||
|
|
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -43,3 +43,8 @@ ehthumbs_vista.db
|
|||
|
||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||
!gradle-wrapper.ja
|
||||
|
||||
/test/
|
||||
/testpaper/
|
||||
/testfork/
|
||||
/testhistory/
|
||||
|
|
|
@ -11,7 +11,7 @@ java {
|
|||
}
|
||||
|
||||
tasks.withType(JavaCompile::class).configureEach {
|
||||
options.release = 11
|
||||
options.release = 17
|
||||
}
|
||||
|
||||
kotlin {
|
||||
|
@ -21,14 +21,15 @@ kotlin {
|
|||
target {
|
||||
compilations.configureEach {
|
||||
kotlinOptions {
|
||||
jvmTarget = "11"
|
||||
freeCompilerArgs = listOf("-Xjvm-default=all", "-Xjdk-release=11")
|
||||
jvmTarget = "17"
|
||||
freeCompilerArgs = listOf("-Xjvm-default=all", "-Xjdk-release=17", "-opt-in=kotlin.io.path.ExperimentalPathApi")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal() // TODO remove again
|
||||
maven("https://repo.papermc.io/repository/maven-snapshots/") {
|
||||
mavenContent {
|
||||
includeModule("org.cadixdev", "mercury")
|
||||
|
@ -38,6 +39,28 @@ repositories {
|
|||
mavenContent {
|
||||
includeGroup("codechicken")
|
||||
includeGroup("net.fabricmc")
|
||||
includeGroupAndSubgroups("io.papermc")
|
||||
}
|
||||
}
|
||||
maven("https://maven.parchmentmc.org") {
|
||||
name = "ParchmentMC"
|
||||
mavenContent {
|
||||
releasesOnly()
|
||||
includeGroupAndSubgroups("org.parchmentmc")
|
||||
}
|
||||
}
|
||||
maven("https://maven.neoforged.net/releases") {
|
||||
name = "NeoForged"
|
||||
mavenContent {
|
||||
releasesOnly()
|
||||
includeGroupAndSubgroups("net.neoforged")
|
||||
}
|
||||
}
|
||||
maven("https://maven.fabricmc.net") {
|
||||
name = "FabricMC"
|
||||
mavenContent {
|
||||
releasesOnly()
|
||||
includeGroupAndSubgroups("net.fabricmc")
|
||||
}
|
||||
}
|
||||
mavenCentral()
|
||||
|
@ -55,6 +78,7 @@ testing {
|
|||
useKotlinTest(embeddedKotlinVersion)
|
||||
dependencies {
|
||||
implementation("org.junit.jupiter:junit-jupiter-engine:5.10.1")
|
||||
implementation("org.junit.platform:junit-platform-launcher:1.10.1")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
group = io.papermc.paperweight
|
||||
version = 1.7.2-SNAPSHOT
|
||||
version = 2.0.0-SNAPSHOT
|
||||
|
||||
org.gradle.caching = true
|
||||
org.gradle.parallel = true
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
[versions]
|
||||
asm = "9.7"
|
||||
lorenz = "0.5.8"
|
||||
hypo = "1.2.4"
|
||||
hypo = "2.3.0"
|
||||
serialize = "1.5.1"
|
||||
feather = "1.1.0"
|
||||
|
||||
[libraries]
|
||||
asm-core = { module = "org.ow2.asm:asm", version.ref = "asm" }
|
||||
|
@ -9,6 +11,8 @@ asm-tree = { module = "org.ow2.asm:asm-tree", version.ref = "asm" }
|
|||
|
||||
httpclient = "org.apache.httpcomponents:httpclient:4.5.14"
|
||||
kotson = "com.github.salomonbrys.kotson:kotson:2.5.0"
|
||||
coroutines = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.2"
|
||||
jgit = "org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r"
|
||||
gson = "com.google.code.gson:gson:2.10.1"
|
||||
|
||||
cadix-lorenz-core = { module = "org.cadixdev:lorenz", version.ref = "lorenz" }
|
||||
|
@ -16,7 +20,9 @@ cadix-lorenz-asm = { module = "org.cadixdev:lorenz-asm", version.ref = "lorenz"
|
|||
cadix-lorenz-proguard = { module = "org.cadixdev:lorenz-io-proguard", version.ref = "lorenz" }
|
||||
cadix-atlas = "org.cadixdev:atlas:0.2.1"
|
||||
cadix-at = "org.cadixdev:at:0.1.0-rc1"
|
||||
#cadix-mercury = "org.cadixdev:mercury:0.1.2-paperweight-local-SNAPSHOT" # todo local mods for patch remapping
|
||||
cadix-mercury = "org.cadixdev:mercury:0.1.2-paperweight-SNAPSHOT"
|
||||
cadix-bombe-jar = "org.cadixdev:bombe-jar:0.4.4"
|
||||
|
||||
hypo-model = { module = "dev.denwav.hypo:hypo-model", version.ref = "hypo" }
|
||||
hypo-core = { module = "dev.denwav.hypo:hypo-core", version.ref = "hypo" }
|
||||
|
@ -29,7 +35,18 @@ slf4j-jdk14 = "org.slf4j:slf4j-jdk14:1.7.32"
|
|||
lorenzTiny = "net.fabricmc:lorenz-tiny:3.0.0"
|
||||
jbsdiff = "io.sigpipe:jbsdiff:1.0"
|
||||
|
||||
diffpatch = "codechicken:DiffPatch:1.5.0.29"
|
||||
feather-core = { module = "org.parchmentmc:feather", version.ref = "feather" }
|
||||
feather-gson = { module = "org.parchmentmc.feather:io-gson", version.ref = "feather" }
|
||||
|
||||
diffpatch = "codechicken:DiffPatch:1.5.0.30"
|
||||
|
||||
serialize-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "serialize" }
|
||||
serialize-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialize" }
|
||||
|
||||
restamp = "io.papermc.restamp:restamp:1.1.1-SNAPSHOT"
|
||||
|
||||
# test
|
||||
mockk = "io.mockk:mockk:1.13.8"
|
||||
|
||||
# Gradle
|
||||
gradle-licenser = "net.kyori:indra-licenser-spotless:3.1.3"
|
||||
|
@ -41,6 +58,6 @@ gradle-plugin-publish = "com.gradle.publish:plugin-publish-plugin:1.2.1"
|
|||
|
||||
[bundles]
|
||||
asm = ["asm-core", "asm-tree"]
|
||||
cadix = ["cadix-lorenz-core", "cadix-lorenz-asm", "cadix-lorenz-proguard", "cadix-atlas", "cadix-at", "cadix-mercury"]
|
||||
cadix = ["cadix-lorenz-core", "cadix-lorenz-asm", "cadix-lorenz-proguard", "cadix-atlas", "cadix-at", "cadix-mercury", "cadix-bombe-jar"]
|
||||
hypo = ["hypo-model", "hypo-core", "hypo-hydrate", "hypo-asm-core", "hypo-asm-hydrate", "hypo-mappings"]
|
||||
kotson = ["kotson", "gson"]
|
||||
|
|
|
@ -7,6 +7,7 @@ dependencies {
|
|||
shade(projects.paperweightLib)
|
||||
|
||||
implementation(libs.bundles.kotson)
|
||||
implementation(libs.coroutines)
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
|
|
|
@ -25,6 +25,7 @@ package io.papermc.paperweight.core
|
|||
import io.papermc.paperweight.DownloadService
|
||||
import io.papermc.paperweight.core.extension.PaperweightCoreExtension
|
||||
import io.papermc.paperweight.core.taskcontainers.AllTasks
|
||||
import io.papermc.paperweight.core.taskcontainers.SoftSpoonTasks
|
||||
import io.papermc.paperweight.core.tasks.PaperweightCorePrepareForDownstream
|
||||
import io.papermc.paperweight.taskcontainers.BundlerJarTasks
|
||||
import io.papermc.paperweight.taskcontainers.DevBundleTasks
|
||||
|
@ -53,7 +54,9 @@ class PaperweightCore : Plugin<Project> {
|
|||
|
||||
val ext = target.extensions.create(PAPERWEIGHT_EXTENSION, PaperweightCoreExtension::class, target)
|
||||
|
||||
target.gradle.sharedServices.registerIfAbsent(DOWNLOAD_SERVICE_NAME, DownloadService::class) {}
|
||||
target.gradle.sharedServices.registerIfAbsent(DOWNLOAD_SERVICE_NAME, DownloadService::class) {
|
||||
parameters.projectPath.set(target.projectDir)
|
||||
}
|
||||
|
||||
target.tasks.register<Delete>("cleanCache") {
|
||||
group = "paper"
|
||||
|
@ -69,6 +72,7 @@ class PaperweightCore : Plugin<Project> {
|
|||
target.configurations.create(REMAPPER_CONFIG)
|
||||
target.configurations.create(DECOMPILER_CONFIG)
|
||||
target.configurations.create(PAPERCLIP_CONFIG)
|
||||
target.configurations.create(MACHE_CONFIG)
|
||||
|
||||
if (target.providers.gradleProperty("paperweight.dev").orNull == "true") {
|
||||
target.tasks.register<CreateDiffOutput>("diff") {
|
||||
|
@ -90,10 +94,12 @@ class PaperweightCore : Plugin<Project> {
|
|||
ext.mainClass
|
||||
)
|
||||
|
||||
val softSpoonTasks = SoftSpoonTasks(target, tasks)
|
||||
|
||||
target.createPatchRemapTask(tasks)
|
||||
|
||||
target.tasks.register<PaperweightCorePrepareForDownstream>(PAPERWEIGHT_PREPARE_DOWNSTREAM) {
|
||||
dependsOn(tasks.applyPatches)
|
||||
dependsOn(tasks.applyPatchesLegacy)
|
||||
vanillaJar.set(tasks.downloadServerJar.flatMap { it.outputJar })
|
||||
remappedJar.set(tasks.lineMapJar.flatMap { it.outputJar })
|
||||
decompiledJar.set(tasks.decompileJar.flatMap { it.outputJar })
|
||||
|
@ -124,21 +130,35 @@ class PaperweightCore : Plugin<Project> {
|
|||
}
|
||||
|
||||
target.afterEvaluate {
|
||||
println("SoftSpoon: ${ext.softSpoon.get()}")
|
||||
|
||||
target.repositories {
|
||||
maven(ext.paramMappingsRepo) {
|
||||
name = PARAM_MAPPINGS_REPO_NAME
|
||||
content { onlyForConfigurations(PARAM_MAPPINGS_CONFIG) }
|
||||
}
|
||||
maven(ext.remapRepo) {
|
||||
name = REMAPPER_REPO_NAME
|
||||
content { onlyForConfigurations(REMAPPER_CONFIG) }
|
||||
}
|
||||
maven(ext.decompileRepo) {
|
||||
name = DECOMPILER_REPO_NAME
|
||||
content { onlyForConfigurations(DECOMPILER_CONFIG) }
|
||||
if (!ext.softSpoon.get()) {
|
||||
maven(ext.paramMappingsRepo) {
|
||||
name = PARAM_MAPPINGS_REPO_NAME
|
||||
content { onlyForConfigurations(PARAM_MAPPINGS_CONFIG) }
|
||||
}
|
||||
maven(ext.remapRepo) {
|
||||
name = REMAPPER_REPO_NAME
|
||||
content { onlyForConfigurations(REMAPPER_CONFIG) }
|
||||
}
|
||||
maven(ext.decompileRepo) {
|
||||
name = DECOMPILER_REPO_NAME
|
||||
content { onlyForConfigurations(DECOMPILER_CONFIG) }
|
||||
}
|
||||
} else {
|
||||
maven(ext.macheRepo) {
|
||||
name = MACHE_REPO_NAME
|
||||
content { onlyForConfigurations(MACHE_CONFIG) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ext.softSpoon.get()) {
|
||||
softSpoonTasks.afterEvaluate()
|
||||
return@afterEvaluate
|
||||
}
|
||||
|
||||
// Setup the server jar
|
||||
val cache = target.layout.cache
|
||||
|
||||
|
|
|
@ -38,8 +38,11 @@ open class PaperExtension(objects: ObjectFactory, layout: ProjectLayout) {
|
|||
val spigotServerPatchDir: DirectoryProperty = objects.dirFrom(baseTargetDir, "patches/server")
|
||||
val remappedSpigotServerPatchDir: DirectoryProperty = objects.dirFrom(baseTargetDir, "patches/server-remapped")
|
||||
val unmappedSpigotServerPatchDir: DirectoryProperty = objects.dirFrom(baseTargetDir, "patches/server-unmapped")
|
||||
val paperApiDir: DirectoryProperty = objects.dirFrom(baseTargetDir, "Paper-API")
|
||||
val paperServerDir: DirectoryProperty = objects.dirFrom(baseTargetDir, "Paper-Server")
|
||||
val paperApiDir: DirectoryProperty = objects.dirFrom(baseTargetDir, "paper-api")
|
||||
val paperServerDir: DirectoryProperty = objects.dirFrom(baseTargetDir, "paper-server")
|
||||
val sourcePatchDir: DirectoryProperty = objects.dirFrom(paperServerDir, "patches/sources")
|
||||
val resourcePatchDir: DirectoryProperty = objects.dirFrom(paperServerDir, "patches/resources")
|
||||
val featurePatchDir: DirectoryProperty = objects.dirFrom(paperServerDir, "patches/feature")
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
val buildDataDir: DirectoryProperty = objects.dirWithDefault(layout, "build-data")
|
||||
|
|
|
@ -36,10 +36,13 @@ import org.gradle.kotlin.dsl.*
|
|||
|
||||
open class PaperweightCoreExtension(project: Project, objects: ObjectFactory, layout: ProjectLayout) {
|
||||
|
||||
val softSpoon: Property<Boolean> = objects.property<Boolean>().convention(false)
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
val workDir: DirectoryProperty = objects.dirWithDefault(layout, "work")
|
||||
|
||||
val minecraftVersion: Property<String> = objects.property()
|
||||
val minecraftManifestUrl: Property<String> = objects.property<String>().convention(MC_MANIFEST_URL)
|
||||
val serverProject: Property<Project> = objects.property()
|
||||
|
||||
val mainClass: Property<String> = objects.property<String>().convention("org.bukkit.craftbukkit.Main")
|
||||
|
@ -50,6 +53,7 @@ open class PaperweightCoreExtension(project: Project, objects: ObjectFactory, la
|
|||
val paramMappingsRepo: Property<String> = objects.property()
|
||||
val decompileRepo: Property<String> = objects.property()
|
||||
val remapRepo: Property<String> = objects.property()
|
||||
val macheRepo: Property<String> = objects.property<String>().convention("https://repo.papermc.io/repository/maven-public/")
|
||||
|
||||
val vanillaJarIncludes: ListProperty<String> = objects.listProperty<String>().convention(
|
||||
listOf("/*.class", "/net/minecraft/**", "/com/mojang/math/**")
|
||||
|
|
|
@ -101,6 +101,23 @@ open class AllTasks(
|
|||
downloader.set(downloadService)
|
||||
}
|
||||
|
||||
val downloadPaperLibrariesSources by tasks.registering<DownloadPaperLibraries> {
|
||||
paperDependencies.set(
|
||||
project.ext.serverProject.map { p ->
|
||||
val configuration = p.configurations["implementation"]
|
||||
configuration.isCanBeResolved = true
|
||||
configuration.resolvedConfiguration.resolvedArtifacts.map {
|
||||
"${it.moduleVersion.id.group}:${it.moduleVersion.id.name}:${it.moduleVersion.id.version}"
|
||||
}
|
||||
}
|
||||
)
|
||||
repositories.set(listOf(MAVEN_CENTRAL_URL, PAPER_MAVEN_REPO_URL))
|
||||
outputDir.set(cache.resolve(PAPER_SOURCES_JARS_PATH))
|
||||
sources.set(true)
|
||||
|
||||
downloader.set(downloadService)
|
||||
}
|
||||
|
||||
@Suppress("DuplicatedCode")
|
||||
val applyServerPatches by tasks.registering<ApplyPaperPatches> {
|
||||
group = "paper"
|
||||
|
@ -126,7 +143,7 @@ open class AllTasks(
|
|||
mcDevSources.set(extension.mcDevSourceDir)
|
||||
}
|
||||
|
||||
val applyPatches by tasks.registering<Task> {
|
||||
val applyPatchesLegacy by tasks.registering<Task> {
|
||||
group = "paper"
|
||||
description = "Set up the Paper development environment"
|
||||
dependsOn(applyApiPatches, applyServerPatches)
|
||||
|
@ -151,7 +168,7 @@ open class AllTasks(
|
|||
}
|
||||
|
||||
@Suppress("unused")
|
||||
val rebuildPatches by tasks.registering<Task> {
|
||||
val rebuildPatchesLegacy by tasks.registering<Task> {
|
||||
group = "paper"
|
||||
description = "Rebuilds patches to api and server"
|
||||
dependsOn(rebuildApiPatches, rebuildServerPatches)
|
||||
|
|
|
@ -45,7 +45,7 @@ open class InitialTasks(
|
|||
) {
|
||||
|
||||
val downloadMcManifest by tasks.registering<DownloadTask> {
|
||||
url.set(MC_MANIFEST_URL)
|
||||
url.set(project.ext.minecraftManifestUrl)
|
||||
outputFile.set(cache.resolve(MC_MANIFEST))
|
||||
|
||||
doNotTrackState("The Minecraft manifest is a changing resource")
|
||||
|
@ -54,7 +54,7 @@ open class InitialTasks(
|
|||
}
|
||||
private val mcManifest = downloadMcManifest.flatMap { it.outputFile }.map { gson.fromJson<MinecraftManifest>(it) }
|
||||
|
||||
val downloadMcVersionManifest by tasks.registering<DownloadTask> {
|
||||
val downloadMcVersionManifest by tasks.registering<CacheableDownloadTask> {
|
||||
url.set(
|
||||
mcManifest.zip(extension.minecraftVersion) { manifest, version ->
|
||||
manifest.versions.first { it.id == version }.url
|
||||
|
@ -71,7 +71,7 @@ open class InitialTasks(
|
|||
}
|
||||
private val versionManifest = downloadMcVersionManifest.flatMap { it.outputFile }.map { gson.fromJson<MinecraftVersionManifest>(it) }
|
||||
|
||||
val downloadMappings by tasks.registering<DownloadTask> {
|
||||
val downloadMappings by tasks.registering<CacheableDownloadTask> {
|
||||
url.set(versionManifest.map { version -> version.serverMappingsDownload().url })
|
||||
expectedHash.set(versionManifest.map { version -> version.serverMappingsDownload().hash() })
|
||||
outputFile.set(cache.resolve(SERVER_MAPPINGS))
|
||||
|
@ -94,5 +94,6 @@ open class InitialTasks(
|
|||
serverLibrariesList.set(cache.resolve(SERVER_LIBRARIES_LIST))
|
||||
serverVersionsList.set(cache.resolve(SERVER_VERSIONS_LIST))
|
||||
serverLibraryJars.set(cache.resolve(MINECRAFT_JARS_PATH))
|
||||
serverJar.set(cache.resolve(SERVER_JAR))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,344 @@
|
|||
/*
|
||||
* 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.ext
|
||||
import io.papermc.paperweight.tasks.*
|
||||
import io.papermc.paperweight.tasks.mache.*
|
||||
import io.papermc.paperweight.tasks.mache.RemapJar
|
||||
import io.papermc.paperweight.tasks.softspoon.ApplyFeaturePatches
|
||||
import io.papermc.paperweight.tasks.softspoon.ApplyFilePatches
|
||||
import io.papermc.paperweight.tasks.softspoon.ApplyFilePatchesFuzzy
|
||||
import io.papermc.paperweight.tasks.softspoon.RebuildFilePatches
|
||||
import io.papermc.paperweight.util.*
|
||||
import io.papermc.paperweight.util.constants.*
|
||||
import io.papermc.paperweight.util.data.mache.*
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.*
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.plugins.JavaPlugin
|
||||
import org.gradle.api.plugins.JavaPluginExtension
|
||||
import org.gradle.api.tasks.SourceSet
|
||||
import org.gradle.api.tasks.TaskContainer
|
||||
import org.gradle.kotlin.dsl.*
|
||||
|
||||
open class SoftSpoonTasks(
|
||||
val project: Project,
|
||||
val allTasks: AllTasks,
|
||||
tasks: TaskContainer = project.tasks
|
||||
) {
|
||||
|
||||
lateinit var mache: MacheMeta
|
||||
|
||||
val macheCodebook by project.configurations.registering {
|
||||
isTransitive = false
|
||||
}
|
||||
val macheRemapper by project.configurations.registering {
|
||||
isTransitive = false
|
||||
}
|
||||
val macheDecompiler by project.configurations.registering {
|
||||
isTransitive = false
|
||||
}
|
||||
val macheParamMappings by project.configurations.registering {
|
||||
isTransitive = false
|
||||
}
|
||||
val macheConstants by project.configurations.registering {
|
||||
isTransitive = false
|
||||
}
|
||||
val macheMinecraft by project.configurations.registering
|
||||
val macheMinecraftExtended by project.configurations.registering
|
||||
|
||||
val macheRemapJar by tasks.registering(RemapJar::class) {
|
||||
group = "mache"
|
||||
serverJar.set(allTasks.extractFromBundler.flatMap { it.serverJar })
|
||||
serverMappings.set(allTasks.downloadMappings.flatMap { it.outputFile })
|
||||
|
||||
remapperArgs.set(mache.remapperArgs)
|
||||
codebookClasspath.from(macheCodebook)
|
||||
minecraftClasspath.from(macheMinecraft)
|
||||
remapperClasspath.from(macheRemapper)
|
||||
paramMappings.from(macheParamMappings)
|
||||
constants.from(macheConstants)
|
||||
|
||||
outputJar.set(layout.cache.resolve(FINAL_REMAPPED_CODEBOOK_JAR))
|
||||
}
|
||||
|
||||
val macheDecompileJar by tasks.registering(DecompileJar::class) {
|
||||
group = "mache"
|
||||
inputJar.set(macheRemapJar.flatMap { it.outputJar })
|
||||
decompilerArgs.set(mache.decompilerArgs)
|
||||
|
||||
minecraftClasspath.from(macheMinecraft)
|
||||
decompiler.from(macheDecompiler)
|
||||
|
||||
outputJar.set(layout.cache.resolve(FINAL_DECOMPILE_JAR))
|
||||
}
|
||||
|
||||
val collectAccessTransform by tasks.registering(CollectATsFromPatches::class) {
|
||||
group = "mache"
|
||||
|
||||
patchDir.set(project.ext.paper.featurePatchDir)
|
||||
}
|
||||
|
||||
val mergeCollectedAts by tasks.registering<MergeAccessTransforms> {
|
||||
firstFile.set(project.ext.paper.additionalAts.fileExists(project))
|
||||
secondFile.set(collectAccessTransform.flatMap { it.outputFile })
|
||||
}
|
||||
|
||||
val setupMacheSources by tasks.registering(SetupVanilla::class) {
|
||||
group = "mache"
|
||||
description = "Setup vanilla source dir (applying mache patches and paper ATs)."
|
||||
|
||||
mache.from(project.configurations.named(MACHE_CONFIG))
|
||||
machePatches.set(layout.cache.resolve(PATCHES_FOLDER))
|
||||
ats.set(mergeCollectedAts.flatMap { it.outputFile })
|
||||
minecraftClasspath.from(macheMinecraft)
|
||||
|
||||
libraries.from(allTasks.downloadPaperLibrariesSources.flatMap { it.outputDir }, allTasks.downloadMcLibrariesSources.flatMap { it.outputDir })
|
||||
paperPatches.from(project.ext.paper.sourcePatchDir, project.ext.paper.featurePatchDir)
|
||||
devImports.set(project.ext.paper.devImports.fileExists(project))
|
||||
|
||||
inputFile.set(macheDecompileJar.flatMap { it.outputJar })
|
||||
predicate.set { Files.isRegularFile(it) && it.toString().endsWith(".java") }
|
||||
outputDir.set(layout.cache.resolve(BASE_PROJECT).resolve("sources"))
|
||||
}
|
||||
|
||||
val setupMacheResources by tasks.registering(SetupVanilla::class) {
|
||||
group = "mache"
|
||||
description = "Setup vanilla resources dir"
|
||||
|
||||
inputFile.set(allTasks.extractFromBundler.flatMap { it.serverJar })
|
||||
predicate.set { Files.isRegularFile(it) && !it.toString().endsWith(".class") }
|
||||
outputDir.set(layout.cache.resolve(BASE_PROJECT).resolve("resources"))
|
||||
}
|
||||
|
||||
val applySourcePatches by tasks.registering(ApplyFilePatches::class) {
|
||||
group = "softspoon"
|
||||
description = "Applies patches to the vanilla sources"
|
||||
|
||||
input.set(setupMacheSources.flatMap { it.outputDir })
|
||||
output.set(project.ext.serverProject.map { it.layout.projectDirectory.dir("src/vanilla/java") })
|
||||
patches.set(project.ext.paper.sourcePatchDir)
|
||||
}
|
||||
|
||||
val applySourcePatchesFuzzy by tasks.registering(ApplyFilePatchesFuzzy::class) {
|
||||
group = "softspoon"
|
||||
description = "Applies patches to the vanilla sources"
|
||||
|
||||
input.set(setupMacheSources.flatMap { it.outputDir })
|
||||
output.set(project.ext.serverProject.map { it.layout.projectDirectory.dir("src/vanilla/java") })
|
||||
patches.set(project.ext.paper.sourcePatchDir)
|
||||
}
|
||||
|
||||
val applyResourcePatches by tasks.registering(ApplyFilePatches::class) {
|
||||
group = "softspoon"
|
||||
description = "Applies patches to the vanilla resources"
|
||||
|
||||
input.set(setupMacheResources.flatMap { it.outputDir })
|
||||
output.set(project.ext.serverProject.map { it.layout.projectDirectory.dir("src/vanilla/resources") })
|
||||
patches.set(project.ext.paper.resourcePatchDir)
|
||||
}
|
||||
|
||||
val applyFilePatches by tasks.registering(Task::class) {
|
||||
group = "softspoon"
|
||||
description = "Applies all file patches"
|
||||
dependsOn(applySourcePatches, applyResourcePatches)
|
||||
}
|
||||
|
||||
val applyFeaturePatches by tasks.registering(ApplyFeaturePatches::class) {
|
||||
group = "softspoon"
|
||||
description = "Applies all feature patches"
|
||||
dependsOn(applyFilePatches)
|
||||
|
||||
repo.set(project.ext.serverProject.map { it.layout.projectDirectory.dir("src/vanilla/java") })
|
||||
patches.set(project.ext.paper.featurePatchDir)
|
||||
}
|
||||
|
||||
val applyPatches by tasks.registering(Task::class) {
|
||||
group = "softspoon"
|
||||
description = "Applies all patches"
|
||||
dependsOn(applyFilePatches, applyFeaturePatches)
|
||||
}
|
||||
|
||||
val rebuildSourcePatches by tasks.registering(RebuildFilePatches::class) {
|
||||
group = "softspoon"
|
||||
description = "Rebuilds patches to the vanilla sources"
|
||||
|
||||
minecraftClasspath.from(macheMinecraftExtended)
|
||||
atFile.set(project.ext.paper.additionalAts.fileExists(project))
|
||||
atFileOut.set(project.ext.paper.additionalAts.fileExists(project))
|
||||
|
||||
base.set(layout.cache.resolve(BASE_PROJECT).resolve("sources"))
|
||||
input.set(project.ext.serverProject.map { it.layout.projectDirectory.dir("src/vanilla/java") })
|
||||
patches.set(project.ext.paper.sourcePatchDir)
|
||||
}
|
||||
|
||||
val rebuildResourcePatches by tasks.registering(RebuildFilePatches::class) {
|
||||
group = "softspoon"
|
||||
description = "Rebuilds patches to the vanilla resources"
|
||||
|
||||
base.set(layout.cache.resolve(BASE_PROJECT).resolve("resources"))
|
||||
input.set(project.ext.serverProject.map { it.layout.projectDirectory.dir("src/vanilla/resources") })
|
||||
patches.set(project.ext.paper.resourcePatchDir)
|
||||
}
|
||||
|
||||
val rebuildFilePatches by tasks.registering(Task::class) {
|
||||
group = "softspoon"
|
||||
description = "Rebuilds all file patches"
|
||||
dependsOn(rebuildSourcePatches, rebuildResourcePatches)
|
||||
}
|
||||
|
||||
val rebuildFeaturePatches by tasks.registering(RebuildGitPatches::class) {
|
||||
group = "softspoon"
|
||||
description = "Rebuilds all feature patches"
|
||||
dependsOn(rebuildFilePatches)
|
||||
|
||||
inputDir.set(project.ext.serverProject.map { it.layout.projectDirectory.dir("src/vanilla/java") })
|
||||
patchDir.set(project.ext.paper.featurePatchDir)
|
||||
baseRef.set("file")
|
||||
}
|
||||
|
||||
val rebuildPatches by tasks.registering(Task::class) {
|
||||
group = "softspoon"
|
||||
description = "Rebuilds all file patches"
|
||||
dependsOn(rebuildFilePatches, rebuildFeaturePatches)
|
||||
}
|
||||
|
||||
fun afterEvaluate() {
|
||||
// load mache
|
||||
mache = this.project.configurations.named(MACHE_CONFIG).get().singleFile.toPath().openZip().use { zip ->
|
||||
return@use gson.fromJson<MacheMeta>(zip.getPath("/mache.json").readLines().joinToString("\n"))
|
||||
}
|
||||
println("Loaded mache ${mache.macheVersion} for minecraft ${mache.minecraftVersion}")
|
||||
|
||||
// setup repos
|
||||
this.project.repositories {
|
||||
println("setup repos for ${project.name}")
|
||||
for (repository in mache.repositories) {
|
||||
maven(repository.url) {
|
||||
name = repository.name
|
||||
mavenContent {
|
||||
for (group in repository.groups ?: listOf()) {
|
||||
includeGroupByRegex(group + ".*")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
maven(MC_LIBRARY_URL) {
|
||||
name = "Minecraft"
|
||||
}
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
val libsFile = project.layout.cache.resolve(SERVER_LIBRARIES_TXT)
|
||||
|
||||
// setup mc deps
|
||||
macheMinecraft {
|
||||
withDependencies {
|
||||
project.dependencies {
|
||||
val libs = libsFile.convertToPathOrNull()
|
||||
if (libs != null && libs.exists()) {
|
||||
libs.forEachLine { line ->
|
||||
add(create(line))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
macheMinecraftExtended {
|
||||
extendsFrom(macheMinecraft.get())
|
||||
withDependencies {
|
||||
project.dependencies {
|
||||
add(create(project.files(project.layout.cache.resolve(FINAL_REMAPPED_CODEBOOK_JAR))))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// setup mache deps
|
||||
this.project.dependencies {
|
||||
mache.dependencies.codebook.forEach {
|
||||
"macheCodebook"(it.toMavenString())
|
||||
}
|
||||
mache.dependencies.paramMappings.forEach {
|
||||
"macheParamMappings"(it.toMavenString())
|
||||
}
|
||||
mache.dependencies.constants.forEach {
|
||||
"macheConstants"(it.toMavenString())
|
||||
}
|
||||
mache.dependencies.remapper.forEach {
|
||||
"macheRemapper"(it.toMavenString())
|
||||
}
|
||||
mache.dependencies.decompiler.forEach {
|
||||
"macheDecompiler"(it.toMavenString())
|
||||
}
|
||||
}
|
||||
|
||||
this.project.ext.serverProject.get().setupServerProject(libsFile)
|
||||
}
|
||||
|
||||
private fun Project.setupServerProject(libsFile: Path) {
|
||||
if (!projectDir.exists()) {
|
||||
return
|
||||
}
|
||||
|
||||
// minecraft deps
|
||||
val macheMinecraft by configurations.creating {
|
||||
withDependencies {
|
||||
dependencies {
|
||||
// setup mc deps
|
||||
val libs = libsFile.convertToPathOrNull()
|
||||
if (libs != null && libs.exists()) {
|
||||
libs.forEachLine { line ->
|
||||
add(create(line))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl extends minecraft
|
||||
configurations.named(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME) {
|
||||
extendsFrom(macheMinecraft)
|
||||
}
|
||||
|
||||
// repos
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven(PAPER_MAVEN_REPO_URL)
|
||||
maven(MC_LIBRARY_URL)
|
||||
}
|
||||
|
||||
// add vanilla source set
|
||||
the<JavaPluginExtension>().sourceSets.named(SourceSet.MAIN_SOURCE_SET_NAME) {
|
||||
java {
|
||||
srcDirs(projectDir.resolve("src/vanilla/java"))
|
||||
}
|
||||
resources {
|
||||
srcDirs(projectDir.resolve("src/vanilla/resources"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -53,7 +53,9 @@ open class SpigotTasks(
|
|||
val generateSpigotMappings by tasks.registering<GenerateSpigotMappings> {
|
||||
classMappings.set(addAdditionalSpigotMappings.flatMap { it.outputClassSrg })
|
||||
|
||||
sourceMappings.set(generateMappings.flatMap { it.outputMappings })
|
||||
// todo hypo update breaks generate mappings, hardcode for now
|
||||
// sourceMappings.set(generateMappings.flatMap { it.outputMappings })
|
||||
sourceMappings.set(Path.of("D:\\IntellijProjects\\PaperClean\\.gradle\\caches\\paperweight\\mappings\\official-mojang+yarn.tiny"))
|
||||
|
||||
outputMappings.set(cache.resolve(SPIGOT_MOJANG_YARN_MAPPINGS))
|
||||
notchToSpigotMappings.set(cache.resolve(OBF_SPIGOT_MAPPINGS))
|
||||
|
|
|
@ -49,7 +49,8 @@ open class VanillaTasks(
|
|||
|
||||
val remapJar by tasks.registering<RemapJar> {
|
||||
inputJar.set(filterVanillaJar.flatMap { it.outputJar })
|
||||
mappingsFile.set(generateMappings.flatMap { it.outputMappings })
|
||||
// mappingsFile.set(generateMappings.flatMap { it.outputMappings })
|
||||
mappingsFile.set(Path.of("D:\\IntellijProjects\\PaperClean\\.gradle\\caches\\paperweight\\mappings\\official-mojang+yarn.tiny"))
|
||||
fromNamespace.set(OBF_NAMESPACE)
|
||||
toNamespace.set(DEOBF_NAMESPACE)
|
||||
remapper.from(project.configurations.named(REMAPPER_CONFIG))
|
||||
|
|
|
@ -0,0 +1,179 @@
|
|||
/*
|
||||
* 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 io.papermc.paperweight.util.*
|
||||
import java.net.URL
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import kotlin.io.path.*
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import org.gradle.testkit.runner.TaskOutcome
|
||||
import org.junit.jupiter.api.Disabled
|
||||
import org.junit.jupiter.api.io.CleanupMode
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
|
||||
class FunctionalTest {
|
||||
|
||||
val debug = false
|
||||
|
||||
@Disabled
|
||||
@Test
|
||||
fun setupCleanTestRepo() {
|
||||
val projectDir = Path.of("F:\\Projects\\paperweight\\test").ensureClean().createDirectories()
|
||||
|
||||
setupMache("fake_mache", projectDir.resolve("mache.zip"))
|
||||
setupMojang("fake_mojang", projectDir.resolve("fake_mojang"))
|
||||
projectDir.copyProject("functional_test")
|
||||
|
||||
val settings = projectDir.resolve("settings.gradle")
|
||||
val text = settings.readText()
|
||||
settings.writeText(text.replace("// includeBuild '..'", "includeBuild '..'").replace("functional_test", "test"))
|
||||
|
||||
projectDir.resolve("patches").deleteRecursively()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test simple test project`(@TempDir(cleanup = CleanupMode.ON_SUCCESS) tempDir: Path) {
|
||||
println("running in $tempDir")
|
||||
val testResource = Paths.get("src/test/resources/functional_test")
|
||||
|
||||
setupMache("fake_mache", tempDir.resolve("mache.zip"))
|
||||
setupMojang("fake_mojang", tempDir.resolve("fake_mojang"))
|
||||
|
||||
val gradleRunner = tempDir.copyProject("functional_test").gradleRunner()
|
||||
|
||||
println("\nrunning extractFromBundler\n")
|
||||
val extractFromBundler = gradleRunner
|
||||
.withArguments("extractFromBundler", "--stacktrace", "-Dfake=true")
|
||||
.withDebug(debug)
|
||||
.build()
|
||||
|
||||
assertEquals(extractFromBundler.task(":extractFromBundler")?.outcome, TaskOutcome.SUCCESS)
|
||||
|
||||
// appP -> works
|
||||
println("\nrunning applyPatches dependencies\n")
|
||||
val appP = gradleRunner
|
||||
.withArguments("applyPatches", "dependencies", ":test-server:dependencies", "--stacktrace", "-Dfake=true")
|
||||
.withDebug(debug)
|
||||
.build()
|
||||
|
||||
assertEquals(appP.task(":applyPatches")?.outcome, TaskOutcome.SUCCESS)
|
||||
|
||||
// clean rebuild rebP -> changes nothing
|
||||
println("\nrunning rebuildPatches\n")
|
||||
val rebP = gradleRunner
|
||||
.withArguments("rebuildPatches", "--stacktrace", "-Dfake=true")
|
||||
.withDebug(debug)
|
||||
.build()
|
||||
|
||||
assertEquals(rebP.task(":rebuildPatches")?.outcome, TaskOutcome.SUCCESS)
|
||||
assertEquals(
|
||||
testResource.resolve("fake-patches/sources/Test.java.patch").readText(),
|
||||
tempDir.resolve("fake-patches/sources/Test.java.patch").readText()
|
||||
)
|
||||
|
||||
// add AT to source -> patch and AT file is updated
|
||||
val sourceFile = tempDir.resolve("test-server/src/vanilla/java/Test.java")
|
||||
val replacedContent = sourceFile.readText().replace(
|
||||
"\"2\";",
|
||||
"\"2\"; // Woo"
|
||||
).replace("public String getTest2() {", "private final String getTest2() {// Paper-AT: private+f getTest2()Ljava/lang/String;")
|
||||
sourceFile.writeText(replacedContent)
|
||||
|
||||
Git(tempDir.resolve("test-server/src/vanilla/java")).let { git ->
|
||||
git("add", ".").executeSilently()
|
||||
git("commit", "--amend", "--no-edit").executeSilently()
|
||||
}
|
||||
|
||||
println("\nrunning rebuildPatches again\n")
|
||||
val rebP2 = gradleRunner
|
||||
.withArguments("rebuildPatches", "--stacktrace", "-Dfake=true")
|
||||
.withDebug(debug)
|
||||
.build()
|
||||
|
||||
assertEquals(rebP2.task(":rebuildPatches")?.outcome, TaskOutcome.SUCCESS)
|
||||
assertEquals(
|
||||
testResource.resolve("fake-patches/expected/Test.java.patch").readText(),
|
||||
tempDir.resolve("fake-patches/sources/Test.java.patch").readText()
|
||||
)
|
||||
assertEquals(testResource.resolve("build-data/expected.at").readText(), tempDir.resolve("build-data/fake.at").readText())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test full vanilla project`(@TempDir(cleanup = CleanupMode.ON_SUCCESS) tempDir: Path) {
|
||||
println("running in $tempDir")
|
||||
val gradleRunner = tempDir.copyProject("functional_test").gradleRunner()
|
||||
|
||||
val extractFromBundler = gradleRunner
|
||||
.withArguments("extractFromBundler", "--stacktrace", "-Dfake=false")
|
||||
.withDebug(debug)
|
||||
.build()
|
||||
|
||||
assertEquals(extractFromBundler.task(":extractFromBundler")?.outcome, TaskOutcome.SUCCESS)
|
||||
|
||||
val result = gradleRunner
|
||||
.withArguments("applyPatches", "-Dfake=false")
|
||||
.withDebug(debug)
|
||||
.build()
|
||||
|
||||
assertEquals(result.task(":applyPatches")?.outcome, TaskOutcome.SUCCESS)
|
||||
}
|
||||
|
||||
fun setupMache(macheName: String, target: Path) {
|
||||
val macheDir = Paths.get("src/test/resources/$macheName")
|
||||
zip(macheDir, target)
|
||||
}
|
||||
|
||||
fun setupMojang(mojangName: String, target: Path) {
|
||||
val mojangDir = Paths.get("src/test/resources/$mojangName")
|
||||
mojangDir.copyRecursivelyTo(target)
|
||||
|
||||
val serverFolder = target.resolve("server")
|
||||
ProcessBuilder()
|
||||
.directory(serverFolder)
|
||||
.command("javac", serverFolder.resolve("Test.java").toString())
|
||||
.redirectErrorStream(true)
|
||||
.start()
|
||||
.waitFor()
|
||||
|
||||
ProcessBuilder()
|
||||
.directory(serverFolder)
|
||||
.command("jar", "-cf", "server.jar", "Test.class", "test.json")
|
||||
.redirectErrorStream(true)
|
||||
.start()
|
||||
.waitFor()
|
||||
|
||||
val versionFolder = target.resolve("bundle/META-INF/versions/fake/")
|
||||
versionFolder.createDirectories()
|
||||
serverFolder.resolve("server.jar").copyTo(versionFolder.resolve("server.jar"))
|
||||
|
||||
val oshiFolder = target.resolve("bundle/META-INF/libraries/com/github/oshi/oshi-core/6.4.5/")
|
||||
oshiFolder.createDirectories()
|
||||
oshiFolder.resolve(
|
||||
"oshi-core-6.4.5.jar"
|
||||
).writeBytes(URL("https://libraries.minecraft.net/com/github/oshi/oshi-core/6.4.5/oshi-core-6.4.5.jar").readBytes())
|
||||
zip(target.resolve("bundle"), target.resolve("bundle.jar"))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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 io.papermc.paperweight.util.*
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
import kotlin.io.path.*
|
||||
import org.gradle.testkit.runner.GradleRunner
|
||||
|
||||
fun Path.copyProject(resourcesProjectName: String): ProjectFiles {
|
||||
Paths.get("src/test/resources/$resourcesProjectName")
|
||||
.copyToRecursively(this, followLinks = false)
|
||||
Git(this)("init").executeSilently()
|
||||
return ProjectFiles(this)
|
||||
}
|
||||
|
||||
class ProjectFiles(val projectDir: Path) {
|
||||
val gradleProperties: Path = resolve("gradle.properties")
|
||||
val buildGradle: Path = resolve("build.gradle")
|
||||
val buildGradleKts: Path = resolve("build.gradle.kts")
|
||||
val settingsGradle: Path = resolve("settings.gradle")
|
||||
val settingsGradleKts: Path = resolve("settings.gradle.kts")
|
||||
|
||||
fun resolve(path: String): Path = projectDir.resolve(path)
|
||||
|
||||
fun gradleRunner(): GradleRunner = GradleRunner.create()
|
||||
.forwardOutput()
|
||||
.withPluginClasspath()
|
||||
.withProjectDir(projectDir.toFile())
|
||||
}
|
108
paperweight-core/src/test/resources/fake_mache/mache.json
Normal file
108
paperweight-core/src/test/resources/fake_mache/mache.json
Normal file
|
@ -0,0 +1,108 @@
|
|||
{
|
||||
"minecraftVersion": "fake",
|
||||
"macheVersion": "fake",
|
||||
"dependencies": {
|
||||
"codebook": [
|
||||
{
|
||||
"group": "io.papermc.codebook",
|
||||
"name": "codebook-cli",
|
||||
"version": "1.0.10",
|
||||
"classifier": "all"
|
||||
}
|
||||
],
|
||||
"paramMappings": [
|
||||
{
|
||||
"group": "org.parchmentmc.data",
|
||||
"name": "parchment-1.20.4",
|
||||
"version": "2024.02.25",
|
||||
"extension": "zip"
|
||||
}
|
||||
],
|
||||
"constants": [
|
||||
],
|
||||
"remapper": [
|
||||
{
|
||||
"group": "net.neoforged",
|
||||
"name": "AutoRenamingTool",
|
||||
"version": "1.0.14",
|
||||
"classifier": "all"
|
||||
}
|
||||
],
|
||||
"decompiler": [
|
||||
{
|
||||
"group": "org.vineflower",
|
||||
"name": "vineflower",
|
||||
"version": "1.10.0-20240212.003104-88"
|
||||
}
|
||||
]
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"url": "https://maven.fabricmc.net/",
|
||||
"name": "FabricMC",
|
||||
"groups": [
|
||||
"net.fabricmc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://maven.neoforged.net/releases/",
|
||||
"name": "NeoForged",
|
||||
"groups": [
|
||||
"net.neoforged",
|
||||
"net.minecraftforge"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://repo.papermc.io/repository/maven-public/",
|
||||
"name": "PaperMC",
|
||||
"groups": [
|
||||
"io.papermc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://maven.parchmentmc.org/",
|
||||
"name": "ParchmentMC",
|
||||
"groups": [
|
||||
"org.parchmentmc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"url": "https://s01.oss.sonatype.org/content/repositories/snapshots/",
|
||||
"name": "sonatype snapshots",
|
||||
"groups": [
|
||||
"org.vineflower"
|
||||
]
|
||||
}
|
||||
],
|
||||
"decompilerArgs": [
|
||||
"-nns=true",
|
||||
"-tcs=true",
|
||||
"-ovr=false",
|
||||
"-vvm=true",
|
||||
"-iec=true",
|
||||
"-jrt=current",
|
||||
"-ind= ",
|
||||
"-jvn=false",
|
||||
"-dcc=true",
|
||||
"-sef=true",
|
||||
"-nls=1"
|
||||
],
|
||||
"remapperArgs": [
|
||||
"--temp-dir={tempDir}",
|
||||
"--remapper-file={remapperFile}",
|
||||
"--mappings-file={mappingsFile}",
|
||||
"--params-file={paramsFile}",
|
||||
"--output={output}",
|
||||
"--input={input}",
|
||||
"--input-classpath={inputClasspath}"
|
||||
],
|
||||
"additionalCompileDependencies": {
|
||||
"compileOnly": [
|
||||
{
|
||||
"group": "org.jetbrains",
|
||||
"name": "annotations",
|
||||
"version": "24.0.1"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
--- a/Test.java
|
||||
+++ b/Test.java
|
||||
@@ -1,5 +_,5 @@
|
||||
public class Test {
|
||||
- public int dum;
|
||||
+ public int dum2;
|
||||
private final String test;
|
||||
|
||||
public Test(String var1) {
|
|
@ -0,0 +1 @@
|
|||
- com.github.oshi:oshi-core:6.4.5 com/github/oshi/oshi-core/6.4.5/oshi-core-6.4.5.jar
|
|
@ -0,0 +1 @@
|
|||
- fake fake/server.jar
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"id": "fake"
|
||||
}
|
19
paperweight-core/src/test/resources/fake_mojang/mappings.txt
Normal file
19
paperweight-core/src/test/resources/fake_mojang/mappings.txt
Normal file
|
@ -0,0 +1,19 @@
|
|||
com.mojang.math.Axis -> a:
|
||||
# {"fileName":"Axis.java","id":"sourceFile"}
|
||||
com.mojang.math.Axis XN -> a
|
||||
com.mojang.math.Axis XP -> b
|
||||
com.mojang.math.Axis YN -> c
|
||||
com.mojang.math.Axis YP -> d
|
||||
com.mojang.math.Axis ZN -> e
|
||||
com.mojang.math.Axis ZP -> f
|
||||
17:17:com.mojang.math.Axis of(org.joml.Vector3f) -> of
|
||||
org.joml.Quaternionf rotation(float) -> rotation
|
||||
23:23:org.joml.Quaternionf rotationDegrees(float) -> rotationDegrees
|
||||
17:17:org.joml.Quaternionf lambda$of$6(org.joml.Vector3f,float) -> a
|
||||
14:14:org.joml.Quaternionf lambda$static$5(float) -> a
|
||||
13:13:org.joml.Quaternionf lambda$static$4(float) -> b
|
||||
12:12:org.joml.Quaternionf lambda$static$3(float) -> c
|
||||
11:11:org.joml.Quaternionf lambda$static$2(float) -> d
|
||||
10:10:org.joml.Quaternionf lambda$static$1(float) -> e
|
||||
9:9:org.joml.Quaternionf lambda$static$0(float) -> f
|
||||
9:14:void <clinit>() -> <clinit>
|
|
@ -0,0 +1,17 @@
|
|||
public class Test {
|
||||
|
||||
public int dum;
|
||||
private final String test;
|
||||
|
||||
public Test(String test) {
|
||||
this.test = test;
|
||||
}
|
||||
|
||||
public String getTest() {
|
||||
return test;
|
||||
}
|
||||
|
||||
public String getTest2() {
|
||||
return test + "2";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"test": "test"
|
||||
}
|
12
paperweight-core/src/test/resources/fake_mojang/version.json
Normal file
12
paperweight-core/src/test/resources/fake_mojang/version.json
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"downloads": {
|
||||
"server": {
|
||||
"sha1": "",
|
||||
"url": "file://project/fake_mojang/bundle.jar"
|
||||
},
|
||||
"server_mappings": {
|
||||
"sha1": "",
|
||||
"url": "file://project/fake_mojang/mappings.txt"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"latest": {
|
||||
"release": "fake",
|
||||
"snapshot": "fake"
|
||||
},
|
||||
"versions": [
|
||||
{
|
||||
"id": "fake",
|
||||
"type": "release",
|
||||
"url": "file://project/fake_mojang/version.json",
|
||||
"sha1": ""
|
||||
}
|
||||
]
|
||||
}
|
2
paperweight-core/src/test/resources/functional_test/.gitignore
vendored
Normal file
2
paperweight-core/src/test/resources/functional_test/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
.gradle
|
||||
gradle
|
|
@ -0,0 +1,5 @@
|
|||
# This file is auto generated, any changes may be overridden!
|
||||
# See CONTRIBUTING.md on how to add access transformers.
|
||||
private+f Test getTest2()Ljava/lang/String;
|
||||
public+f Test dum2
|
||||
public+f Test getTest()Ljava/lang/String;
|
|
@ -0,0 +1,4 @@
|
|||
# This file is auto generated, any changes may be overridden!
|
||||
# See CONTRIBUTING.md on how to add access transformers.
|
||||
public+f Test dum2
|
||||
public+f Test getTest()Ljava/lang/String;
|
|
@ -0,0 +1,3 @@
|
|||
# This file is auto generated, any changes may be overridden!
|
||||
# See CONTRIBUTING.md on how to add access transformers.
|
||||
private+f net.minecraft.CrashReport getTitle()Ljava/lang/String;
|
|
@ -0,0 +1,52 @@
|
|||
plugins {
|
||||
id 'java'
|
||||
id 'com.github.johnrengelman.shadow' version '8.1.1' apply false
|
||||
id 'io.papermc.paperweight.core'
|
||||
}
|
||||
|
||||
allprojects {
|
||||
apply plugin: 'java'
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
def fake = Boolean.getBoolean("fake")
|
||||
|
||||
dependencies {
|
||||
if (fake) {
|
||||
mache files('mache.zip') // use fake mache for testing
|
||||
} else {
|
||||
mache 'io.papermc:mache:1.20.4+build.3'
|
||||
}
|
||||
}
|
||||
|
||||
paperweight {
|
||||
softSpoon = true
|
||||
|
||||
if (fake) {
|
||||
// use fake mojang data for testing
|
||||
minecraftVersion = 'fake'
|
||||
minecraftManifestUrl = 'file://project/fake_mojang/version_manifest.json'
|
||||
|
||||
paper {
|
||||
sourcePatchDir.set(file('fake-patches/sources'))
|
||||
resourcePatchDir.set(file('fake-patches/resources'))
|
||||
featurePatchDir.set(file('fake-patches/feature'))
|
||||
|
||||
additionalAts.set(file('build-data/fake.at'))
|
||||
|
||||
paperServerDir.set(file('test-server'))
|
||||
}
|
||||
} else {
|
||||
minecraftVersion = '1.20.4'
|
||||
|
||||
paper {
|
||||
paperServerDir.set(file('test-server'))
|
||||
}
|
||||
}
|
||||
|
||||
serverProject = project(':test-server')
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
--- a/Test.java
|
||||
+++ b/Test.java
|
||||
@@ -7,10 +_,10 @@
|
||||
}
|
||||
|
||||
public final String getTest() {
|
||||
- return this.test;
|
||||
+ return this.test; // WOOOO
|
||||
}
|
||||
|
||||
private final String getTest2() {
|
||||
- return this.test + "2";
|
||||
+ return this.test + "2"; // Woo
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
--- a/test.json
|
||||
+++ b/test.json
|
||||
@@ -1,3 +_,3 @@
|
||||
{
|
||||
- "test": "test"
|
||||
+ "test": "test2"
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
--- a/Test.java
|
||||
+++ b/Test.java
|
||||
@@ -7,7 +_,7 @@
|
||||
}
|
||||
|
||||
public final String getTest() {
|
||||
- return this.test;
|
||||
+ return this.test; // WOOOO
|
||||
}
|
||||
|
||||
public String getTest2() {
|
|
@ -0,0 +1,18 @@
|
|||
pluginManagement {
|
||||
// includeBuild '..'
|
||||
repositories {
|
||||
mavenLocal()
|
||||
gradlePluginPortal()
|
||||
maven {
|
||||
url "https://repo.papermc.io/repository/maven-public/"
|
||||
}
|
||||
maven {
|
||||
url "https://maven.parchmentmc.org"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rootProject.name = 'functional_test'
|
||||
|
||||
include 'test-api'
|
||||
include 'test-server'
|
|
@ -0,0 +1,3 @@
|
|||
plugins {
|
||||
id "java-library"
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
plugins {
|
||||
id "java"
|
||||
id "com.github.johnrengelman.shadow"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(":test-api")
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: MiniDigger | Martin <admin@benndorf.dev>
|
||||
Date: Sun, 31 Mar 2024 17:01:32 +0200
|
||||
Subject: [PATCH] Example
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 28def15b5789d34bcfc2a16a17444c9c72dc2c8f..a8f735100a8d4db72dae9be3eeeca0d417be3eee 100644
|
||||
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -106,6 +106,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
thread.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(LOGGER));
|
||||
thread.start();
|
||||
LOGGER.info("Starting minecraft server version {}", SharedConstants.getCurrentVersion().getName());
|
||||
+ LOGGER.info("Wooooooooooooooooooo");
|
||||
if (Runtime.getRuntime().maxMemory() / 1024L / 1024L < 512L) {
|
||||
LOGGER.warn("To start the server with more ram, launch it as \"java -Xmx1024M -Xms1024M -jar minecraft_server.jar\"");
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
--- a/version.json
|
||||
+++ b/version.json
|
||||
@@ -1,6 +_,6 @@
|
||||
{
|
||||
- "id": "1.20.4",
|
||||
- "name": "1.20.4",
|
||||
+ "id": "1.20.4-paper",
|
||||
+ "name": "1.20.4 - Paper",
|
||||
"world_version": 3700,
|
||||
"series_id": "main",
|
||||
"protocol_version": 765,
|
|
@ -0,0 +1,15 @@
|
|||
--- a/net/minecraft/CrashReport.java
|
||||
+++ b/net/minecraft/CrashReport.java
|
||||
@@ -35,10 +_,11 @@
|
||||
public CrashReport(String title, Throwable exception) {
|
||||
this.title = title;
|
||||
this.exception = exception;
|
||||
+ // FIXME this.systemReport.setDetail("CraftBukkit Information", new org.bukkit.craftbukkit.CraftCrashReport()); // CraftBukkit
|
||||
}
|
||||
|
||||
private final String getTitle() {
|
||||
- return this.title;
|
||||
+ return this.title; // Test
|
||||
}
|
||||
|
||||
public Throwable getException() {
|
|
@ -9,6 +9,8 @@ repositories {
|
|||
dependencies {
|
||||
implementation(libs.httpclient)
|
||||
implementation(libs.bundles.kotson)
|
||||
implementation(libs.coroutines)
|
||||
implementation(libs.jgit)
|
||||
|
||||
// ASM for inspection
|
||||
implementation(libs.bundles.asm)
|
||||
|
@ -19,9 +21,16 @@ dependencies {
|
|||
|
||||
implementation(libs.lorenzTiny)
|
||||
|
||||
implementation(libs.feather.core)
|
||||
implementation(libs.feather.gson)
|
||||
|
||||
implementation(libs.jbsdiff)
|
||||
|
||||
implementation(libs.restamp)
|
||||
|
||||
implementation(variantOf(libs.diffpatch) { classifier("all") }) {
|
||||
isTransitive = false
|
||||
}
|
||||
|
||||
testImplementation(libs.mockk)
|
||||
}
|
||||
|
|
|
@ -32,6 +32,8 @@ import java.time.format.DateTimeFormatter
|
|||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.io.path.*
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import org.apache.http.HttpHost
|
||||
import org.apache.http.HttpStatus
|
||||
import org.apache.http.client.config.CookieSpecs
|
||||
|
@ -41,12 +43,17 @@ import org.apache.http.client.methods.HttpGet
|
|||
import org.apache.http.client.utils.DateUtils
|
||||
import org.apache.http.impl.client.CloseableHttpClient
|
||||
import org.apache.http.impl.client.HttpClientBuilder
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.api.logging.Logging
|
||||
import org.gradle.api.services.BuildService
|
||||
import org.gradle.api.services.BuildServiceParameters
|
||||
|
||||
abstract class DownloadService : BuildService<BuildServiceParameters.None>, AutoCloseable {
|
||||
abstract class DownloadService : BuildService<DownloadService.Params>, AutoCloseable {
|
||||
|
||||
interface Params : BuildServiceParameters {
|
||||
val projectPath: DirectoryProperty
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val LOGGER: Logger = Logging.getLogger(DownloadService::class.java)
|
||||
|
@ -64,13 +71,19 @@ abstract class DownloadService : BuildService<BuildServiceParameters.None>, Auto
|
|||
download(url, file, hash)
|
||||
}
|
||||
|
||||
suspend fun downloadAsync(source: Any, target: Any, hash: Hash? = null) = coroutineScope {
|
||||
async {
|
||||
download(source.convertToUrl(), target.convertToPath(), hash, false)
|
||||
}
|
||||
}
|
||||
|
||||
private fun download(source: URL, target: Path, hash: Hash?, retry: Boolean = false) {
|
||||
download(source, target)
|
||||
if (hash == null) {
|
||||
return
|
||||
}
|
||||
val dlHash = target.hashFile(hash.algorithm).asHexString().lowercase(Locale.ENGLISH)
|
||||
if (dlHash == hash.valueLower) {
|
||||
if (hash.value == "" || dlHash == hash.valueLower) {
|
||||
return
|
||||
}
|
||||
LOGGER.warn(
|
||||
|
@ -91,6 +104,15 @@ abstract class DownloadService : BuildService<BuildServiceParameters.None>, Auto
|
|||
private fun download(source: URL, target: Path) {
|
||||
target.parent.createDirectories()
|
||||
|
||||
if (source.protocol == "file") {
|
||||
var path = source.toString().replace("file://", "")
|
||||
if (source.host == "project") {
|
||||
path = path.replace("project", parameters.projectPath.path.absolutePathString())
|
||||
}
|
||||
Path.of(path).copyTo(target, overwrite = true)
|
||||
return
|
||||
}
|
||||
|
||||
val etagDir = target.resolveSibling("etags")
|
||||
etagDir.createDirectories()
|
||||
|
||||
|
|
|
@ -189,16 +189,16 @@ fun Git.disableAutoGpgSigningInRepo() {
|
|||
invoke("config", "tag.gpgSign", "false").executeSilently(silenceErr = true)
|
||||
}
|
||||
|
||||
fun checkoutRepoFromUpstream(git: Git, upstream: Path, upstreamBranch: String) {
|
||||
fun checkoutRepoFromUpstream(git: Git, upstream: Path, upstreamBranch: String, upstreamName: String = "upstream", branchName: String = "master") {
|
||||
git("init", "--quiet").executeSilently(silenceErr = true)
|
||||
git.disableAutoGpgSigningInRepo()
|
||||
git("remote", "remove", "upstream").runSilently(silenceErr = true)
|
||||
git("remote", "add", "upstream", upstream.toUri().toString()).executeSilently(silenceErr = true)
|
||||
git("fetch", "upstream", "--prune").executeSilently(silenceErr = true)
|
||||
if (git("checkout", "master").runSilently(silenceErr = true) != 0) {
|
||||
git("checkout", "-b", "master").runSilently(silenceErr = true)
|
||||
git("remote", "remove", upstreamName).runSilently(silenceErr = true)
|
||||
git("remote", "add", upstreamName, upstream.toUri().toString()).executeSilently(silenceErr = true)
|
||||
git("fetch", upstreamName, "--prune").executeSilently(silenceErr = true)
|
||||
if (git("checkout", branchName).runSilently(silenceErr = true) != 0) {
|
||||
git("checkout", "-b", branchName).runSilently(silenceErr = true)
|
||||
}
|
||||
git("reset", "--hard", "upstream/$upstreamBranch").executeSilently(silenceErr = true)
|
||||
git("reset", "--hard", "$upstreamName/$upstreamBranch").executeSilently(silenceErr = true)
|
||||
git("gc").runSilently(silenceErr = true)
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ import org.gradle.api.file.RegularFileProperty
|
|||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.*
|
||||
|
||||
// Not cached since this is Mojang's server jar
|
||||
@CacheableTask
|
||||
abstract class DownloadServerJar : BaseTask() {
|
||||
|
||||
@get:Input
|
||||
|
@ -41,7 +41,6 @@ abstract class DownloadServerJar : BaseTask() {
|
|||
abstract val downloader: Property<DownloadService>
|
||||
|
||||
@get:Nested
|
||||
@get:Optional
|
||||
abstract val expectedHash: Property<Hash>
|
||||
|
||||
override fun init() {
|
||||
|
|
|
@ -59,11 +59,6 @@ abstract class ExtractFromBundler : BaseTask() {
|
|||
@get:OutputFile
|
||||
abstract val serverVersionsList: RegularFileProperty
|
||||
|
||||
override fun init() {
|
||||
super.init()
|
||||
serverJar.set(defaultOutput())
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun run() {
|
||||
ServerBundler.extractFromBundler(
|
||||
|
@ -99,16 +94,16 @@ object ServerBundler {
|
|||
}
|
||||
|
||||
private fun extractServerJar(bundlerZip: Path, serverJar: Path, outputVersionJson: Path?) {
|
||||
val serverVersionJson = bundlerZip.resolve("version.json")
|
||||
val serverVersionJson = bundlerZip.resolve(FileEntry.VERSION_JSON)
|
||||
outputVersionJson?.let { output ->
|
||||
serverVersionJson.copyTo(output, overwrite = true)
|
||||
}
|
||||
|
||||
val versionId = gson.fromJson<JsonObject>(serverVersionJson)["id"].asString
|
||||
val versions = bundlerZip.resolve("/META-INF/versions.list").readLines()
|
||||
val versions = bundlerZip.resolve(FileEntry.VERSIONS_LIST).readLines()
|
||||
.map { it.split('\t') }
|
||||
.associate { it[1] to it[2] }
|
||||
val serverJarPath = bundlerZip.resolve("/META-INF/versions/${versions[versionId]}")
|
||||
val serverJarPath = bundlerZip.resolve("${FileEntry.VERSIONS_DIR}/${versions[versionId]}")
|
||||
|
||||
serverJar.parent.createDirectories()
|
||||
serverJarPath.copyTo(serverJar, overwrite = true)
|
||||
|
@ -117,7 +112,7 @@ object ServerBundler {
|
|||
private fun extractLibraryJars(bundlerZip: Path, serverLibraryJars: Path) {
|
||||
serverLibraryJars.deleteRecursive()
|
||||
serverLibraryJars.parent.createDirectories()
|
||||
bundlerZip.resolve("/META-INF/libraries").copyRecursivelyTo(serverLibraryJars)
|
||||
bundlerZip.resolve(FileEntry.LIBRARIES_DIR).copyRecursivelyTo(serverLibraryJars)
|
||||
}
|
||||
|
||||
private fun writeLibrariesTxt(bundlerZip: Path, serverLibrariesTxt: Path) {
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* 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.tasks
|
||||
|
||||
import io.papermc.paperweight.util.*
|
||||
import io.papermc.paperweight.util.data.mache.*
|
||||
import kotlin.io.path.*
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.tasks.Classpath
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
|
||||
abstract class MacheTask : DefaultTask() {
|
||||
|
||||
@get:Classpath
|
||||
abstract val mache: ConfigurableFileCollection
|
||||
|
||||
@TaskAction
|
||||
fun run() {
|
||||
val meta = getMacheMeta()
|
||||
println("loaded meta: $meta")
|
||||
}
|
||||
|
||||
private fun getMacheMeta(): MacheMeta {
|
||||
val metaJson = mutableListOf("")
|
||||
mache.singleFile.toPath().openZip().use { zip ->
|
||||
metaJson.addAll(zip.getPath("/mache.json").readLines())
|
||||
}
|
||||
|
||||
return gson.fromJson<MacheMeta>(metaJson.joinToString("\n"))
|
||||
}
|
||||
|
||||
private fun extractVanillaJar() {
|
||||
// val jar = downloadedJar.convertToPath()
|
||||
// val out = serverJar.convertToPath().ensureClean()
|
||||
//
|
||||
// jar.useZip { root ->
|
||||
// val metaInf = root.resolve("META-INF")
|
||||
// val versionsList = metaInf.resolve("versions.list")
|
||||
// if (versionsList.notExists()) {
|
||||
// throw Exception("Could not find versions.list")
|
||||
// }
|
||||
//
|
||||
// val lines = versionsList.readLines()
|
||||
// if (lines.size != 1) {
|
||||
// throw Exception("versions.list is invalid")
|
||||
// }
|
||||
//
|
||||
// val line = lines.first()
|
||||
// val parts = line.split(whitespace)
|
||||
// if (parts.size != 3) {
|
||||
// throw Exception("versions.list line is invalid")
|
||||
// }
|
||||
//
|
||||
// val serverJarInJar = metaInf.resolve("versions").resolve(parts[2])
|
||||
// if (serverJarInJar.notExists()) {
|
||||
// throw Exception("Could not find version jar")
|
||||
// }
|
||||
//
|
||||
// serverJarInJar.copyTo(out)
|
||||
// }
|
||||
}
|
||||
}
|
|
@ -34,6 +34,7 @@ import org.gradle.api.tasks.OutputFile
|
|||
import org.gradle.api.tasks.PathSensitive
|
||||
import org.gradle.api.tasks.PathSensitivity
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import writeLF
|
||||
|
||||
@CacheableTask
|
||||
abstract class MergeAccessTransforms : BaseTask() {
|
||||
|
@ -67,6 +68,6 @@ abstract class MergeAccessTransforms : BaseTask() {
|
|||
outputAt.merge(at)
|
||||
}
|
||||
|
||||
AccessTransformFormats.FML.write(outputFile.path, outputAt)
|
||||
AccessTransformFormats.FML.writeLF(outputFile.path, outputAt)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.gradle.api.tasks.OutputFile
|
|||
import org.gradle.api.tasks.PathSensitive
|
||||
import org.gradle.api.tasks.PathSensitivity
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import writeLF
|
||||
|
||||
@CacheableTask
|
||||
abstract class RemapAccessTransform : BaseTask() {
|
||||
|
@ -57,6 +58,6 @@ abstract class RemapAccessTransform : BaseTask() {
|
|||
val mappingSet = MappingFormats.TINY.read(mappings.path, SPIGOT_NAMESPACE, DEOBF_NAMESPACE)
|
||||
|
||||
val resultAt = at.remap(mappingSet)
|
||||
AccessTransformFormats.FML.write(outputFile.path, resultAt)
|
||||
AccessTransformFormats.FML.writeLF(outputFile.path, resultAt)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ import org.gradle.kotlin.dsl.*
|
|||
import org.gradle.workers.WorkAction
|
||||
import org.gradle.workers.WorkParameters
|
||||
import org.gradle.workers.WorkerExecutor
|
||||
import writeLF
|
||||
|
||||
@CacheableTask
|
||||
abstract class RemapSources : JavaLauncherTask() {
|
||||
|
@ -260,7 +261,7 @@ abstract class RemapSources : JavaLauncherTask() {
|
|||
}
|
||||
|
||||
if (generatedAtOutPath != null) {
|
||||
AccessTransformFormats.FML.write(generatedAtOutPath, processAt)
|
||||
AccessTransformFormats.FML.writeLF(generatedAtOutPath, processAt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.gradle.api.tasks.OutputFile
|
|||
import org.gradle.api.tasks.PathSensitive
|
||||
import org.gradle.api.tasks.PathSensitivity
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import writeLF
|
||||
|
||||
@CacheableTask
|
||||
abstract class RemapSpigotAt : BaseTask() {
|
||||
|
@ -108,7 +109,7 @@ abstract class RemapSpigotAt : BaseTask() {
|
|||
val mappings = MappingFormats.TINY.read(mapping.path, SPIGOT_NAMESPACE, DEOBF_NAMESPACE)
|
||||
val remappedAt = outputAt.remap(mappings)
|
||||
|
||||
AccessTransformFormats.FML.write(outputFile.path, remappedAt)
|
||||
AccessTransformFormats.FML.writeLF(outputFile.path, remappedAt)
|
||||
}
|
||||
|
||||
private fun parseAccess(text: String): AccessTransform {
|
||||
|
|
|
@ -71,6 +71,9 @@ abstract class DownloadTask : DefaultTask() {
|
|||
fun run() = downloader.get().download(url, outputFile, expectedHash.orNull)
|
||||
}
|
||||
|
||||
@CacheableTask
|
||||
abstract class CacheableDownloadTask : DownloadTask()
|
||||
|
||||
@CacheableTask
|
||||
abstract class DownloadMcLibraries : BaseTask() {
|
||||
|
||||
|
@ -100,7 +103,7 @@ abstract class DownloadMcLibraries : BaseTask() {
|
|||
|
||||
@TaskAction
|
||||
fun run() {
|
||||
downloadMinecraftLibraries(
|
||||
downloadLibraries(
|
||||
downloader,
|
||||
workerExecutor,
|
||||
outputDir.path,
|
||||
|
@ -111,20 +114,62 @@ abstract class DownloadMcLibraries : BaseTask() {
|
|||
}
|
||||
}
|
||||
|
||||
fun downloadMinecraftLibraries(
|
||||
@CacheableTask
|
||||
abstract class DownloadPaperLibraries : BaseTask() {
|
||||
|
||||
@get:Input
|
||||
abstract val paperDependencies: ListProperty<String>
|
||||
|
||||
@get:Input
|
||||
abstract val repositories: ListProperty<String>
|
||||
|
||||
@get:OutputDirectory
|
||||
abstract val outputDir: DirectoryProperty
|
||||
|
||||
@get:Internal
|
||||
abstract val downloader: Property<DownloadService>
|
||||
|
||||
@get:Inject
|
||||
abstract val workerExecutor: WorkerExecutor
|
||||
|
||||
@get:Input
|
||||
abstract val sources: Property<Boolean>
|
||||
|
||||
override fun init() {
|
||||
super.init()
|
||||
sources.convention(false)
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun run() {
|
||||
downloadLibraries(
|
||||
downloader,
|
||||
workerExecutor,
|
||||
outputDir.path,
|
||||
repositories.get(),
|
||||
paperDependencies.get(),
|
||||
sources.get()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun downloadLibraries(
|
||||
download: Provider<DownloadService>,
|
||||
workerExecutor: WorkerExecutor,
|
||||
targetDir: Path,
|
||||
repositories: List<String>,
|
||||
mcLibraries: List<String>,
|
||||
libraries: List<String>,
|
||||
sources: Boolean
|
||||
): WorkQueue {
|
||||
val excludes = listOf(targetDir.fileSystem.getPathMatcher("glob:*.etag"))
|
||||
targetDir.deleteRecursive(excludes)
|
||||
if (!targetDir.exists()) {
|
||||
targetDir.createDirectories()
|
||||
}
|
||||
|
||||
val queue = workerExecutor.noIsolation()
|
||||
|
||||
for (lib in mcLibraries) {
|
||||
for (lib in libraries) {
|
||||
if (sources) {
|
||||
queue.submit(DownloadSourcesToDirAction::class) {
|
||||
repos.set(repositories)
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* 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.tasks.mache
|
||||
|
||||
import io.papermc.paperweight.util.*
|
||||
import io.papermc.paperweight.util.constants.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.io.path.absolutePathString
|
||||
import kotlin.io.path.deleteIfExists
|
||||
import kotlin.io.path.name
|
||||
import kotlin.io.path.outputStream
|
||||
import kotlin.io.path.writeText
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.ProjectLayout
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.tasks.CacheableTask
|
||||
import org.gradle.api.tasks.Classpath
|
||||
import org.gradle.api.tasks.CompileClasspath
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.PathSensitive
|
||||
import org.gradle.api.tasks.PathSensitivity
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.process.ExecOperations
|
||||
|
||||
@CacheableTask
|
||||
abstract class DecompileJar : DefaultTask() {
|
||||
|
||||
@get:PathSensitive(PathSensitivity.NONE)
|
||||
@get:InputFile
|
||||
abstract val inputJar: RegularFileProperty
|
||||
|
||||
@get:Input
|
||||
abstract val decompilerArgs: ListProperty<String>
|
||||
|
||||
@get:CompileClasspath
|
||||
abstract val minecraftClasspath: ConfigurableFileCollection
|
||||
|
||||
@get:Classpath
|
||||
abstract val decompiler: ConfigurableFileCollection
|
||||
|
||||
@get:OutputFile
|
||||
abstract val outputJar: RegularFileProperty
|
||||
|
||||
@get:Inject
|
||||
abstract val exec: ExecOperations
|
||||
|
||||
@get:Inject
|
||||
abstract val layout: ProjectLayout
|
||||
|
||||
@TaskAction
|
||||
fun run() {
|
||||
val out = outputJar.convertToPath().ensureClean()
|
||||
|
||||
val cfgFile = layout.buildDirectory.file(DECOMP_CFG).convertToPath().ensureClean()
|
||||
val cfgText = buildString {
|
||||
for (file in minecraftClasspath.files) {
|
||||
append("-e=")
|
||||
append(file.toPath().absolutePathString())
|
||||
append(System.lineSeparator())
|
||||
}
|
||||
}
|
||||
cfgFile.writeText(cfgText)
|
||||
|
||||
val logs = out.resolveSibling("${out.name}.log")
|
||||
|
||||
logs.outputStream().buffered().use { log ->
|
||||
exec.javaexec {
|
||||
classpath(decompiler)
|
||||
mainClass.set("org.jetbrains.java.decompiler.main.decompiler.ConsoleDecompiler")
|
||||
|
||||
maxHeapSize = "3G"
|
||||
|
||||
args(decompilerArgs.get())
|
||||
args("-cfg", cfgFile.absolutePathString())
|
||||
|
||||
args(inputJar.convertToPath().absolutePathString())
|
||||
args(out.absolutePathString())
|
||||
|
||||
standardOutput = log
|
||||
errorOutput = log
|
||||
}
|
||||
}
|
||||
|
||||
out.openZip().use { root ->
|
||||
root.getPath("META-INF", "MANIFEST.MF").deleteIfExists()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* 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.tasks.mache
|
||||
|
||||
import io.papermc.paperweight.util.*
|
||||
import javax.inject.Inject
|
||||
import kotlin.io.path.*
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.ProjectLayout
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.process.ExecOperations
|
||||
|
||||
@CacheableTask
|
||||
abstract class RemapJar : DefaultTask() {
|
||||
|
||||
@get:PathSensitive(PathSensitivity.NONE)
|
||||
@get:InputFile
|
||||
abstract val serverJar: RegularFileProperty
|
||||
|
||||
@get:PathSensitive(PathSensitivity.NONE)
|
||||
@get:InputFile
|
||||
abstract val serverMappings: RegularFileProperty
|
||||
|
||||
@get:Input
|
||||
abstract val remapperArgs: ListProperty<String>
|
||||
|
||||
@get:Classpath
|
||||
abstract val codebookClasspath: ConfigurableFileCollection
|
||||
|
||||
@get:CompileClasspath
|
||||
abstract val minecraftClasspath: ConfigurableFileCollection
|
||||
|
||||
@get:Classpath
|
||||
abstract val remapperClasspath: ConfigurableFileCollection
|
||||
|
||||
@get:PathSensitive(PathSensitivity.NONE)
|
||||
@get:InputFiles
|
||||
abstract val paramMappings: ConfigurableFileCollection
|
||||
|
||||
@get:Classpath
|
||||
abstract val constants: ConfigurableFileCollection
|
||||
|
||||
@get:OutputFile
|
||||
abstract val outputJar: RegularFileProperty
|
||||
|
||||
@get:Inject
|
||||
abstract val exec: ExecOperations
|
||||
|
||||
@get:Inject
|
||||
abstract val layout: ProjectLayout
|
||||
|
||||
@TaskAction
|
||||
fun run() {
|
||||
val out = outputJar.convertToPath().ensureClean()
|
||||
|
||||
val logFile = out.resolveSibling("${out.name}.log")
|
||||
|
||||
logFile.outputStream().buffered().use { log ->
|
||||
exec.javaexec {
|
||||
classpath(codebookClasspath.singleFile)
|
||||
|
||||
maxHeapSize = "2G"
|
||||
|
||||
remapperArgs.get().forEach { arg ->
|
||||
args(
|
||||
arg
|
||||
.replace(Regex("\\{tempDir}")) { layout.buildDirectory.dir(".tmp_codebook").get().asFile.absolutePath }
|
||||
.replace(Regex("\\{remapperFile}")) { remapperClasspath.singleFile.absolutePath }
|
||||
.replace(Regex("\\{mappingsFile}")) { serverMappings.get().asFile.absolutePath }
|
||||
.replace(Regex("\\{paramsFile}")) { paramMappings.singleFile.absolutePath }
|
||||
.replace(Regex("\\{constantsFile}")) { constants.singleFile.absolutePath }
|
||||
.replace(Regex("\\{output}")) { outputJar.get().asFile.absolutePath }
|
||||
.replace(Regex("\\{input}")) { serverJar.get().asFile.absolutePath }
|
||||
.replace(Regex("\\{inputClasspath}")) { minecraftClasspath.files.joinToString(":") { it.absolutePath } }
|
||||
)
|
||||
}
|
||||
|
||||
standardOutput = log
|
||||
errorOutput = log
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* 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.tasks.mache
|
||||
|
||||
import codechicken.diffpatch.cli.PatchOperation
|
||||
import codechicken.diffpatch.util.LoggingOutputStream
|
||||
import codechicken.diffpatch.util.archiver.ArchiveFormat
|
||||
import io.papermc.paperweight.tasks.*
|
||||
import io.papermc.paperweight.util.*
|
||||
import io.papermc.restamp.Restamp
|
||||
import io.papermc.restamp.RestampContextConfiguration
|
||||
import io.papermc.restamp.RestampInput
|
||||
import java.nio.file.Path
|
||||
import java.util.function.Predicate
|
||||
import kotlin.io.path.*
|
||||
import org.cadixdev.at.io.AccessTransformFormats
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.api.ResetCommand
|
||||
import org.eclipse.jgit.lib.PersonIdent
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.logging.LogLevel
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.*
|
||||
import org.openrewrite.InMemoryExecutionContext
|
||||
|
||||
abstract class SetupVanilla : BaseTask() {
|
||||
|
||||
@get:PathSensitive(PathSensitivity.NONE)
|
||||
@get:InputFile
|
||||
abstract val inputFile: RegularFileProperty
|
||||
|
||||
@get:Internal
|
||||
abstract val predicate: Property<Predicate<Path>>
|
||||
|
||||
@get:OutputDirectory
|
||||
abstract val outputDir: DirectoryProperty
|
||||
|
||||
@get:Internal
|
||||
abstract val machePatches: DirectoryProperty
|
||||
|
||||
@get:Optional
|
||||
@get:InputFile
|
||||
@get:PathSensitive(PathSensitivity.NONE)
|
||||
abstract val ats: RegularFileProperty
|
||||
|
||||
@get:Optional
|
||||
@get:InputFiles
|
||||
abstract val libraries: ConfigurableFileCollection
|
||||
|
||||
@get:Optional
|
||||
@get:InputFiles
|
||||
abstract val paperPatches: ConfigurableFileCollection
|
||||
|
||||
@get:Optional
|
||||
@get:InputFile
|
||||
abstract val devImports: RegularFileProperty
|
||||
|
||||
@get:Optional
|
||||
@get:CompileClasspath
|
||||
abstract val minecraftClasspath: ConfigurableFileCollection
|
||||
|
||||
@get:Optional
|
||||
@get:Classpath
|
||||
abstract val mache: ConfigurableFileCollection
|
||||
|
||||
@TaskAction
|
||||
fun run() {
|
||||
val outputPath = outputDir.convertToPath()
|
||||
|
||||
val git: Git
|
||||
if (outputPath.resolve(".git/HEAD").isRegularFile()) {
|
||||
git = Git.open(outputPath.toFile())
|
||||
git.reset().setRef("ROOT").setMode(ResetCommand.ResetType.HARD).call()
|
||||
} else {
|
||||
outputPath.createDirectories()
|
||||
|
||||
git = Git.init()
|
||||
.setDirectory(outputPath.toFile())
|
||||
.setInitialBranch("main")
|
||||
.call()
|
||||
|
||||
val rootIdent = PersonIdent("ROOT", "root@automated.papermc.io")
|
||||
git.commit().setMessage("ROOT").setAllowEmpty(true).setAuthor(rootIdent).setSign(false).call()
|
||||
git.tagDelete().setTags("ROOT").call()
|
||||
git.tag().setName("ROOT").setTagger(rootIdent).setSigned(false).call()
|
||||
}
|
||||
|
||||
println("Copy initial sources...")
|
||||
inputFile.convertToPath().openZip().walk()
|
||||
.filter(predicate.get())
|
||||
.forEach {
|
||||
val target = outputPath.resolve(it.toString().substring(1))
|
||||
target.parent.createDirectories()
|
||||
// make sure we have a trailing newline
|
||||
var content = it.readText()
|
||||
if (!content.endsWith("\n")) {
|
||||
content += "\n"
|
||||
}
|
||||
target.writeText(content)
|
||||
}
|
||||
|
||||
println("Setup git repo...")
|
||||
commitAndTag(git, "Vanilla")
|
||||
|
||||
if (machePatches.isPresent) {
|
||||
println("Applying mache patches...")
|
||||
|
||||
val result = PatchOperation.builder()
|
||||
.logTo(LoggingOutputStream(logger, LogLevel.LIFECYCLE))
|
||||
.basePath(outputPath.convertToPath())
|
||||
.outputPath(outputPath.convertToPath())
|
||||
.patchesPath(mache.singleFile.toPath(), ArchiveFormat.ZIP)
|
||||
.patchesPrefix("patches")
|
||||
.level(codechicken.diffpatch.util.LogLevel.INFO)
|
||||
.ignorePrefix(".git")
|
||||
.build()
|
||||
.operate()
|
||||
|
||||
commitAndTag(git, "Mache")
|
||||
|
||||
if (result.exit != 0) {
|
||||
throw Exception("Failed to apply ${result.summary.failedMatches} mache patches")
|
||||
}
|
||||
|
||||
logger.lifecycle("Applied ${result.summary.changedFiles} mache patches")
|
||||
}
|
||||
|
||||
if (ats.isPresent) {
|
||||
val classPath = minecraftClasspath.files.map { it.toPath() }.toMutableList()
|
||||
classPath.add(outputPath)
|
||||
|
||||
println("Applying access transformers...")
|
||||
val configuration = RestampContextConfiguration.builder()
|
||||
.accessTransformers(ats.convertToPath(), AccessTransformFormats.FML)
|
||||
.sourceRoot(outputPath)
|
||||
.sourceFilesFromAccessTransformers(false)
|
||||
.classpath(classPath)
|
||||
.executionContext(InMemoryExecutionContext { it.printStackTrace() })
|
||||
.failWithNotApplicableAccessTransformers()
|
||||
.build()
|
||||
|
||||
val parsedInput = RestampInput.parseFrom(configuration)
|
||||
val results = Restamp.run(parsedInput).allResults
|
||||
|
||||
results.forEach { result ->
|
||||
if (result.after != null) {
|
||||
outputPath.resolve(result.after!!.sourcePath).writeText(result.after!!.printAll())
|
||||
}
|
||||
}
|
||||
|
||||
commitAndTag(git, "ATs")
|
||||
}
|
||||
|
||||
if (!libraries.isEmpty && !paperPatches.isEmpty) {
|
||||
val patches = paperPatches.files.flatMap { it.toPath().walk().filter { path -> path.toString().endsWith(".patch") }.toList() }
|
||||
McDev.importMcDev(patches, null, devImports.pathOrNull, outputPath, null, libraries.files.map { it.toPath() }, true, "")
|
||||
|
||||
commitAndTag(git, "Imports")
|
||||
}
|
||||
|
||||
git.close()
|
||||
}
|
||||
|
||||
private fun commitAndTag(git: Git, name: String) {
|
||||
val vanillaIdent = PersonIdent(name, "${name.lowercase()}@automated.papermc.io")
|
||||
|
||||
git.add().addFilepattern(".").call()
|
||||
git.commit()
|
||||
.setMessage(name)
|
||||
.setAuthor(vanillaIdent)
|
||||
.setSign(false)
|
||||
.call()
|
||||
git.tagDelete().setTags(name).call()
|
||||
git.tag().setName(name).setTagger(vanillaIdent).setSigned(false).call()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* 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.tasks.softspoon
|
||||
|
||||
import io.papermc.paperweight.tasks.*
|
||||
import io.papermc.paperweight.util.*
|
||||
import javax.inject.Inject
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.ProviderFactory
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputDirectory
|
||||
import org.gradle.api.tasks.PathSensitive
|
||||
import org.gradle.api.tasks.PathSensitivity
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.api.tasks.UntrackedTask
|
||||
|
||||
@UntrackedTask(because = "Always apply patches")
|
||||
abstract class ApplyFeaturePatches : ControllableOutputTask() {
|
||||
|
||||
@get:PathSensitive(PathSensitivity.NONE)
|
||||
@get:InputDirectory
|
||||
abstract val repo: DirectoryProperty
|
||||
|
||||
@get:PathSensitive(PathSensitivity.NONE)
|
||||
@get:InputDirectory
|
||||
abstract val patches: DirectoryProperty
|
||||
|
||||
@get:Inject
|
||||
abstract val providers: ProviderFactory
|
||||
|
||||
@get:Input
|
||||
abstract val verbose: Property<Boolean>
|
||||
|
||||
override fun init() {
|
||||
printOutput.convention(false).finalizeValueOnRead()
|
||||
verbose.convention(false)
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun run() {
|
||||
Git.checkForGit()
|
||||
|
||||
val repoPath = repo.convertToPath()
|
||||
|
||||
val git = Git(repoPath)
|
||||
|
||||
if (git("checkout", "main").runSilently(silenceErr = true) != 0) {
|
||||
git("checkout", "-b", "main").runSilently(silenceErr = true)
|
||||
}
|
||||
git("reset", "--hard", "file").executeSilently(silenceErr = true)
|
||||
git("gc").runSilently(silenceErr = true)
|
||||
|
||||
applyGitPatches(git, "server repo", repoPath, patches.convertToPath(), printOutput.get(), verbose.get())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* 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.tasks.softspoon
|
||||
|
||||
import codechicken.diffpatch.cli.PatchOperation
|
||||
import codechicken.diffpatch.match.FuzzyLineMatcher
|
||||
import codechicken.diffpatch.util.LoggingOutputStream
|
||||
import codechicken.diffpatch.util.PatchMode
|
||||
import io.papermc.paperweight.tasks.*
|
||||
import io.papermc.paperweight.util.*
|
||||
import java.io.PrintStream
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.*
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.eclipse.jgit.lib.PersonIdent
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.logging.LogLevel
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputDirectory
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.PathSensitive
|
||||
import org.gradle.api.tasks.PathSensitivity
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.api.tasks.UntrackedTask
|
||||
import org.gradle.api.tasks.options.Option
|
||||
|
||||
@UntrackedTask(because = "Always apply patches")
|
||||
abstract class ApplyFilePatches : BaseTask() {
|
||||
|
||||
@get:Input
|
||||
@get:Option(
|
||||
option = "verbose",
|
||||
description = "Prints out more info about the patching process",
|
||||
)
|
||||
abstract val verbose: Property<Boolean>
|
||||
|
||||
@get:PathSensitive(PathSensitivity.NONE)
|
||||
@get:InputDirectory
|
||||
abstract val input: DirectoryProperty
|
||||
|
||||
@get:OutputDirectory
|
||||
abstract val output: DirectoryProperty
|
||||
|
||||
@get:PathSensitive(PathSensitivity.NONE)
|
||||
@get:InputDirectory
|
||||
abstract val patches: DirectoryProperty
|
||||
|
||||
init {
|
||||
run {
|
||||
verbose.convention(false)
|
||||
}
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
open fun run() {
|
||||
io.papermc.paperweight.util.Git.checkForGit()
|
||||
|
||||
val outputPath = output.convertToPath()
|
||||
recreateCloneDirectory(outputPath)
|
||||
|
||||
checkoutRepoFromUpstream(Git(outputPath), input.convertToPath(), "main", "mache", "main")
|
||||
|
||||
setupGitHook(outputPath)
|
||||
|
||||
val printStream = PrintStream(LoggingOutputStream(logger, LogLevel.LIFECYCLE))
|
||||
val result = PatchOperation.builder()
|
||||
.logTo(printStream)
|
||||
.basePath(output.convertToPath())
|
||||
.patchesPath(patches.convertToPath())
|
||||
.outputPath(output.convertToPath())
|
||||
.level(if (verbose.get()) codechicken.diffpatch.util.LogLevel.ALL else codechicken.diffpatch.util.LogLevel.INFO)
|
||||
.mode(mode())
|
||||
.minFuzz(minFuzz())
|
||||
.summary(verbose.get())
|
||||
.lineEnding("\n")
|
||||
.ignorePrefix(".git")
|
||||
.build()
|
||||
.operate()
|
||||
|
||||
commit()
|
||||
|
||||
if (result.exit != 0) {
|
||||
val total = result.summary.failedMatches + result.summary.exactMatches +
|
||||
result.summary.accessMatches + result.summary.offsetMatches + result.summary.fuzzyMatches
|
||||
throw Exception("Failed to apply ${result.summary.failedMatches}/$total hunks")
|
||||
}
|
||||
|
||||
if (!verbose.get()) {
|
||||
logger.lifecycle("Applied ${result.summary.changedFiles} patches")
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupGitHook(outputPath: Path) {
|
||||
val hook = outputPath.resolve(".git/hooks/post-rewrite")
|
||||
hook.parent.createDirectories()
|
||||
hook.writeText(javaClass.getResource("/post-rewrite.sh")!!.readText())
|
||||
hook.toFile().setExecutable(true)
|
||||
}
|
||||
|
||||
private fun commit() {
|
||||
val ident = PersonIdent("File", "filepatches@automated.papermc.io")
|
||||
val git = Git.open(output.convertToPath().toFile())
|
||||
git.add().addFilepattern(".").call()
|
||||
git.commit()
|
||||
.setMessage("File Patches")
|
||||
.setAuthor(ident)
|
||||
.setSign(false)
|
||||
.call()
|
||||
git.tagDelete().setTags("file").call()
|
||||
git.tag().setName("file").setTagger(ident).setSigned(false).call()
|
||||
git.close()
|
||||
}
|
||||
|
||||
internal open fun mode(): PatchMode {
|
||||
return PatchMode.OFFSET
|
||||
}
|
||||
|
||||
internal open fun minFuzz(): Float {
|
||||
return FuzzyLineMatcher.DEFAULT_MIN_MATCH_SCORE
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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.tasks.softspoon
|
||||
import codechicken.diffpatch.util.PatchMode
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.UntrackedTask
|
||||
import org.gradle.api.tasks.options.Option
|
||||
|
||||
@UntrackedTask(because = "Always apply patches")
|
||||
abstract class ApplyFilePatchesFuzzy : ApplyFilePatches() {
|
||||
|
||||
@get:Input
|
||||
@get:Option(
|
||||
option = "min-fuzz",
|
||||
description = "Min fuzz. The minimum quality needed for a patch to be applied. Default is 0.5.",
|
||||
)
|
||||
abstract val minFuzz: Property<String>
|
||||
|
||||
init {
|
||||
run {
|
||||
minFuzz.convention("0.5")
|
||||
}
|
||||
}
|
||||
|
||||
override fun mode(): PatchMode {
|
||||
return PatchMode.FUZZY
|
||||
}
|
||||
|
||||
override fun minFuzz(): Float {
|
||||
return minFuzz.get().toFloat()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* 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.tasks.softspoon
|
||||
|
||||
import io.papermc.paperweight.tasks.*
|
||||
import io.papermc.paperweight.util.*
|
||||
import io.papermc.restamp.Restamp
|
||||
import io.papermc.restamp.RestampContextConfiguration
|
||||
import io.papermc.restamp.RestampInput
|
||||
import java.nio.file.Files
|
||||
import javax.inject.Inject
|
||||
import kotlin.io.path.*
|
||||
import org.cadixdev.at.io.AccessTransformFormats
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.kotlin.dsl.*
|
||||
import org.gradle.workers.WorkAction
|
||||
import org.gradle.workers.WorkParameters
|
||||
import org.gradle.workers.WorkerExecutor
|
||||
import org.openrewrite.InMemoryExecutionContext
|
||||
|
||||
@CacheableTask
|
||||
abstract class ApplySourceAT : BaseTask() {
|
||||
|
||||
@get:Classpath
|
||||
abstract val inputJar: RegularFileProperty
|
||||
|
||||
@get:OutputFile
|
||||
abstract val outputJar: RegularFileProperty
|
||||
|
||||
@get:Optional
|
||||
@get:InputFile
|
||||
@get:PathSensitive(PathSensitivity.NONE)
|
||||
abstract val atFile: RegularFileProperty
|
||||
|
||||
@get:Optional
|
||||
@get:CompileClasspath
|
||||
abstract val minecraftClasspath: ConfigurableFileCollection
|
||||
|
||||
@get:Inject
|
||||
abstract val worker: WorkerExecutor
|
||||
|
||||
override fun init() {
|
||||
outputJar.convention(defaultOutput())
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun run() {
|
||||
val queue = worker.processIsolation {
|
||||
forkOptions {
|
||||
maxHeapSize = "2G"
|
||||
}
|
||||
}
|
||||
|
||||
val classPath = minecraftClasspath.files.map { it.toPath() }.toMutableList()
|
||||
classPath.add(inputJar.convertToPath())
|
||||
|
||||
queue.submit(RestampWorker::class) {
|
||||
minecraftClasspath.from(minecraftClasspath)
|
||||
atFile.set(atFile)
|
||||
inputJar.set(inputJar)
|
||||
outputJar.set(outputJar)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class RestampWorker : WorkAction<RestampWorker.Params> {
|
||||
interface Params : WorkParameters {
|
||||
val minecraftClasspath: ConfigurableFileCollection
|
||||
val atFile: RegularFileProperty
|
||||
val inputJar: RegularFileProperty
|
||||
val outputJar: RegularFileProperty
|
||||
}
|
||||
|
||||
override fun execute() {
|
||||
val inputZip = parameters.inputJar.convertToPath().openZip()
|
||||
|
||||
val classPath = parameters.minecraftClasspath.files.map { it.toPath() }.toMutableList()
|
||||
classPath.add(parameters.inputJar.convertToPath())
|
||||
|
||||
val configuration = RestampContextConfiguration.builder()
|
||||
.accessTransformers(parameters.atFile.convertToPath(), AccessTransformFormats.FML)
|
||||
.sourceRoot(inputZip.getPath("/"))
|
||||
.sourceFilesFromAccessTransformers()
|
||||
.classpath(classPath)
|
||||
.executionContext(InMemoryExecutionContext { it.printStackTrace() })
|
||||
.failWithNotApplicableAccessTransformers()
|
||||
.build()
|
||||
|
||||
val parsedInput = RestampInput.parseFrom(configuration)
|
||||
val results = Restamp.run(parsedInput).allResults
|
||||
|
||||
parameters.outputJar.convertToPath().writeZip().use { zip ->
|
||||
val alreadyWritten = mutableSetOf<String>()
|
||||
results.forEach { result ->
|
||||
if (result.after == null) {
|
||||
println("Ignoring ${result.before?.sourcePath} because result.after is null?")
|
||||
return@forEach
|
||||
}
|
||||
result.after?.let { after ->
|
||||
zip.getPath(after.sourcePath.toString()).writeText(after.printAll())
|
||||
alreadyWritten.add("/" + after.sourcePath.toString())
|
||||
}
|
||||
}
|
||||
|
||||
inputZip.walk().filter { Files.isRegularFile(it) }.filter { !alreadyWritten.contains(it.toString()) }.forEach { file ->
|
||||
zip.getPath(file.toString()).writeText(file.readText())
|
||||
}
|
||||
|
||||
zip.close()
|
||||
}
|
||||
inputZip.close()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* 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.tasks.softspoon
|
||||
|
||||
import atFromString
|
||||
import codechicken.diffpatch.cli.DiffOperation
|
||||
import codechicken.diffpatch.util.LogLevel
|
||||
import codechicken.diffpatch.util.LoggingOutputStream
|
||||
import io.papermc.paperweight.tasks.*
|
||||
import io.papermc.paperweight.util.*
|
||||
import io.papermc.restamp.Restamp
|
||||
import io.papermc.restamp.RestampContextConfiguration
|
||||
import io.papermc.restamp.RestampInput
|
||||
import java.io.PrintStream
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.*
|
||||
import org.cadixdev.at.AccessTransformSet
|
||||
import org.cadixdev.at.io.AccessTransformFormats
|
||||
import org.cadixdev.bombe.type.signature.MethodSignature
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.api.tasks.options.Option
|
||||
import org.openrewrite.InMemoryExecutionContext
|
||||
import writeLF
|
||||
|
||||
@UntrackedTask(because = "Always rebuild patches")
|
||||
abstract class RebuildFilePatches : BaseTask() {
|
||||
|
||||
@get:Input
|
||||
@get:Option(
|
||||
option = "verbose",
|
||||
description = "Prints out more info about the patching process",
|
||||
)
|
||||
abstract val verbose: Property<Boolean>
|
||||
|
||||
@get:InputDirectory
|
||||
abstract val input: DirectoryProperty
|
||||
|
||||
@get:InputDirectory
|
||||
abstract val base: DirectoryProperty
|
||||
|
||||
@get:OutputDirectory
|
||||
abstract val patches: DirectoryProperty
|
||||
|
||||
@get:Optional
|
||||
@get:InputFile
|
||||
abstract val atFile: RegularFileProperty
|
||||
|
||||
@get:Optional
|
||||
@get:OutputFile
|
||||
abstract val atFileOut: RegularFileProperty
|
||||
|
||||
@get:Optional
|
||||
@get:CompileClasspath
|
||||
abstract val minecraftClasspath: ConfigurableFileCollection
|
||||
|
||||
@get:Input
|
||||
abstract val contextLines: Property<Int>
|
||||
|
||||
override fun init() {
|
||||
contextLines.convention(3)
|
||||
verbose.convention(false)
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun run() {
|
||||
val patchDir = patches.convertToPath().ensureClean()
|
||||
patchDir.createDirectory()
|
||||
val inputDir = input.convertToPath()
|
||||
val baseDir = base.convertToPath()
|
||||
|
||||
val oldAts = if (atFile.isPresent) AccessTransformFormats.FML.read(atFile.convertToPath()) else AccessTransformSet.create()
|
||||
|
||||
val git = Git(inputDir)
|
||||
git("stash", "push").executeSilently(silenceErr = true)
|
||||
git("checkout", "file").executeSilently(silenceErr = true)
|
||||
|
||||
// handle AT
|
||||
baseDir.walk()
|
||||
.map { it.relativeTo(baseDir).toString().replace("\\", "/") }
|
||||
.filter {
|
||||
!it.startsWith(".git") && !it.endsWith(".nbt") && !it.endsWith(".mcassetsroot")
|
||||
}
|
||||
.forEach {
|
||||
val ats = AccessTransformSet.create()
|
||||
val source = inputDir.resolve(it)
|
||||
val decomp = baseDir.resolve(it)
|
||||
val className = it.replace(".java", "")
|
||||
handleATInSource(source, ats, className)
|
||||
handleATInBase(decomp, ats, baseDir)
|
||||
oldAts.merge(ats)
|
||||
}
|
||||
|
||||
if (atFileOut.isPresent) {
|
||||
AccessTransformFormats.FML.writeLF(
|
||||
atFileOut.convertToPath(),
|
||||
oldAts,
|
||||
"# This file is auto generated, any changes may be overridden!\n# See CONTRIBUTING.md on how to add access transformers.\n"
|
||||
)
|
||||
}
|
||||
|
||||
// rebuild patches
|
||||
val printStream = PrintStream(LoggingOutputStream(logger, org.gradle.api.logging.LogLevel.LIFECYCLE))
|
||||
val result = DiffOperation.builder()
|
||||
.logTo(printStream)
|
||||
.aPath(baseDir)
|
||||
.bPath(inputDir)
|
||||
.outputPath(patchDir)
|
||||
.autoHeader(true)
|
||||
.level(if (verbose.get()) LogLevel.ALL else LogLevel.INFO)
|
||||
.lineEnding("\n")
|
||||
.ignorePrefix(".git")
|
||||
.ignorePrefix("data/minecraft/structures")
|
||||
.ignorePrefix("data/.mc")
|
||||
.ignorePrefix("assets/.mc")
|
||||
.context(contextLines.get())
|
||||
.summary(verbose.get())
|
||||
.build()
|
||||
.operate()
|
||||
|
||||
git("switch", "-").executeSilently(silenceErr = true)
|
||||
git("stash", "pop").runSilently(silenceErr = true)
|
||||
|
||||
logger.lifecycle("Rebuilt ${result.summary.changedFiles} patches")
|
||||
}
|
||||
|
||||
private fun handleATInBase(decomp: Path, newAts: AccessTransformSet, decompRoot: Path) {
|
||||
if (newAts.classes.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
val configuration = RestampContextConfiguration.builder()
|
||||
.accessTransformSet(newAts)
|
||||
.sourceRoot(decompRoot)
|
||||
.sourceFiles(listOf(decomp))
|
||||
.classpath(minecraftClasspath.files.map { it.toPath() })
|
||||
.executionContext(InMemoryExecutionContext { it.printStackTrace() })
|
||||
.build()
|
||||
|
||||
val parsedInput = RestampInput.parseFrom(configuration)
|
||||
val results = Restamp.run(parsedInput).allResults
|
||||
|
||||
if (results.size != 1) {
|
||||
logger.lifecycle("Failed to apply AT to ${decomp.fileName} (doesn't it already exist?): $results")
|
||||
return
|
||||
}
|
||||
|
||||
val result = results[0].after?.printAll()
|
||||
if (result != null) {
|
||||
decomp.writeText(result, Charsets.UTF_8)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleATInSource(source: Path, newAts: AccessTransformSet, className: String) {
|
||||
val sourceLines = source.readLines()
|
||||
val fixedLines = ArrayList<String>(sourceLines.size)
|
||||
var requiresWrite = false
|
||||
sourceLines.forEach { line ->
|
||||
if (!line.contains("// Paper-AT: ")) {
|
||||
fixedLines.add(line)
|
||||
return@forEach
|
||||
}
|
||||
|
||||
requiresWrite = true
|
||||
|
||||
val split = line.split("// Paper-AT: ")
|
||||
val at = split[1]
|
||||
val atClass = newAts.getOrCreateClass(className)
|
||||
val parts = at.split(" ")
|
||||
val accessTransform = atFromString(parts[0])
|
||||
val name = parts[1]
|
||||
val index = name.indexOf('(')
|
||||
if (index == -1) {
|
||||
atClass.mergeField(name, accessTransform)
|
||||
} else {
|
||||
atClass.mergeMethod(MethodSignature.of(name.substring(0, index), name.substring(index)), accessTransform)
|
||||
}
|
||||
logger.lifecycle("Found new AT in $className: $at -> $accessTransform")
|
||||
|
||||
fixedLines.add(split[0])
|
||||
}
|
||||
|
||||
if (requiresWrite) {
|
||||
source.writeText(fixedLines.joinToString("\n", postfix = "\n"), Charsets.UTF_8)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,16 +35,17 @@ object McDev {
|
|||
|
||||
fun importMcDev(
|
||||
patches: Iterable<Path>,
|
||||
decompJar: Path,
|
||||
decompJar: Path?,
|
||||
importsFile: Path?,
|
||||
targetDir: Path,
|
||||
dataTargetDir: Path? = null,
|
||||
librariesDirs: List<Path> = listOf(),
|
||||
printOutput: Boolean = true
|
||||
printOutput: Boolean = true,
|
||||
javaSourceSet: String = "/src/main/java"
|
||||
) {
|
||||
val (javaPatchLines, dataPatchLines) = readPatchLines(patches)
|
||||
val (javaPatchLines, dataPatchLines) = readPatchLines(patches, javaSourceSet)
|
||||
|
||||
decompJar.openZip().use { zipFile ->
|
||||
decompJar?.openZip()?.use { zipFile ->
|
||||
val decompSourceFiles = mutableSetOf<String>()
|
||||
val decompDataFiles = mutableSetOf<String>()
|
||||
|
||||
|
@ -127,7 +128,7 @@ object McDev {
|
|||
}
|
||||
|
||||
// Import library classes
|
||||
val imports = findLibraries(importsFile, libFiles, javaPatchLines)
|
||||
val imports = findLibraries(importsFile, libFiles, javaPatchLines, javaSourceSet)
|
||||
logger.log(if (printOutput) LogLevel.LIFECYCLE else LogLevel.DEBUG, "Importing {} classes from library sources...", imports.size)
|
||||
|
||||
for ((libraryFileName, importFilePath) in imports) {
|
||||
|
@ -170,11 +171,11 @@ object McDev {
|
|||
}
|
||||
}
|
||||
|
||||
private fun readPatchLines(patches: Iterable<Path>): Pair<Set<String>, Set<String>> {
|
||||
private fun readPatchLines(patches: Iterable<Path>, javaSourceSet: String): Pair<Set<String>, Set<String>> {
|
||||
val srcResult = hashSetOf<String>()
|
||||
val dataResult = hashSetOf<String>()
|
||||
|
||||
val javaPrefix = "+++ b/src/main/java/"
|
||||
val javaPrefix = "+++ b$javaSourceSet/"
|
||||
val dataPrefix = "+++ b/src/main/resources/data/minecraft/"
|
||||
|
||||
for (patch in patches) {
|
||||
|
@ -216,7 +217,7 @@ object McDev {
|
|||
return Pair(srcResult, dataResult)
|
||||
}
|
||||
|
||||
private fun findLibraries(libraryImports: Path?, libFiles: List<Path>, patchLines: Set<String>): Set<LibraryImport> {
|
||||
private fun findLibraries(libraryImports: Path?, libFiles: List<Path>, patchLines: Set<String>, javaSourceSet: String): Set<LibraryImport> {
|
||||
val result = hashSetOf<LibraryImport>()
|
||||
|
||||
// Imports from library-imports.txt
|
||||
|
@ -233,15 +234,15 @@ object McDev {
|
|||
}
|
||||
|
||||
// Scan patches for necessary imports
|
||||
result += findNeededLibraryImports(patchLines, libFiles)
|
||||
result += findNeededLibraryImports(patchLines, libFiles, javaSourceSet)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private fun findNeededLibraryImports(patchLines: Set<String>, libFiles: List<Path>): Set<LibraryImport> {
|
||||
private fun findNeededLibraryImports(patchLines: Set<String>, libFiles: List<Path>, javaSourceSet: String): Set<LibraryImport> {
|
||||
val knownImportMap = findPossibleLibraryImports(libFiles)
|
||||
.associateBy { it.importFilePath }
|
||||
val prefix = "+++ b/src/main/java/"
|
||||
val prefix = "+++ b$javaSourceSet/"
|
||||
return patchLines.map { it.substringAfter(prefix) }
|
||||
.mapNotNull { knownImportMap[it] }
|
||||
.toSet()
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
import java.io.BufferedWriter
|
||||
import java.io.StringWriter
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.*
|
||||
import org.cadixdev.at.AccessChange
|
||||
import org.cadixdev.at.AccessTransform
|
||||
import org.cadixdev.at.AccessTransformSet
|
||||
import org.cadixdev.at.ModifierChange
|
||||
import org.cadixdev.at.io.AccessTransformFormat
|
||||
import org.cadixdev.at.io.AccessTransformFormats
|
||||
|
||||
fun atFromString(input: String): AccessTransform {
|
||||
var last = input.length - 1
|
||||
|
||||
val final = if (input[last] == 'f') {
|
||||
if (input[--last] == '-') ModifierChange.REMOVE else ModifierChange.ADD
|
||||
} else {
|
||||
ModifierChange.NONE
|
||||
}
|
||||
|
||||
val access = when (input.split("+", "-").first()) {
|
||||
"public" -> AccessChange.PUBLIC
|
||||
"protected" -> AccessChange.PROTECTED
|
||||
"private" -> AccessChange.PRIVATE
|
||||
else -> AccessChange.NONE
|
||||
}
|
||||
|
||||
return AccessTransform.of(access, final)
|
||||
}
|
||||
|
||||
fun atToString(at: AccessTransform): String {
|
||||
val access = when (at.access) {
|
||||
AccessChange.PRIVATE -> "private"
|
||||
AccessChange.PROTECTED -> "protected"
|
||||
AccessChange.PUBLIC -> "public"
|
||||
else -> ""
|
||||
}
|
||||
val final = when (at.final) {
|
||||
ModifierChange.REMOVE -> "-f"
|
||||
ModifierChange.ADD -> "+f"
|
||||
else -> ""
|
||||
}
|
||||
return access + final
|
||||
}
|
||||
|
||||
fun AccessTransformFormat.writeLF(path: Path, at: AccessTransformSet, header: String = "") {
|
||||
val stringWriter = StringWriter()
|
||||
val writer = BufferedWriter(stringWriter)
|
||||
AccessTransformFormats.FML.write(writer, at)
|
||||
writer.close()
|
||||
// unify line endings
|
||||
val lines = stringWriter.toString().replace("\r\n", "\n").split("\n")
|
||||
// remove last empty line, the sort, then add it back
|
||||
path.writeText(lines.subList(0, lines.size - 1).sorted().joinToString("\n", header, "\n"), Charsets.UTF_8)
|
||||
}
|
|
@ -44,6 +44,7 @@ const val REMAPPER_CONFIG = "remapper"
|
|||
const val PLUGIN_REMAPPER_CONFIG = "pluginRemapper"
|
||||
const val DECOMPILER_CONFIG = "decompiler"
|
||||
const val PAPERCLIP_CONFIG = "paperclip"
|
||||
const val MACHE_CONFIG = "mache"
|
||||
const val DEV_BUNDLE_CONFIG = "paperweightDevelopmentBundle"
|
||||
const val MOJANG_MAPPED_SERVER_CONFIG = "mojangMappedServer"
|
||||
const val MOJANG_MAPPED_SERVER_RUNTIME_CONFIG = "mojangMappedServerRuntime"
|
||||
|
@ -54,6 +55,7 @@ const val SERVER_RUNTIME_CLASSPATH = "serverRuntimeClasspath"
|
|||
const val PARAM_MAPPINGS_REPO_NAME = "paperweightParamMappingsRepository"
|
||||
const val DECOMPILER_REPO_NAME = "paperweightDecompilerRepository"
|
||||
const val REMAPPER_REPO_NAME = "paperweightRemapperRepository"
|
||||
const val MACHE_REPO_NAME = "paperweightMacheRepository"
|
||||
|
||||
const val CACHE_PATH = "caches"
|
||||
private const val PAPER_PATH = "paperweight"
|
||||
|
@ -77,6 +79,9 @@ const val MINECRAFT_SOURCES_PATH = "$JARS_PATH/minecraft-sources"
|
|||
const val SPIGOT_JARS_PATH = "$JARS_PATH/spigot"
|
||||
const val SPIGOT_SOURCES_JARS_PATH = "$JARS_PATH/spigot-sources"
|
||||
|
||||
const val PAPER_JARS_PATH = "$JARS_PATH/paper"
|
||||
const val PAPER_SOURCES_JARS_PATH = "$JARS_PATH/paper-sources"
|
||||
|
||||
private const val MAPPINGS_DIR = "$PAPER_PATH/mappings"
|
||||
const val SERVER_MAPPINGS = "$MAPPINGS_DIR/server_mappings.txt"
|
||||
const val MOJANG_YARN_MAPPINGS = "$MAPPINGS_DIR/official-mojang+yarn.tiny"
|
||||
|
@ -90,10 +95,12 @@ const val PATCHED_SPIGOT_MOJANG_YARN_SOURCE_MAPPINGS = "$MAPPINGS_DIR/spigot-moj
|
|||
const val REOBF_MOJANG_SPIGOT_MAPPINGS = "$MAPPINGS_DIR/mojang+yarn-spigot-reobf.tiny"
|
||||
const val PATCHED_REOBF_MOJANG_SPIGOT_MAPPINGS = "$MAPPINGS_DIR/mojang+yarn-spigot-reobf-patched.tiny"
|
||||
const val RELOCATED_PATCHED_REOBF_MOJANG_SPIGOT_MAPPINGS = "$MAPPINGS_DIR/mojang+yarn-spigot-reobf-patched-relocated.tiny"
|
||||
const val SPIGOT_MOJANG_PARCHMENT_MAPPINGS = "$MAPPINGS_DIR/spigot-mojang+parchment.tiny"
|
||||
|
||||
const val OBF_NAMESPACE = "official"
|
||||
const val SPIGOT_NAMESPACE = "spigot"
|
||||
const val DEOBF_NAMESPACE = "mojang+yarn"
|
||||
const val NEW_DEOBF_NAMESPACE = "mojang+parchment"
|
||||
const val MAPPINGS_NAMESPACE_MANIFEST_KEY = "paperweight-mappings-namespace"
|
||||
|
||||
private const val DATA_PATH = "$PAPER_PATH/data"
|
||||
|
@ -105,13 +112,17 @@ const val SERVER_VERSION_JSON = "$BUNDLER_PATH/version.json"
|
|||
const val SERVER_LIBRARIES_TXT = "$BUNDLER_PATH/ServerLibraries.txt"
|
||||
const val SERVER_LIBRARIES_LIST = "$BUNDLER_PATH/libraries.list"
|
||||
const val SERVER_VERSIONS_LIST = "$BUNDLER_PATH/versions.list"
|
||||
const val SERVER_JAR = "$BUNDLER_PATH/server.jar"
|
||||
|
||||
private const val SETUP_CACHE = "$PAPER_PATH/setupCache"
|
||||
private const val TASK_CACHE = "$PAPER_PATH/taskCache"
|
||||
|
||||
const val FINAL_REMAPPED_JAR = "$TASK_CACHE/minecraft.jar"
|
||||
const val FINAL_REMAPPED_CODEBOOK_JAR = "$TASK_CACHE/codebook-minecraft.jar"
|
||||
const val FINAL_FILTERED_REMAPPED_JAR = "$TASK_CACHE/filteredMinecraft.jar"
|
||||
const val FINAL_DECOMPILE_JAR = "$TASK_CACHE/decompileJar.jar"
|
||||
const val SPIGOT_MACHE_DECOMPILE_JAR = "$TASK_CACHE/macheSpigotDecompileJar.jar"
|
||||
const val DECOMP_CFG = "$TASK_CACHE/decomp_cfg.txt"
|
||||
|
||||
const val MC_DEV_SOURCES_DIR = "$PAPER_PATH/mc-dev-sources"
|
||||
|
||||
|
@ -119,6 +130,13 @@ const val IVY_REPOSITORY = "$PAPER_PATH/ivyRepository"
|
|||
|
||||
const val DOWNLOAD_SERVICE_NAME = "paperweightDownloadService"
|
||||
|
||||
private const val MACHE_PATH = "$PAPER_PATH/mache"
|
||||
const val PATCHED_JAR = "$MACHE_PATH/patched.jar"
|
||||
const val FAILED_PATCH_JAR = "$MACHE_PATH/failed.jar"
|
||||
const val PATCHES_FOLDER = "$MACHE_PATH/patches"
|
||||
const val BASE_PROJECT = "$MACHE_PATH/base"
|
||||
const val REMAPPED_CB = "$MACHE_PATH/remapped-cb"
|
||||
|
||||
fun paperSetupOutput(name: String, ext: String) = "$SETUP_CACHE/$name.$ext"
|
||||
fun Task.paperTaskOutput(ext: String) = paperTaskOutput(name, ext)
|
||||
fun paperTaskOutput(name: String, ext: String) = "$TASK_CACHE/$name.$ext"
|
||||
|
|
|
@ -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.util.data.mache
|
||||
|
||||
data class MacheAdditionalDependencies(
|
||||
val compileOnly: List<MavenArtifact>? = null,
|
||||
val implementation: List<MavenArtifact>? = null,
|
||||
)
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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.util.data.mache
|
||||
|
||||
data class MacheDependencies(
|
||||
val codebook: List<MavenArtifact>,
|
||||
val paramMappings: List<MavenArtifact>,
|
||||
val constants: List<MavenArtifact>,
|
||||
val remapper: List<MavenArtifact>,
|
||||
val decompiler: List<MavenArtifact>,
|
||||
)
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* 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.util.data.mache
|
||||
|
||||
data class MacheMeta(
|
||||
val minecraftVersion: String,
|
||||
val macheVersion: String,
|
||||
val dependencies: MacheDependencies,
|
||||
val repositories: List<MacheRepository>,
|
||||
val decompilerArgs: List<String>,
|
||||
val remapperArgs: List<String>,
|
||||
val additionalCompileDependencies: MacheAdditionalDependencies? = null,
|
||||
)
|
|
@ -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.util.data.mache
|
||||
|
||||
data class MacheRepository(
|
||||
val url: String,
|
||||
val name: String,
|
||||
val groups: List<String>? = null,
|
||||
)
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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.util.data.mache
|
||||
|
||||
data class MavenArtifact(
|
||||
val group: String,
|
||||
val name: String,
|
||||
val version: String,
|
||||
val classifier: String? = null,
|
||||
val extension: String? = null,
|
||||
) {
|
||||
fun toMavenString(): String {
|
||||
return "$group:$name:$version" + (classifier?.let { ":$it" } ?: "") + (extension?.let { "@$it" } ?: "")
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@ import io.papermc.paperweight.PaperweightException
|
|||
import java.io.InputStream
|
||||
import java.net.URI
|
||||
import java.nio.file.FileSystem
|
||||
import java.nio.file.FileSystemNotFoundException
|
||||
import java.nio.file.FileSystems
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
|
@ -35,6 +36,9 @@ import java.util.Arrays
|
|||
import java.util.stream.Collectors
|
||||
import java.util.stream.Stream
|
||||
import java.util.stream.StreamSupport
|
||||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipInputStream
|
||||
import java.util.zip.ZipOutputStream
|
||||
import kotlin.io.path.*
|
||||
import kotlin.streams.asSequence
|
||||
import org.gradle.api.Project
|
||||
|
@ -142,13 +146,41 @@ private fun Path.jarUri(): URI {
|
|||
}
|
||||
|
||||
fun Path.openZip(): FileSystem {
|
||||
return FileSystems.newFileSystem(jarUri(), emptyMap<String, Any>())
|
||||
return try {
|
||||
FileSystems.getFileSystem(jarUri())
|
||||
} catch (e: FileSystemNotFoundException) {
|
||||
FileSystems.newFileSystem(jarUri(), emptyMap<String, Any>())
|
||||
}
|
||||
}
|
||||
|
||||
fun Path.writeZip(): FileSystem {
|
||||
return FileSystems.newFileSystem(jarUri(), mapOf("create" to "true"))
|
||||
}
|
||||
|
||||
inline fun Path.writeZipStream(func: (ZipOutputStream) -> Unit) {
|
||||
ZipOutputStream(this.outputStream().buffered()).use(func)
|
||||
}
|
||||
|
||||
inline fun Path.readZipStream(func: (ZipInputStream, ZipEntry) -> Unit) {
|
||||
ZipInputStream(this.inputStream().buffered()).use { zis ->
|
||||
var entry = zis.nextEntry
|
||||
while (entry != null) {
|
||||
func(zis, entry)
|
||||
entry = zis.nextEntry
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun copyEntry(input: InputStream, output: ZipOutputStream, entry: ZipEntry) {
|
||||
val newEntry = ZipEntry(entry)
|
||||
output.putNextEntry(newEntry)
|
||||
try {
|
||||
input.copyTo(output)
|
||||
} finally {
|
||||
output.closeEntry()
|
||||
}
|
||||
}
|
||||
|
||||
fun FileSystem.walk(): Stream<Path> {
|
||||
return StreamSupport.stream(rootDirectories.spliterator(), false)
|
||||
.flatMap { Files.walk(it) }
|
||||
|
|
|
@ -102,6 +102,17 @@ class Git(private val repo: Path, private val env: Map<String, String> = emptyMa
|
|||
|
||||
throw PaperweightException("You must have git installed and available on your PATH in order to use paperweight.")
|
||||
}
|
||||
|
||||
fun checkForGitRepo(directory: Path): Boolean {
|
||||
try {
|
||||
val proc = ProcessBuilder("git", "status").redirectErrorStream(true).directory(directory).start()
|
||||
proc.inputStream.copyTo(UselessOutputStream)
|
||||
if (proc.waitFor() == 0) {
|
||||
return true
|
||||
}
|
||||
} catch (_: Exception) {}
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -74,6 +74,8 @@ import org.gradle.jvm.toolchain.JavaLauncher
|
|||
import org.gradle.jvm.toolchain.JavaToolchainService
|
||||
import org.gradle.kotlin.dsl.*
|
||||
|
||||
val whitespace = Regex("\\s+")
|
||||
|
||||
val gson: Gson = GsonBuilder().disableHtmlEscaping().setPrettyPrinting().registerTypeHierarchyAdapter(Path::class.java, PathJsonConverter()).create()
|
||||
|
||||
class PathJsonConverter : JsonDeserializer<Path?>, JsonSerializer<Path?> {
|
||||
|
@ -107,7 +109,9 @@ fun ProjectLayout.maybeInitSubmodules(offline: Boolean, logger: Logger) {
|
|||
|
||||
fun ProjectLayout.initSubmodules() {
|
||||
Git.checkForGit()
|
||||
Git(projectDirectory.path)("submodule", "update", "--init").executeOut()
|
||||
if (Git.checkForGitRepo(projectDirectory.path)) {
|
||||
Git(projectDirectory.path)("submodule", "update", "--init").executeOut()
|
||||
}
|
||||
}
|
||||
|
||||
fun Project.offlineMode(): Boolean = gradle.startParameter.isOffline
|
||||
|
@ -201,6 +205,18 @@ fun Any.convertToPath(): Path {
|
|||
}
|
||||
}
|
||||
|
||||
fun Path.ensureClean(): Path {
|
||||
try {
|
||||
deleteRecursively()
|
||||
} catch (e: Exception) {
|
||||
println("Failed to delete $this: ${e.javaClass.name}: ${e.message}")
|
||||
e.suppressedExceptions.forEach { println("Suppressed exception: $it") }
|
||||
throw PaperweightException("Failed to delete $this", e)
|
||||
}
|
||||
parent.createDirectories()
|
||||
return this
|
||||
}
|
||||
|
||||
fun Any.convertToFileProvider(layout: ProjectLayout, providers: ProviderFactory): Provider<RegularFile> {
|
||||
return when (this) {
|
||||
is Path -> layout.file(providers.provider { toFile() })
|
||||
|
|
11
paperweight-lib/src/main/resources/post-rewrite.sh
Normal file
11
paperweight-lib/src/main/resources/post-rewrite.sh
Normal file
|
@ -0,0 +1,11 @@
|
|||
#!/bin/sh
|
||||
input=$(cat) # <old-object> SP <new-object> [SP <extra-info>] LF
|
||||
fileCommit=$(git rev-list -n 1 file) # current commit tagged as "file"
|
||||
oldObject=$(echo $input | cut -d' ' -f1) # <old-object>
|
||||
newObject=$(echo $input | cut -d' ' -f2) # <new-object>
|
||||
|
||||
if [ $oldObject = $fileCommit ]; then
|
||||
git tag -d file > /dev/null # delete old tag (silent)
|
||||
git tag file "$newObject" --no-sign
|
||||
echo "Updated tag 'file' from $oldObject to $newObject"
|
||||
fi
|
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* 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.tasks
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkObject
|
||||
import java.nio.file.Path
|
||||
import kotlin.test.BeforeTest
|
||||
import kotlin.test.Test
|
||||
import org.gradle.kotlin.dsl.*
|
||||
import org.gradle.workers.WorkQueue
|
||||
import org.gradle.workers.WorkerExecutor
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
|
||||
class ApplyAccessTransformTest : TaskTest() {
|
||||
private lateinit var task: ApplyAccessTransform
|
||||
|
||||
private val workerExecutor: WorkerExecutor = mockk()
|
||||
private val workQueue: WorkQueue = mockk()
|
||||
|
||||
@BeforeTest
|
||||
fun setup() {
|
||||
val project = setupProject()
|
||||
project.apply(plugin = "java")
|
||||
task = project.tasks.register("applyAccessTransform", ApplyAccessTransform::class).get()
|
||||
mockkObject(task)
|
||||
|
||||
every { task.workerExecutor } returns workerExecutor
|
||||
every { workerExecutor.processIsolation(any()) } returns workQueue
|
||||
every { workQueue.submit(ApplyAccessTransform.AtlasAction::class, any()) } answers {
|
||||
val action = object : ApplyAccessTransform.AtlasAction() {
|
||||
override fun getParameters(): ApplyAccessTransform.AtlasParameters {
|
||||
return mockk<ApplyAccessTransform.AtlasParameters>().also {
|
||||
every { it.inputJar.get() } returns task.inputJar.get()
|
||||
every { it.atFile.get() } returns task.atFile.get()
|
||||
every { it.outputJar.get() } returns task.outputJar.get()
|
||||
}
|
||||
}
|
||||
}
|
||||
action.execute()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should apply access transform`(@TempDir tempDir: Path) {
|
||||
val testResource = Path.of("src/test/resources/apply_access_transform")
|
||||
val testInput = testResource.resolve("input")
|
||||
|
||||
val input = createJar(tempDir, testInput, "Test").toFile()
|
||||
val output = tempDir.resolve("output.jar").toFile()
|
||||
val atFile = testInput.resolve("ats.at").toFile()
|
||||
|
||||
task.inputJar.set(input)
|
||||
task.outputJar.set(output)
|
||||
task.atFile.set(atFile)
|
||||
|
||||
task.run()
|
||||
|
||||
val testOutput = testResource.resolve("output")
|
||||
compareJar(tempDir, testOutput, "output", "Test")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* 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.tasks
|
||||
|
||||
import io.papermc.paperweight.util.*
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.*
|
||||
import org.eclipse.jgit.api.Git
|
||||
import org.gradle.testfixtures.ProjectBuilder
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
|
||||
open class TaskTest {
|
||||
|
||||
fun setupProject() = ProjectBuilder.builder()
|
||||
.withGradleUserHomeDir(File("build"))
|
||||
.withProjectDir(File(""))
|
||||
.build()
|
||||
|
||||
fun setupDir(tempDir: Path, testResource: Path, name: String): Path {
|
||||
val temp = tempDir.resolve(name).toFile()
|
||||
temp.mkdir()
|
||||
testResource.resolve(name).copyRecursivelyTo(temp.convertToPath())
|
||||
return temp.convertToPath()
|
||||
}
|
||||
|
||||
fun setupFile(tempDir: Path, testResource: Path, name: String): Path {
|
||||
val temp = tempDir.resolve(name)
|
||||
testResource.resolve(name).copyTo(temp)
|
||||
return temp
|
||||
}
|
||||
|
||||
fun compareDir(tempDir: Path, testResource: Path, name: String) {
|
||||
val actualOutput = tempDir.resolve(name)
|
||||
val expectedOutput = testResource.resolve(name)
|
||||
|
||||
val expectedFiles = expectedOutput.walk().filter { Files.isRegularFile(it) }.filter { !it.toString().contains(".git") }.toList()
|
||||
val actualFiles = actualOutput.walk().filter { Files.isRegularFile(it) }.filter { !it.toString().contains(".git") }.toList()
|
||||
|
||||
assertEquals(expectedFiles.size, actualFiles.size, "Expected $expectedFiles files, got $actualFiles")
|
||||
|
||||
expectedFiles.forEach { expectedFile ->
|
||||
val actualFile = actualOutput.resolve(expectedOutput.relativize(expectedFile))
|
||||
|
||||
compareFile(actualFile, expectedFile)
|
||||
}
|
||||
}
|
||||
|
||||
fun compareZip(tempDir: Path, testResource: Path, name: String) {
|
||||
val actualOutput = tempDir.resolve(name)
|
||||
val expectedOutput = testResource.resolve(name)
|
||||
|
||||
compareZip(actualOutput, expectedOutput)
|
||||
}
|
||||
|
||||
fun compareZip(actualOutput: Path, expectedOutput: Path) {
|
||||
val actualZip = actualOutput.openZip()
|
||||
val actualFiles = actualZip.walk().filter { Files.isRegularFile(it) }.toList()
|
||||
val expectedZip = expectedOutput.openZip()
|
||||
val expectedFiles = expectedZip.walk().filter { Files.isRegularFile(it) }.toList()
|
||||
|
||||
assertEquals(expectedFiles.size, actualFiles.size, "Expected $expectedFiles files, got $actualFiles")
|
||||
|
||||
expectedFiles.forEach { expectedFile ->
|
||||
val actualFile = actualZip.getPath(expectedFile.toString())
|
||||
|
||||
compareFile(actualFile, expectedFile)
|
||||
}
|
||||
}
|
||||
|
||||
fun compareFile(tempDir: Path, testResource: Path, name: String) {
|
||||
val actualOutput = tempDir.resolve(name)
|
||||
val expectedOutput = testResource.resolve(name)
|
||||
|
||||
compareFile(actualOutput, expectedOutput)
|
||||
}
|
||||
|
||||
private fun compareFile(actual: Path, expected: Path) {
|
||||
assertTrue(actual.exists(), "Expected file $actual doesn't exist")
|
||||
assertEquals(expected.readText(), actual.readText(), "File $actual doesn't match expected")
|
||||
}
|
||||
|
||||
fun setupGitRepo(directory: File, mainBranch: String, tag: String? = null) {
|
||||
val git = Git.init().setDirectory(directory).setInitialBranch(mainBranch).call()
|
||||
|
||||
git.add().addFilepattern(".").call()
|
||||
git.commit().setMessage("Test").call()
|
||||
if (tag != null) {
|
||||
git.tag().setName(tag).call()
|
||||
}
|
||||
|
||||
git.close()
|
||||
}
|
||||
|
||||
fun createZip(tempDir: Path, testResource: Path, zipName: String, vararg fileNames: String,): Path {
|
||||
val targetZip = tempDir.resolve(zipName)
|
||||
|
||||
targetZip.writeZip().use { zip ->
|
||||
fileNames.forEach { fileName ->
|
||||
val sourceFile = testResource.resolve(fileName)
|
||||
zip.getPath(fileName).writeText(sourceFile.readText())
|
||||
}
|
||||
}
|
||||
|
||||
return targetZip
|
||||
}
|
||||
|
||||
fun createJar(tempDir: Path, testResource: Path, name: String): Path {
|
||||
val sourceFile = tempDir.resolve("$name.java")
|
||||
testResource.resolve("$name.java").copyTo(sourceFile)
|
||||
|
||||
// run javac on the file
|
||||
ProcessBuilder()
|
||||
.directory(tempDir.toFile())
|
||||
.command("javac", sourceFile.toString())
|
||||
.redirectErrorStream(true)
|
||||
.start()
|
||||
.waitFor()
|
||||
|
||||
// create jar
|
||||
ProcessBuilder()
|
||||
.directory(tempDir.toFile())
|
||||
.command("jar", "-cf", "$name.jar", "$name.class")
|
||||
.redirectErrorStream(true)
|
||||
.start()
|
||||
.waitFor()
|
||||
|
||||
return tempDir.resolve("$name.jar")
|
||||
}
|
||||
|
||||
fun compareJar(tempDir: Path, testResource: Path, fileName: String, className: String) {
|
||||
val outputJar = tempDir.resolve("$fileName.jar")
|
||||
val expectedOutputFile = testResource.resolve("$fileName.javap")
|
||||
|
||||
// unpack jar
|
||||
ProcessBuilder()
|
||||
.directory(tempDir.toFile())
|
||||
.command("jar", "-xf", outputJar.toString())
|
||||
.redirectErrorStream(true)
|
||||
.start()
|
||||
.waitFor()
|
||||
|
||||
// disassemble class
|
||||
val process = ProcessBuilder()
|
||||
.directory(tempDir.toFile())
|
||||
.command("javap", "-p", "-c", "$className.class")
|
||||
.redirectErrorStream(true)
|
||||
.start()
|
||||
|
||||
var actualOutput = process.inputStream.bufferedReader().readText()
|
||||
val expectedOutput = expectedOutputFile.readText()
|
||||
|
||||
// cleanup output
|
||||
val lines = actualOutput.split("\n")
|
||||
if (lines[0].startsWith("Picked up JAVA_TOOL_OPTIONS")) {
|
||||
actualOutput = actualOutput.replace(lines[0] + "\n", "")
|
||||
}
|
||||
actualOutput = actualOutput.replace("\r\n", "\n")
|
||||
|
||||
process.waitFor()
|
||||
|
||||
assertEquals(expectedOutput, actualOutput, "Output doesn't match expected")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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.tasks.softspoon
|
||||
|
||||
import io.papermc.paperweight.tasks.*
|
||||
import java.nio.file.Path
|
||||
import kotlin.test.BeforeTest
|
||||
import kotlin.test.Test
|
||||
import org.gradle.kotlin.dsl.*
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
|
||||
class ApplyFilePatchesTest : TaskTest() {
|
||||
private lateinit var task: ApplyFilePatches
|
||||
|
||||
@BeforeTest
|
||||
fun setup() {
|
||||
val project = setupProject()
|
||||
task = project.tasks.register("applyPatches", ApplyFilePatches::class).get()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should apply patches`(@TempDir tempDir: Path) {
|
||||
val testResource = Path.of("src/test/resources/apply_patches")
|
||||
val testInput = testResource.resolve("input")
|
||||
|
||||
val input = setupDir(tempDir, testInput, "base").toFile()
|
||||
val output = tempDir.resolve("source").toFile()
|
||||
val patches = testInput.resolve("patches").toFile()
|
||||
|
||||
setupGitRepo(input, "main")
|
||||
|
||||
task.input.set(input)
|
||||
task.output.set(output)
|
||||
task.patches.set(patches)
|
||||
task.verbose.set(true)
|
||||
|
||||
task.run()
|
||||
|
||||
val testOutput = testResource.resolve("output")
|
||||
compareDir(tempDir, testOutput, "source")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* 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.tasks.softspoon
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkObject
|
||||
import io.papermc.paperweight.tasks.*
|
||||
import java.nio.file.Path
|
||||
import kotlin.test.BeforeTest
|
||||
import kotlin.test.Test
|
||||
import org.gradle.kotlin.dsl.*
|
||||
import org.gradle.workers.WorkQueue
|
||||
import org.gradle.workers.WorkerExecutor
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
|
||||
class ApplySourceATTest : TaskTest() {
|
||||
private lateinit var task: ApplySourceAT
|
||||
|
||||
private val workerExecutor: WorkerExecutor = mockk()
|
||||
private val workQueue: WorkQueue = mockk()
|
||||
|
||||
@BeforeTest
|
||||
fun setup() {
|
||||
val project = setupProject()
|
||||
task = project.tasks.register("applySourceAT", ApplySourceAT::class).get()
|
||||
mockkObject(task)
|
||||
|
||||
every { task.worker } returns workerExecutor
|
||||
every { workerExecutor.processIsolation(any()) } returns workQueue
|
||||
every { workQueue.submit(RestampWorker::class, any()) } answers {
|
||||
val action = object : RestampWorker() {
|
||||
override fun getParameters(): Params {
|
||||
return mockk<Params>().also {
|
||||
every { it.inputJar.get() } returns task.inputJar.get()
|
||||
every { it.atFile.get() } returns task.atFile.get()
|
||||
every { it.outputJar.get() } returns task.outputJar.get()
|
||||
every { it.minecraftClasspath } returns task.minecraftClasspath
|
||||
}
|
||||
}
|
||||
}
|
||||
action.execute()
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should apply source access transformers`(@TempDir tempDir: Path) {
|
||||
val testResource = Path.of("src/test/resources/apply_source_at")
|
||||
val testInput = testResource.resolve("input")
|
||||
|
||||
val inputJar = createZip(tempDir, testInput, "Test.jar", "Test.java", "Unrelated.java")
|
||||
val atFile = testInput.resolve("ats.at").toFile()
|
||||
val outputJar = tempDir.resolve("output.jar")
|
||||
|
||||
task.inputJar.set(inputJar.toFile())
|
||||
task.atFile.set(atFile)
|
||||
task.outputJar.set(outputJar.toFile())
|
||||
|
||||
task.run()
|
||||
|
||||
val testOutput = testResource.resolve("output")
|
||||
val expectedJar = createZip(tempDir, testOutput, "expected.jar", "Test.java", "Unrelated.java")
|
||||
compareZip(outputJar, expectedJar)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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.tasks.softspoon
|
||||
|
||||
import io.papermc.paperweight.tasks.*
|
||||
import java.nio.file.Path
|
||||
import kotlin.test.BeforeTest
|
||||
import kotlin.test.Test
|
||||
import org.gradle.kotlin.dsl.*
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
|
||||
class RebuildFilePatchesTest : TaskTest() {
|
||||
private lateinit var task: RebuildFilePatches
|
||||
|
||||
@BeforeTest
|
||||
fun setup() {
|
||||
val project = setupProject()
|
||||
task = project.tasks.register("rebuildPatches", RebuildFilePatches::class).get()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should rebuild patches`(@TempDir tempDir: Path) {
|
||||
val testResource = Path.of("src/test/resources/rebuild_patches")
|
||||
val testInput = testResource.resolve("input")
|
||||
|
||||
val source = setupDir(tempDir, testInput, "source").toFile()
|
||||
setupGitRepo(source, "main", "file")
|
||||
val base = setupDir(tempDir, testInput, "base").toFile()
|
||||
val patches = tempDir.resolve("patches").toFile()
|
||||
val atFile = testInput.resolve("ats.at").toFile()
|
||||
val atFileOut = tempDir.resolve("ats.at").toFile()
|
||||
|
||||
task.input.set(source)
|
||||
task.base.set(base)
|
||||
task.patches.set(patches)
|
||||
task.atFile.set(atFile)
|
||||
task.atFileOut.set(atFileOut)
|
||||
task.verbose.set(true)
|
||||
|
||||
task.run()
|
||||
|
||||
val testOutput = testResource.resolve("output")
|
||||
compareDir(tempDir, testOutput, "base")
|
||||
compareDir(tempDir, testOutput, "source")
|
||||
compareDir(tempDir, testOutput, "patches")
|
||||
compareFile(tempDir, testOutput, "ats.at")
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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.util
|
||||
|
||||
import atFromString
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import org.cadixdev.at.AccessChange
|
||||
import org.cadixdev.at.AccessTransform
|
||||
import org.cadixdev.at.ModifierChange
|
||||
|
||||
class ATTest {
|
||||
|
||||
@Test
|
||||
fun testATFromString() {
|
||||
assertEquals(AccessTransform.of(AccessChange.PUBLIC, ModifierChange.REMOVE), atFromString("public-f"))
|
||||
assertEquals(AccessTransform.of(AccessChange.PUBLIC, ModifierChange.NONE), atFromString("public"))
|
||||
assertEquals(AccessTransform.of(AccessChange.PUBLIC, ModifierChange.ADD), atFromString("public+f"))
|
||||
|
||||
assertEquals(AccessTransform.of(AccessChange.PRIVATE, ModifierChange.REMOVE), atFromString("private-f"))
|
||||
assertEquals(AccessTransform.of(AccessChange.PRIVATE, ModifierChange.NONE), atFromString("private"))
|
||||
assertEquals(AccessTransform.of(AccessChange.PRIVATE, ModifierChange.ADD), atFromString("private+f"))
|
||||
|
||||
assertEquals(AccessTransform.of(AccessChange.NONE, ModifierChange.REMOVE), atFromString("-f"))
|
||||
assertEquals(AccessTransform.of(AccessChange.NONE, ModifierChange.ADD), atFromString("+f"))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
public class Test {
|
||||
|
||||
public int dum;
|
||||
private final String test;
|
||||
|
||||
public Test(String test) {
|
||||
this.test = test;
|
||||
}
|
||||
|
||||
public String getTest() {
|
||||
return test;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
# This file is auto generated, any changes may be overridden!
|
||||
# See CONTRIBUTING.md on how to add access transformers.
|
||||
public-f Test test
|
||||
public+f Test dum
|
||||
private+f Test getTest()Ljava/lang/String;
|
|
@ -0,0 +1,21 @@
|
|||
Compiled from "Test.java"
|
||||
public class Test {
|
||||
public final int dum;
|
||||
|
||||
public java.lang.String test;
|
||||
|
||||
public Test(java.lang.String);
|
||||
Code:
|
||||
0: aload_0
|
||||
1: invokespecial #1 // Method java/lang/Object."<init>":()V
|
||||
4: aload_0
|
||||
5: aload_1
|
||||
6: putfield #7 // Field test:Ljava/lang/String;
|
||||
9: return
|
||||
|
||||
private final java.lang.String getTest();
|
||||
Code:
|
||||
0: aload_0
|
||||
1: getfield #7 // Field test:Ljava/lang/String;
|
||||
4: areturn
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
public class Test {
|
||||
|
||||
public int dum;
|
||||
private final String test;
|
||||
|
||||
public Test(String test) {
|
||||
this.test = test;
|
||||
}
|
||||
|
||||
public String getTest() {
|
||||
return test;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
--- a/Test.java
|
||||
+++ b/Test.java
|
||||
@@ -8,6 +_,6 @@
|
||||
}
|
||||
|
||||
public String getTest() {
|
||||
- return test;
|
||||
+ return test + "Test"; // Test
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
public class Test {
|
||||
|
||||
public int dum;
|
||||
private final String test;
|
||||
|
||||
public Test(String test) {
|
||||
this.test = test;
|
||||
}
|
||||
|
||||
public String getTest() {
|
||||
return test + "Test"; // Test
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
public class Test {
|
||||
|
||||
public int dum;
|
||||
private final String test;
|
||||
|
||||
public Test(String test) {
|
||||
this.test = test;
|
||||
}
|
||||
|
||||
public String getTest() {
|
||||
return test;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
class Unrealted {
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
# This file is auto generated, any changes may be overridden!
|
||||
# See CONTRIBUTING.md on how to add access transformers.
|
||||
public-f Test test
|
||||
public+f Test dum
|
||||
private+f Test getTest()Ljava/lang/String;
|
|
@ -0,0 +1,13 @@
|
|||
public class Test {
|
||||
|
||||
public final int dum;
|
||||
public String test;
|
||||
|
||||
public Test(String test) {
|
||||
this.test = test;
|
||||
}
|
||||
|
||||
private final String getTest() {
|
||||
return test;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
class Unrealted {
|
||||
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
# This file is auto generated, any changes may be overridden!
|
||||
# See CONTRIBUTING.md on how to add access transformers.
|
||||
public Test dum
|
|
@ -0,0 +1,13 @@
|
|||
public class Test {
|
||||
|
||||
public int dum;
|
||||
private final String test;
|
||||
|
||||
public Test(String test) {
|
||||
this.test = test;
|
||||
}
|
||||
|
||||
public String getTest() {
|
||||
return test;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
public class Test {
|
||||
|
||||
public int dum;
|
||||
public String test;// Paper-AT: public-f test
|
||||
|
||||
public Test(String test) {
|
||||
this.test = test;
|
||||
}
|
||||
|
||||
private final String getTest() {// Paper-AT: private+f getTest()Ljava/lang/String;
|
||||
return test + "Test"; // Test
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
# This file is auto generated, any changes may be overridden!
|
||||
# See CONTRIBUTING.md on how to add access transformers.
|
||||
private+f Test getTest()Ljava/lang/String;
|
||||
public Test dum
|
||||
public-f Test test
|
|
@ -0,0 +1,13 @@
|
|||
public class Test {
|
||||
|
||||
public int dum;
|
||||
public String test;
|
||||
|
||||
public Test(String test) {
|
||||
this.test = test;
|
||||
}
|
||||
|
||||
private final String getTest() {
|
||||
return test;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
--- a/Test.java
|
||||
+++ b/Test.java
|
||||
@@ -8,6 +_,6 @@
|
||||
}
|
||||
|
||||
private final String getTest() {
|
||||
- return test;
|
||||
+ return test + "Test"; // Test
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
public class Test {
|
||||
|
||||
public int dum;
|
||||
public String test;
|
||||
|
||||
public Test(String test) {
|
||||
this.test = test;
|
||||
}
|
||||
|
||||
private final String getTest() {
|
||||
return test + "Test"; // Test
|
||||
}
|
||||
}
|
|
@ -67,7 +67,9 @@ abstract class PaperweightUser : Plugin<Project> {
|
|||
|
||||
val sharedCacheRoot = target.gradle.gradleUserHomeDir.toPath().resolve("caches/paperweight-userdev")
|
||||
|
||||
target.gradle.sharedServices.registerIfAbsent(DOWNLOAD_SERVICE_NAME, DownloadService::class) {}
|
||||
target.gradle.sharedServices.registerIfAbsent(DOWNLOAD_SERVICE_NAME, DownloadService::class) {
|
||||
parameters.projectPath.set(target.projectDir)
|
||||
}
|
||||
|
||||
val cleanAll = target.tasks.register<Delete>("cleanAllPaperweightUserdevCaches") {
|
||||
group = "paperweight"
|
||||
|
|
|
@ -70,12 +70,12 @@ class SetupHandlerImplV2(
|
|||
override val hashFile: Path = cache.resolve(paperSetupOutput("minecraftLibraries", "hashes"))
|
||||
|
||||
override fun run(context: SetupHandler.Context) {
|
||||
downloadMinecraftLibraries(
|
||||
downloadLibraries(
|
||||
download = parameters.downloadService,
|
||||
workerExecutor = context.workerExecutor,
|
||||
targetDir = minecraftLibraryJars,
|
||||
repositories = listOf(MC_LIBRARY_URL, MAVEN_CENTRAL_URL),
|
||||
mcLibraries = bundle.config.buildData.vanillaServerLibraries,
|
||||
libraries = bundle.config.buildData.vanillaServerLibraries,
|
||||
sources = false
|
||||
).await()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue