diff --git a/.editorconfig b/.editorconfig index 340d0e17..c138702a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -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 diff --git a/.github/workflows/deploy-snapshot.yml b/.github/workflows/deploy-snapshot.yml index 2087f8d3..a40c9c72 100644 --- a/.github/workflows/deploy-snapshot.yml +++ b/.github/workflows/deploy-snapshot.yml @@ -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 }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 34b52e96..ecb393f0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -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 diff --git a/.gitignore b/.gitignore index fd472d07..9e181772 100644 --- a/.gitignore +++ b/.gitignore @@ -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/ diff --git a/buildSrc/src/main/kotlin/config-kotlin.gradle.kts b/buildSrc/src/main/kotlin/config-kotlin.gradle.kts index 9efe9cad..a7d98e48 100644 --- a/buildSrc/src/main/kotlin/config-kotlin.gradle.kts +++ b/buildSrc/src/main/kotlin/config-kotlin.gradle.kts @@ -1,5 +1,7 @@ import com.diffplug.gradle.spotless.SpotlessExtension import net.kyori.indra.licenser.spotless.IndraSpotlessLicenserExtension +import org.gradle.api.tasks.testing.logging.TestExceptionFormat +import org.gradle.api.tasks.testing.logging.TestLogEvent plugins { idea @@ -11,7 +13,7 @@ java { } tasks.withType(JavaCompile::class).configureEach { - options.release = 11 + options.release = 17 } kotlin { @@ -21,14 +23,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 +41,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 +80,16 @@ testing { useKotlinTest(embeddedKotlinVersion) dependencies { implementation("org.junit.jupiter:junit-jupiter-engine:5.10.1") + implementation("org.junit.platform:junit-platform-launcher:1.10.1") + } + + targets.configureEach { + testTask { + testLogging { + events(TestLogEvent.FAILED) + exceptionFormat = TestExceptionFormat.FULL + } + } } } } diff --git a/gradle.properties b/gradle.properties index c8006928..8015950f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ group = io.papermc.paperweight -version = 1.7.5-SNAPSHOT +version = 2.0.0-SNAPSHOT org.gradle.caching = true org.gradle.parallel = true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 829b158d..c0459cfb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,9 @@ [versions] -asm = "9.7" +asm = "9.7.1" 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,18 +35,29 @@ 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" gradle-spotless = "com.diffplug.spotless:spotless-plugin-gradle:6.23.1" gradle-shadow = "com.github.johnrengelman.shadow:com.github.johnrengelman.shadow.gradle.plugin:8.1.1" -gradle-kotlin-dsl = "org.gradle.kotlin.kotlin-dsl:org.gradle.kotlin.kotlin-dsl.gradle.plugin:4.3.0" +gradle-kotlin-dsl = "org.gradle.kotlin.kotlin-dsl:org.gradle.kotlin.kotlin-dsl.gradle.plugin:4.5.0" gradle-plugin-kotlin = { module = "org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin" } 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"] diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e7646dea..df97d72b 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/paperweight-core/build.gradle.kts b/paperweight-core/build.gradle.kts index 99133c9e..5957f60d 100644 --- a/paperweight-core/build.gradle.kts +++ b/paperweight-core/build.gradle.kts @@ -7,6 +7,7 @@ dependencies { shade(projects.paperweightLib) implementation(libs.bundles.kotson) + implementation(libs.coroutines) } gradlePlugin { diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/PaperweightCore.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/PaperweightCore.kt index 26db8adb..514a7cdc 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/PaperweightCore.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/PaperweightCore.kt @@ -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 { 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("cleanCache") { group = "paper" @@ -69,6 +72,7 @@ class PaperweightCore : Plugin { 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("diff") { @@ -90,10 +94,12 @@ class PaperweightCore : Plugin { ext.mainClass ) + val softSpoonTasks = SoftSpoonTasks(target, tasks) + target.createPatchRemapTask(tasks) target.tasks.register(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 { } 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 diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/PaperExtension.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/PaperExtension.kt index 9d5fac37..9891838a 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/PaperExtension.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/PaperExtension.kt @@ -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/features") @Suppress("MemberVisibilityCanBePrivate") val buildDataDir: DirectoryProperty = objects.dirWithDefault(layout, "build-data") diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/PaperweightCoreExtension.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/PaperweightCoreExtension.kt index 08c2fddf..3b016c15 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/PaperweightCoreExtension.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/PaperweightCoreExtension.kt @@ -36,10 +36,13 @@ import org.gradle.kotlin.dsl.* open class PaperweightCoreExtension(project: Project, objects: ObjectFactory, layout: ProjectLayout) { + val softSpoon: Property = objects.property().convention(false) + @Suppress("MemberVisibilityCanBePrivate") val workDir: DirectoryProperty = objects.dirWithDefault(layout, "work") val minecraftVersion: Property = objects.property() + val minecraftManifestUrl: Property = objects.property().convention(MC_MANIFEST_URL) val serverProject: Property = objects.property() val mainClass: Property = objects.property().convention("org.bukkit.craftbukkit.Main") @@ -50,6 +53,7 @@ open class PaperweightCoreExtension(project: Project, objects: ObjectFactory, la val paramMappingsRepo: Property = objects.property() val decompileRepo: Property = objects.property() val remapRepo: Property = objects.property() + val macheRepo: Property = objects.property().convention("https://repo.papermc.io/repository/maven-public/") val vanillaJarIncludes: ListProperty = objects.listProperty().convention( listOf("/*.class", "/net/minecraft/**", "/com/mojang/math/**") diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/AllTasks.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/AllTasks.kt index 9f9d6aea..f6ac77d1 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/AllTasks.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/AllTasks.kt @@ -101,6 +101,23 @@ open class AllTasks( downloader.set(downloadService) } + val downloadPaperLibrariesSources by tasks.registering { + 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 { group = "paper" @@ -126,7 +143,7 @@ open class AllTasks( mcDevSources.set(extension.mcDevSourceDir) } - val applyPatches by tasks.registering { + val applyPatchesLegacy by tasks.registering { 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 { + val rebuildPatchesLegacy by tasks.registering { group = "paper" description = "Rebuilds patches to api and server" dependsOn(rebuildApiPatches, rebuildServerPatches) diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/InitialTasks.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/InitialTasks.kt index 09af05c9..ad8982f1 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/InitialTasks.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/InitialTasks.kt @@ -45,7 +45,7 @@ open class InitialTasks( ) { val downloadMcManifest by tasks.registering { - 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(it) } - val downloadMcVersionManifest by tasks.registering { + val downloadMcVersionManifest by tasks.registering { 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(it) } - val downloadMappings by tasks.registering { + val downloadMappings by tasks.registering { 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)) } } diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/SoftSpoonTasks.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/SoftSpoonTasks.kt new file mode 100644 index 00000000..0ce3f73b --- /dev/null +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/SoftSpoonTasks.kt @@ -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 { + 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(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().sourceSets.named(SourceSet.MAIN_SOURCE_SET_NAME) { + java { + srcDirs(projectDir.resolve("src/vanilla/java")) + } + resources { + srcDirs(projectDir.resolve("src/vanilla/resources")) + } + } + } +} diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/SpigotTasks.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/SpigotTasks.kt index 4deb154a..83b77551 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/SpigotTasks.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/SpigotTasks.kt @@ -53,7 +53,9 @@ open class SpigotTasks( val generateSpigotMappings by tasks.registering { 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)) diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/VanillaTasks.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/VanillaTasks.kt index e73f13eb..c03e4c66 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/VanillaTasks.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/VanillaTasks.kt @@ -49,7 +49,8 @@ open class VanillaTasks( val remapJar by tasks.registering { 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)) diff --git a/paperweight-core/src/test/kotlin/io/papermc/paperweight/FunctionalTest.kt b/paperweight-core/src/test/kotlin/io/papermc/paperweight/FunctionalTest.kt new file mode 100644 index 00000000..1bb901bd --- /dev/null +++ b/paperweight-core/src/test/kotlin/io/papermc/paperweight/FunctionalTest.kt @@ -0,0 +1,206 @@ +/* + * 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.io.path.readText +import kotlin.io.path.writeText +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 = true + + @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 + println("adding at to source") + modifyFile(tempDir.resolve("test-server/src/vanilla/java/Test.java")) { + it.replace( + "\"2\";", + "\"2\"; // Woo" + ).replace("public String getTest2() {", "private final String getTest2() {// Paper-AT: private+f getTest2()Ljava/lang/String;") + } + + Git(tempDir.resolve("test-server/src/vanilla/java")).let { git -> + git("add", ".").executeSilently() + git("commit", "--fixup", "file").executeSilently() + git("rebase", "--autosquash", "mache/main").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()) + + // feature patch + println("\nmodifying feature patch\n") + modifyFile(tempDir.resolve("test-server/src/vanilla/java/Test.java")) { + it.replace("wonderful feature", "amazing feature") + } + + println("\nrebuilding feature patch\n") + val rebP3 = gradleRunner + .withArguments("rebuildPatches", "--stacktrace", "-Dfake=true") + .withDebug(debug) + .build() + assertEquals(rebP3.task(":rebuildPatches")?.outcome, TaskOutcome.SUCCESS) + assertEquals( + testResource.resolve("fake-patches/expected/0001-Feature.patch").readText(), + tempDir.resolve("fake-patches/features/0001-Feature.patch").readText() + ) + + // todo lib patches + } + + @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")) + } + + fun modifyFile(path: Path, action: (content: String) -> String) { + path.writeText(action.invoke(path.readText())) + } +} diff --git a/paperweight-core/src/test/kotlin/io/papermc/paperweight/util.kt b/paperweight-core/src/test/kotlin/io/papermc/paperweight/util.kt new file mode 100644 index 00000000..0e5aa0e8 --- /dev/null +++ b/paperweight-core/src/test/kotlin/io/papermc/paperweight/util.kt @@ -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()) +} diff --git a/paperweight-core/src/test/resources/fake_mache/mache.json b/paperweight-core/src/test/resources/fake_mache/mache.json new file mode 100644 index 00000000..9bc8092e --- /dev/null +++ b/paperweight-core/src/test/resources/fake_mache/mache.json @@ -0,0 +1,114 @@ +{ + "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.21", + "version": "2024.07.28", + "extension": "zip" + } + ], + "constants": [ + ], + "remapper": [ + { + "group": "net.neoforged", + "name": "AutoRenamingTool", + "version": "1.0.14", + "classifier": "all" + } + ], + "decompiler": [ + { + "group": "org.vineflower", + "name": "vineflower", + "version": "1.11.0-20240829.184116-48" + } + ] + }, + "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": [ + "--synthetic-not-set=true", + "--ternary-constant-simplification=true", + "--include-runtime=current", + "--decompile-complex-constant-dynamic=true", + "--indent-string= ", + "--decompile-inner=true", + "--remove-bridge=true", + "--decompile-generics=true", + "--ascii-strings=false", + "--remove-synthetic=true", + "--include-classpath=true", + "--inline-simple-lambdas=true", + "--ignore-invalid-bytecode=false", + "--bytecode-source-mapping=true", + "--dump-code-lines=true", + "--override-annotation=false", + "--skip-extra-files=true" + ], + "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" + } + ] + } +} diff --git a/paperweight-core/src/test/resources/fake_mache/patches/Test.java.patch b/paperweight-core/src/test/resources/fake_mache/patches/Test.java.patch new file mode 100644 index 00000000..ee7e4b27 --- /dev/null +++ b/paperweight-core/src/test/resources/fake_mache/patches/Test.java.patch @@ -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) { diff --git a/paperweight-core/src/test/resources/fake_mojang/bundle/META-INF/libraries.list b/paperweight-core/src/test/resources/fake_mojang/bundle/META-INF/libraries.list new file mode 100644 index 00000000..5e85ec5d --- /dev/null +++ b/paperweight-core/src/test/resources/fake_mojang/bundle/META-INF/libraries.list @@ -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 diff --git a/paperweight-core/src/test/resources/fake_mojang/bundle/META-INF/versions.list b/paperweight-core/src/test/resources/fake_mojang/bundle/META-INF/versions.list new file mode 100644 index 00000000..6c9206a7 --- /dev/null +++ b/paperweight-core/src/test/resources/fake_mojang/bundle/META-INF/versions.list @@ -0,0 +1 @@ +- fake fake/server.jar diff --git a/paperweight-core/src/test/resources/fake_mojang/bundle/version.json b/paperweight-core/src/test/resources/fake_mojang/bundle/version.json new file mode 100644 index 00000000..d31cbf41 --- /dev/null +++ b/paperweight-core/src/test/resources/fake_mojang/bundle/version.json @@ -0,0 +1,3 @@ +{ + "id": "fake" +} diff --git a/paperweight-core/src/test/resources/fake_mojang/mappings.txt b/paperweight-core/src/test/resources/fake_mojang/mappings.txt new file mode 100644 index 00000000..5d04b367 --- /dev/null +++ b/paperweight-core/src/test/resources/fake_mojang/mappings.txt @@ -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 () -> diff --git a/paperweight-core/src/test/resources/fake_mojang/server/Test.java b/paperweight-core/src/test/resources/fake_mojang/server/Test.java new file mode 100644 index 00000000..ab9fb25d --- /dev/null +++ b/paperweight-core/src/test/resources/fake_mojang/server/Test.java @@ -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"; + } +} diff --git a/paperweight-core/src/test/resources/fake_mojang/server/test.json b/paperweight-core/src/test/resources/fake_mojang/server/test.json new file mode 100644 index 00000000..d0ae716d --- /dev/null +++ b/paperweight-core/src/test/resources/fake_mojang/server/test.json @@ -0,0 +1,3 @@ +{ + "test": "test" +} diff --git a/paperweight-core/src/test/resources/fake_mojang/version.json b/paperweight-core/src/test/resources/fake_mojang/version.json new file mode 100644 index 00000000..b6f14b3b --- /dev/null +++ b/paperweight-core/src/test/resources/fake_mojang/version.json @@ -0,0 +1,12 @@ +{ + "downloads": { + "server": { + "sha1": "", + "url": "file://project/fake_mojang/bundle.jar" + }, + "server_mappings": { + "sha1": "", + "url": "file://project/fake_mojang/mappings.txt" + } + } +} diff --git a/paperweight-core/src/test/resources/fake_mojang/version_manifest.json b/paperweight-core/src/test/resources/fake_mojang/version_manifest.json new file mode 100644 index 00000000..7aa49bb6 --- /dev/null +++ b/paperweight-core/src/test/resources/fake_mojang/version_manifest.json @@ -0,0 +1,14 @@ +{ + "latest": { + "release": "fake", + "snapshot": "fake" + }, + "versions": [ + { + "id": "fake", + "type": "release", + "url": "file://project/fake_mojang/version.json", + "sha1": "" + } + ] +} diff --git a/paperweight-core/src/test/resources/functional_test/.gitignore b/paperweight-core/src/test/resources/functional_test/.gitignore new file mode 100644 index 00000000..c6b58a75 --- /dev/null +++ b/paperweight-core/src/test/resources/functional_test/.gitignore @@ -0,0 +1,2 @@ +.gradle +gradle diff --git a/paperweight-core/src/test/resources/functional_test/build-data/expected.at b/paperweight-core/src/test/resources/functional_test/build-data/expected.at new file mode 100644 index 00000000..ca799db8 --- /dev/null +++ b/paperweight-core/src/test/resources/functional_test/build-data/expected.at @@ -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; diff --git a/paperweight-core/src/test/resources/functional_test/build-data/fake.at b/paperweight-core/src/test/resources/functional_test/build-data/fake.at new file mode 100644 index 00000000..7627e75c --- /dev/null +++ b/paperweight-core/src/test/resources/functional_test/build-data/fake.at @@ -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; diff --git a/paperweight-core/src/test/resources/functional_test/build-data/paper.at b/paperweight-core/src/test/resources/functional_test/build-data/paper.at new file mode 100644 index 00000000..7883d560 --- /dev/null +++ b/paperweight-core/src/test/resources/functional_test/build-data/paper.at @@ -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; diff --git a/paperweight-core/src/test/resources/functional_test/build.gradle b/paperweight-core/src/test/resources/functional_test/build.gradle new file mode 100644 index 00000000..e2819e10 --- /dev/null +++ b/paperweight-core/src/test/resources/functional_test/build.gradle @@ -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.21.1+build.1' + } +} + +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/features')) + + additionalAts.set(file('build-data/fake.at')) + + paperServerDir.set(file('test-server')) + } + } else { + minecraftVersion = '1.21.1' + + paper { + paperServerDir.set(file('test-server')) + } + } + + serverProject = project(':test-server') +} diff --git a/paperweight-core/src/test/resources/functional_test/fake-patches/expected/0001-Feature.patch b/paperweight-core/src/test/resources/functional_test/fake-patches/expected/0001-Feature.patch new file mode 100644 index 00000000..d9718665 --- /dev/null +++ b/paperweight-core/src/test/resources/functional_test/fake-patches/expected/0001-Feature.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MiniDigger | Martin +Date: Sun, 20 Oct 2024 09:24:36 +0200 +Subject: [PATCH] Feature + + +diff --git a/Test.java b/Test.java +index 8bd0bab8fc2fb2f6a4459ed9f618214ec048afc4..6accbd08d129088975d63c13230eefb73bdc3fcb 100644 +--- a/Test.java ++++ b/Test.java +@@ -13,4 +13,8 @@ public class Test { + private final String getTest2() {// Paper-AT: private+f getTest2()Ljava/lang/String; + return this.test + "2"; // Woo + } ++ ++ public String feature() { ++ return "wonderful feature"; ++ } + } diff --git a/paperweight-core/src/test/resources/functional_test/fake-patches/expected/Test.java.patch b/paperweight-core/src/test/resources/functional_test/fake-patches/expected/Test.java.patch new file mode 100644 index 00000000..87713536 --- /dev/null +++ b/paperweight-core/src/test/resources/functional_test/fake-patches/expected/Test.java.patch @@ -0,0 +1,16 @@ +--- 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"; ++ private final String getTest2() {// Paper-AT: private+f getTest2()Ljava/lang/String; ++ return this.test + "2"; // Woo + } + } diff --git a/paperweight-core/src/test/resources/functional_test/fake-patches/features/0001-Feature.patch b/paperweight-core/src/test/resources/functional_test/fake-patches/features/0001-Feature.patch new file mode 100644 index 00000000..9fe99c6a --- /dev/null +++ b/paperweight-core/src/test/resources/functional_test/fake-patches/features/0001-Feature.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MiniDigger | Martin +Date: Sun, 20 Oct 2024 09:24:36 +0200 +Subject: [PATCH] Feature + + +diff --git a/Test.java b/Test.java +index 418548ec7dd11e57f0838d1dae048b99a2669ea3..95266c0cad0b100367ca840d286b7a004b93f4ef 100644 +--- a/Test.java ++++ b/Test.java +@@ -13,4 +13,8 @@ public class Test { + public String getTest2() { + return this.test + "2"; + } ++ ++ public String feature() { ++ return "wonderful feature"; ++ } + } diff --git a/paperweight-core/src/test/resources/functional_test/fake-patches/resources/test.json.patch b/paperweight-core/src/test/resources/functional_test/fake-patches/resources/test.json.patch new file mode 100644 index 00000000..a29ad924 --- /dev/null +++ b/paperweight-core/src/test/resources/functional_test/fake-patches/resources/test.json.patch @@ -0,0 +1,7 @@ +--- a/test.json ++++ b/test.json +@@ -1,3 +_,3 @@ + { +- "test": "test" ++ "test": "test2" + } diff --git a/paperweight-core/src/test/resources/functional_test/fake-patches/sources/Test.java.patch b/paperweight-core/src/test/resources/functional_test/fake-patches/sources/Test.java.patch new file mode 100644 index 00000000..f52ee82a --- /dev/null +++ b/paperweight-core/src/test/resources/functional_test/fake-patches/sources/Test.java.patch @@ -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() { diff --git a/paperweight-core/src/test/resources/functional_test/settings.gradle b/paperweight-core/src/test/resources/functional_test/settings.gradle new file mode 100644 index 00000000..4ce338cd --- /dev/null +++ b/paperweight-core/src/test/resources/functional_test/settings.gradle @@ -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' diff --git a/paperweight-core/src/test/resources/functional_test/test-api/build.gradle b/paperweight-core/src/test/resources/functional_test/test-api/build.gradle new file mode 100644 index 00000000..0e306a7b --- /dev/null +++ b/paperweight-core/src/test/resources/functional_test/test-api/build.gradle @@ -0,0 +1,3 @@ +plugins { + id "java-library" +} diff --git a/paperweight-core/src/test/resources/functional_test/test-server/build.gradle b/paperweight-core/src/test/resources/functional_test/test-server/build.gradle new file mode 100644 index 00000000..cd2984f1 --- /dev/null +++ b/paperweight-core/src/test/resources/functional_test/test-server/build.gradle @@ -0,0 +1,8 @@ +plugins { + id "java" + id "com.github.johnrengelman.shadow" +} + +dependencies { + implementation project(":test-api") +} diff --git a/paperweight-core/src/test/resources/functional_test/test-server/patches/features/0001-something.patch b/paperweight-core/src/test/resources/functional_test/test-server/patches/features/0001-something.patch new file mode 100644 index 00000000..75f08885 --- /dev/null +++ b/paperweight-core/src/test/resources/functional_test/test-server/patches/features/0001-something.patch @@ -0,0 +1,18 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MiniDigger | Martin +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\""); + } diff --git a/paperweight-core/src/test/resources/functional_test/test-server/patches/resources/version.json.patch b/paperweight-core/src/test/resources/functional_test/test-server/patches/resources/version.json.patch new file mode 100644 index 00000000..978105f3 --- /dev/null +++ b/paperweight-core/src/test/resources/functional_test/test-server/patches/resources/version.json.patch @@ -0,0 +1,11 @@ +--- a/version.json ++++ b/version.json +@@ -1,6 +_,6 @@ + { +- "id": "1.21.1", +- "name": "1.21.1", ++ "id": "1.21.1-paper", ++ "name": "1.21.1 - Paper", + "world_version": 3955, + "series_id": "main", + "protocol_version": 767, diff --git a/paperweight-core/src/test/resources/functional_test/test-server/patches/sources/net/minecraft/CrashReport.java.patch b/paperweight-core/src/test/resources/functional_test/test-server/patches/sources/net/minecraft/CrashReport.java.patch new file mode 100644 index 00000000..1341d625 --- /dev/null +++ b/paperweight-core/src/test/resources/functional_test/test-server/patches/sources/net/minecraft/CrashReport.java.patch @@ -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() { diff --git a/paperweight-lib/build.gradle.kts b/paperweight-lib/build.gradle.kts index c3d6203c..3fc65f70 100644 --- a/paperweight-lib/build.gradle.kts +++ b/paperweight-lib/build.gradle.kts @@ -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) } diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/DownloadService.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/DownloadService.kt index 0833b603..12aae51c 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/DownloadService.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/DownloadService.kt @@ -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, AutoCloseable { +abstract class DownloadService : BuildService, 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, 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, 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() diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/ApplyGitPatches.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/ApplyGitPatches.kt index 9bc3ab13..68a0ac1f 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/ApplyGitPatches.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/ApplyGitPatches.kt @@ -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", "--prune-tags", "--force").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) } diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/DownloadServerJar.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/DownloadServerJar.kt index 7040764d..6f13ee7d 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/DownloadServerJar.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/DownloadServerJar.kt @@ -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 @get:Nested - @get:Optional abstract val expectedHash: Property override fun init() { diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/ExtractFromBundler.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/ExtractFromBundler.kt index afd208eb..4e8ec1a7 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/ExtractFromBundler.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/ExtractFromBundler.kt @@ -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(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) { diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/MacheTask.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/MacheTask.kt new file mode 100644 index 00000000..d00a9a70 --- /dev/null +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/MacheTask.kt @@ -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(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) + // } + } +} diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/MergeAccessTransforms.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/MergeAccessTransforms.kt index c7df0d17..ecc8d2c2 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/MergeAccessTransforms.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/MergeAccessTransforms.kt @@ -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) } } diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/RemapAccessTransform.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/RemapAccessTransform.kt index 51359dc4..0f86bab3 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/RemapAccessTransform.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/RemapAccessTransform.kt @@ -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) } } diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/RemapSources.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/RemapSources.kt index 50d162a9..79e6db3d 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/RemapSources.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/RemapSources.kt @@ -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) } } } diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/RemapSpigotAt.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/RemapSpigotAt.kt index 5f25d777..90978064 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/RemapSpigotAt.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/RemapSpigotAt.kt @@ -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 { diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/download-task.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/download-task.kt index 6e4fcf25..1cb95e6f 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/download-task.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/download-task.kt @@ -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 + + @get:Input + abstract val repositories: ListProperty + + @get:OutputDirectory + abstract val outputDir: DirectoryProperty + + @get:Internal + abstract val downloader: Property + + @get:Inject + abstract val workerExecutor: WorkerExecutor + + @get:Input + abstract val sources: Property + + 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, workerExecutor: WorkerExecutor, targetDir: Path, repositories: List, - mcLibraries: List, + libraries: List, 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) diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/mache/DecompileJar.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/mache/DecompileJar.kt new file mode 100644 index 00000000..17015b20 --- /dev/null +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/mache/DecompileJar.kt @@ -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 + + @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() + } + } +} diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/mache/RemapJar.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/mache/RemapJar.kt new file mode 100644 index 00000000..ffbb18f3 --- /dev/null +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/mache/RemapJar.kt @@ -0,0 +1,114 @@ +/* + * 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 + + @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() { + if (minecraftClasspath.files.isEmpty()) { + throw RuntimeException("Could not resolve minecraft dependencies, try again") + } + + val out = outputJar.convertToPath().ensureClean() + + val logFile = out.resolveSibling("${out.name}.log") + + try { + 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 + } + } + } catch (e: Exception) { + throw RuntimeException("Error while running codebook, see ${logFile.pathString} for details", e) + } + } +} diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/mache/SetupVanilla.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/mache/SetupVanilla.kt new file mode 100644 index 00000000..d7680304 --- /dev/null +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/mache/SetupVanilla.kt @@ -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> + + @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() + } +} diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/softspoon/ApplyFeaturePatches.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/softspoon/ApplyFeaturePatches.kt new file mode 100644 index 00000000..5474e07e --- /dev/null +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/softspoon/ApplyFeaturePatches.kt @@ -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 + + 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()) + } +} diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/softspoon/ApplyFilePatches.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/softspoon/ApplyFilePatches.kt new file mode 100644 index 00000000..5e7d4fea --- /dev/null +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/softspoon/ApplyFilePatches.kt @@ -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 + + @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 + } +} diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/softspoon/ApplyFilePatchesFuzzy.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/softspoon/ApplyFilePatchesFuzzy.kt new file mode 100644 index 00000000..445d4eba --- /dev/null +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/softspoon/ApplyFilePatchesFuzzy.kt @@ -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 + + init { + run { + minFuzz.convention("0.5") + } + } + + override fun mode(): PatchMode { + return PatchMode.FUZZY + } + + override fun minFuzz(): Float { + return minFuzz.get().toFloat() + } +} diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/softspoon/ApplySourceAT.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/softspoon/ApplySourceAT.kt new file mode 100644 index 00000000..2ed1a546 --- /dev/null +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/softspoon/ApplySourceAT.kt @@ -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 { + 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() + 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() + } +} diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/softspoon/RebuildFilePatches.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/softspoon/RebuildFilePatches.kt new file mode 100644 index 00000000..684af974 --- /dev/null +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/softspoon/RebuildFilePatches.kt @@ -0,0 +1,220 @@ +/* + * 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 + + @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 + + 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 + var addedNewAts = false + 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", "") + addedNewAts = handleATInSource(source, ats, className) || addedNewAts + 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" + ) + } + + if (addedNewAts) { + git("add", ".").executeSilently(silenceErr = true) + git("commit", "--amend", "--no-edit").executeSilently(silenceErr = true) + } + + // 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) + if (addedNewAts) { + try { + git("rebase", "file").executeSilently() + } catch (e: Exception) { + // TODO better message to inform the user on what to do + throw RuntimeException("Encountered conflicts while rebuilding file patches.", e) + } + } + 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() + + // mmmh, maybe add comment to base too? + + 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): Boolean { + val sourceLines = source.readLines() + var foundNew = false + sourceLines.forEach { line -> + if (!line.contains("// Paper-AT: ")) { + return@forEach + } + + foundNew = 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") + } + + return foundNew + } +} diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/McDev.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/McDev.kt index 41e0f745..07116184 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/McDev.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/McDev.kt @@ -35,16 +35,17 @@ object McDev { fun importMcDev( patches: Iterable, - decompJar: Path, + decompJar: Path?, importsFile: Path?, targetDir: Path, dataTargetDir: Path? = null, librariesDirs: List = 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() val decompDataFiles = mutableSetOf() @@ -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): Pair, Set> { + private fun readPatchLines(patches: Iterable, javaSourceSet: String): Pair, Set> { val srcResult = hashSetOf() val dataResult = hashSetOf() - 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, patchLines: Set): Set { + private fun findLibraries(libraryImports: Path?, libFiles: List, patchLines: Set, javaSourceSet: String): Set { val result = hashSetOf() // 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, libFiles: List): Set { + private fun findNeededLibraryImports(patchLines: Set, libFiles: List, javaSourceSet: String): Set { 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() diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/at.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/at.kt new file mode 100644 index 00000000..1b19a872 --- /dev/null +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/at.kt @@ -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) +} diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/constants/constants.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/constants/constants.kt index 2274e8d2..ec6b575b 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/constants/constants.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/constants/constants.kt @@ -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" diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/data/mache/MacheAdditionalDependencies.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/data/mache/MacheAdditionalDependencies.kt new file mode 100644 index 00000000..417d99c1 --- /dev/null +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/data/mache/MacheAdditionalDependencies.kt @@ -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? = null, + val implementation: List? = null, +) diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/data/mache/MacheDependencies.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/data/mache/MacheDependencies.kt new file mode 100644 index 00000000..630003ed --- /dev/null +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/data/mache/MacheDependencies.kt @@ -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, + val paramMappings: List, + val constants: List, + val remapper: List, + val decompiler: List, +) diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/data/mache/MacheMeta.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/data/mache/MacheMeta.kt new file mode 100644 index 00000000..e594ed51 --- /dev/null +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/data/mache/MacheMeta.kt @@ -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, + val decompilerArgs: List, + val remapperArgs: List, + val additionalCompileDependencies: MacheAdditionalDependencies? = null, +) diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/data/mache/MacheRepository.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/data/mache/MacheRepository.kt new file mode 100644 index 00000000..b2f8b478 --- /dev/null +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/data/mache/MacheRepository.kt @@ -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? = null, +) diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/data/mache/MavenArtifact.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/data/mache/MavenArtifact.kt new file mode 100644 index 00000000..33c4d35c --- /dev/null +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/data/mache/MavenArtifact.kt @@ -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" } ?: "") + } +} diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/file.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/file.kt index cc252dea..094996b1 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/file.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/file.kt @@ -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()) + return try { + FileSystems.getFileSystem(jarUri()) + } catch (e: FileSystemNotFoundException) { + FileSystems.newFileSystem(jarUri(), emptyMap()) + } } 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 { return StreamSupport.stream(rootDirectories.spliterator(), false) .flatMap { Files.walk(it) } diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/git.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/git.kt index 71c9beee..4d276271 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/git.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/git.kt @@ -102,6 +102,17 @@ class Git(private val repo: Path, private val env: Map = 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 + } } } diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/utils.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/utils.kt index fa62d067..1cd86394 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/utils.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/utils.kt @@ -75,6 +75,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, JsonSerializer { @@ -108,7 +110,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 @@ -202,6 +206,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 { return when (this) { is Path -> layout.file(providers.provider { toFile() }) diff --git a/paperweight-lib/src/main/resources/post-rewrite.sh b/paperweight-lib/src/main/resources/post-rewrite.sh new file mode 100644 index 00000000..8918da87 --- /dev/null +++ b/paperweight-lib/src/main/resources/post-rewrite.sh @@ -0,0 +1,11 @@ +#!/bin/sh +input=$(cat) # SP [SP ] LF +fileCommit=$(git rev-list -n 1 file) # current commit tagged as "file" +oldObject=$(echo $input | cut -d' ' -f1) # +newObject=$(echo $input | cut -d' ' -f2) # + +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 diff --git a/paperweight-lib/src/test/kotlin/io/papermc/paperweight/tasks/ApplyAccessTransformTest.kt b/paperweight-lib/src/test/kotlin/io/papermc/paperweight/tasks/ApplyAccessTransformTest.kt new file mode 100644 index 00000000..b534103f --- /dev/null +++ b/paperweight-lib/src/test/kotlin/io/papermc/paperweight/tasks/ApplyAccessTransformTest.kt @@ -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().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") + } +} diff --git a/paperweight-lib/src/test/kotlin/io/papermc/paperweight/tasks/TaskTest.kt b/paperweight-lib/src/test/kotlin/io/papermc/paperweight/tasks/TaskTest.kt new file mode 100644 index 00000000..b7c481df --- /dev/null +++ b/paperweight-lib/src/test/kotlin/io/papermc/paperweight/tasks/TaskTest.kt @@ -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") + } +} diff --git a/paperweight-lib/src/test/kotlin/io/papermc/paperweight/tasks/softspoon/ApplyFilePatchesTest.kt b/paperweight-lib/src/test/kotlin/io/papermc/paperweight/tasks/softspoon/ApplyFilePatchesTest.kt new file mode 100644 index 00000000..fa0acf01 --- /dev/null +++ b/paperweight-lib/src/test/kotlin/io/papermc/paperweight/tasks/softspoon/ApplyFilePatchesTest.kt @@ -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") + } +} diff --git a/paperweight-lib/src/test/kotlin/io/papermc/paperweight/tasks/softspoon/ApplySourceATTest.kt b/paperweight-lib/src/test/kotlin/io/papermc/paperweight/tasks/softspoon/ApplySourceATTest.kt new file mode 100644 index 00000000..bbb757d9 --- /dev/null +++ b/paperweight-lib/src/test/kotlin/io/papermc/paperweight/tasks/softspoon/ApplySourceATTest.kt @@ -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().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) + } +} diff --git a/paperweight-lib/src/test/kotlin/io/papermc/paperweight/tasks/softspoon/RebuildFilePatchesTest.kt b/paperweight-lib/src/test/kotlin/io/papermc/paperweight/tasks/softspoon/RebuildFilePatchesTest.kt new file mode 100644 index 00000000..faa4c41a --- /dev/null +++ b/paperweight-lib/src/test/kotlin/io/papermc/paperweight/tasks/softspoon/RebuildFilePatchesTest.kt @@ -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") + } +} diff --git a/paperweight-lib/src/test/kotlin/io/papermc/paperweight/util/ATTest.kt b/paperweight-lib/src/test/kotlin/io/papermc/paperweight/util/ATTest.kt new file mode 100644 index 00000000..125f370f --- /dev/null +++ b/paperweight-lib/src/test/kotlin/io/papermc/paperweight/util/ATTest.kt @@ -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")) + } +} diff --git a/paperweight-lib/src/test/resources/apply_access_transform/input/Test.java b/paperweight-lib/src/test/resources/apply_access_transform/input/Test.java new file mode 100644 index 00000000..b8cb9b8a --- /dev/null +++ b/paperweight-lib/src/test/resources/apply_access_transform/input/Test.java @@ -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; + } +} diff --git a/paperweight-lib/src/test/resources/apply_access_transform/input/ats.at b/paperweight-lib/src/test/resources/apply_access_transform/input/ats.at new file mode 100644 index 00000000..693b10bf --- /dev/null +++ b/paperweight-lib/src/test/resources/apply_access_transform/input/ats.at @@ -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; diff --git a/paperweight-lib/src/test/resources/apply_access_transform/output/output.javap b/paperweight-lib/src/test/resources/apply_access_transform/output/output.javap new file mode 100644 index 00000000..77a6ccfa --- /dev/null +++ b/paperweight-lib/src/test/resources/apply_access_transform/output/output.javap @@ -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."":()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 +} diff --git a/paperweight-lib/src/test/resources/apply_patches/input/base/Test.java b/paperweight-lib/src/test/resources/apply_patches/input/base/Test.java new file mode 100644 index 00000000..b8cb9b8a --- /dev/null +++ b/paperweight-lib/src/test/resources/apply_patches/input/base/Test.java @@ -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; + } +} diff --git a/paperweight-lib/src/test/resources/apply_patches/input/patches/Test.java.patch b/paperweight-lib/src/test/resources/apply_patches/input/patches/Test.java.patch new file mode 100644 index 00000000..58d2f2fd --- /dev/null +++ b/paperweight-lib/src/test/resources/apply_patches/input/patches/Test.java.patch @@ -0,0 +1,10 @@ +--- a/Test.java ++++ b/Test.java +@@ -8,6 +_,6 @@ + } + + public String getTest() { +- return test; ++ return test + "Test"; // Test + } + } diff --git a/paperweight-lib/src/test/resources/apply_patches/output/source/Test.java b/paperweight-lib/src/test/resources/apply_patches/output/source/Test.java new file mode 100644 index 00000000..bb72c175 --- /dev/null +++ b/paperweight-lib/src/test/resources/apply_patches/output/source/Test.java @@ -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 + } +} diff --git a/paperweight-lib/src/test/resources/apply_source_at/input/Test.java b/paperweight-lib/src/test/resources/apply_source_at/input/Test.java new file mode 100644 index 00000000..b8cb9b8a --- /dev/null +++ b/paperweight-lib/src/test/resources/apply_source_at/input/Test.java @@ -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; + } +} diff --git a/paperweight-lib/src/test/resources/apply_source_at/input/Unrelated.java b/paperweight-lib/src/test/resources/apply_source_at/input/Unrelated.java new file mode 100644 index 00000000..c821a33f --- /dev/null +++ b/paperweight-lib/src/test/resources/apply_source_at/input/Unrelated.java @@ -0,0 +1,3 @@ +class Unrealted { + +} diff --git a/paperweight-lib/src/test/resources/apply_source_at/input/ats.at b/paperweight-lib/src/test/resources/apply_source_at/input/ats.at new file mode 100644 index 00000000..693b10bf --- /dev/null +++ b/paperweight-lib/src/test/resources/apply_source_at/input/ats.at @@ -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; diff --git a/paperweight-lib/src/test/resources/apply_source_at/output/Test.java b/paperweight-lib/src/test/resources/apply_source_at/output/Test.java new file mode 100644 index 00000000..869744fb --- /dev/null +++ b/paperweight-lib/src/test/resources/apply_source_at/output/Test.java @@ -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; + } +} diff --git a/paperweight-lib/src/test/resources/apply_source_at/output/Unrelated.java b/paperweight-lib/src/test/resources/apply_source_at/output/Unrelated.java new file mode 100644 index 00000000..c821a33f --- /dev/null +++ b/paperweight-lib/src/test/resources/apply_source_at/output/Unrelated.java @@ -0,0 +1,3 @@ +class Unrealted { + +} diff --git a/paperweight-lib/src/test/resources/rebuild_patches/input/ats.at b/paperweight-lib/src/test/resources/rebuild_patches/input/ats.at new file mode 100644 index 00000000..c46fe9b7 --- /dev/null +++ b/paperweight-lib/src/test/resources/rebuild_patches/input/ats.at @@ -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 diff --git a/paperweight-lib/src/test/resources/rebuild_patches/input/base/Test.java b/paperweight-lib/src/test/resources/rebuild_patches/input/base/Test.java new file mode 100644 index 00000000..b8cb9b8a --- /dev/null +++ b/paperweight-lib/src/test/resources/rebuild_patches/input/base/Test.java @@ -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; + } +} diff --git a/paperweight-lib/src/test/resources/rebuild_patches/input/source/Test.java b/paperweight-lib/src/test/resources/rebuild_patches/input/source/Test.java new file mode 100644 index 00000000..1e61ad8f --- /dev/null +++ b/paperweight-lib/src/test/resources/rebuild_patches/input/source/Test.java @@ -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 + } +} diff --git a/paperweight-lib/src/test/resources/rebuild_patches/output/ats.at b/paperweight-lib/src/test/resources/rebuild_patches/output/ats.at new file mode 100644 index 00000000..3b428036 --- /dev/null +++ b/paperweight-lib/src/test/resources/rebuild_patches/output/ats.at @@ -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 diff --git a/paperweight-lib/src/test/resources/rebuild_patches/output/base/Test.java b/paperweight-lib/src/test/resources/rebuild_patches/output/base/Test.java new file mode 100644 index 00000000..fd852a16 --- /dev/null +++ b/paperweight-lib/src/test/resources/rebuild_patches/output/base/Test.java @@ -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; + } +} diff --git a/paperweight-lib/src/test/resources/rebuild_patches/output/patches/Test.java.patch b/paperweight-lib/src/test/resources/rebuild_patches/output/patches/Test.java.patch new file mode 100644 index 00000000..aaa46dd4 --- /dev/null +++ b/paperweight-lib/src/test/resources/rebuild_patches/output/patches/Test.java.patch @@ -0,0 +1,10 @@ +--- a/Test.java ++++ b/Test.java +@@ -8,6 +_,6 @@ + } + + private final String getTest() { +- return test; ++ return test + "Test"; // Test + } + } diff --git a/paperweight-lib/src/test/resources/rebuild_patches/output/source/Test.java b/paperweight-lib/src/test/resources/rebuild_patches/output/source/Test.java new file mode 100644 index 00000000..a2d35e43 --- /dev/null +++ b/paperweight-lib/src/test/resources/rebuild_patches/output/source/Test.java @@ -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 + } +} diff --git a/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/PaperweightUser.kt b/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/PaperweightUser.kt index a0f393c0..b2cca41c 100644 --- a/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/PaperweightUser.kt +++ b/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/PaperweightUser.kt @@ -67,7 +67,9 @@ abstract class PaperweightUser : Plugin { 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("cleanAllPaperweightUserdevCaches") { group = "paperweight" diff --git a/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/v2/SetupHandlerImplV2.kt b/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/v2/SetupHandlerImplV2.kt index ef7727e4..ade6bbdd 100644 --- a/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/v2/SetupHandlerImplV2.kt +++ b/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/v2/SetupHandlerImplV2.kt @@ -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() }