diff --git a/.github/workflows/deploy-snapshot.yml b/.github/workflows/deploy-snapshot.yml index 5353dd42b..a70e593b5 100644 --- a/.github/workflows/deploy-snapshot.yml +++ b/.github/workflows/deploy-snapshot.yml @@ -12,25 +12,15 @@ on: jobs: deploy: name: Deploy Snapshot - runs-on: namespace-profile-linux-default + runs-on: 'ubuntu-latest' steps: - - uses: namespacelabs/nscloud-checkout-action@v9 - - uses: actions/setup-java@v6 + - uses: actions/checkout@v5 + - uses: actions/setup-java@v5 with: - distribution: 'temurin' java-version: 21 - cache: "" # namespace handles this - - name: Set up cache - uses: namespacelabs/nscloud-cache-action@v1 - with: - cache: gradle - - name: Setup gradle build cache - run: | - nsc cache gradle setup --init-gradle /tmp/init.gradle + distribution: 'temurin' - name: Setup Gradle uses: gradle/actions/setup-gradle@v6 - with: - cache-disabled: true # namespace handles this - name: Get project version id: get_version shell: bash @@ -39,7 +29,7 @@ jobs: echo version=$project_version >> $GITHUB_OUTPUT - name: Deploy snapshot version if: endsWith(steps.get_version.outputs.version, '-SNAPSHOT') - run: ./gradlew --init-script=/tmp/init.gradle -Dorg.gradle.parallel=true publish --no-daemon --stacktrace -Dorg.gradle.internal.http.socketTimeout=90000 -Dorg.gradle.internal.http.connectionTimeout=90000 + run: ./gradlew -Dorg.gradle.parallel=true publishAllPublicationsToCanvasMC_SnapshotsRepository --no-daemon --stacktrace -Dorg.gradle.internal.http.socketTimeout=90000 -Dorg.gradle.internal.http.connectionTimeout=90000 env: - ORG_GRADLE_PROJECT_paperUsername: ${{ secrets.ARTIFACTORY_USERNAME }} - ORG_GRADLE_PROJECT_paperPassword: ${{ secrets.ARTIFACTORY_PASSWORD }} + PUBLISH_USER: ${{ secrets.PUBLISH_USER }} + PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 83bb6f5e4..3fd2756d1 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -6,35 +6,25 @@ on: jobs: deploy: name: Deploy - runs-on: namespace-profile-linux-default + runs-on: 'ubuntu-latest' steps: - - uses: namespacelabs/nscloud-checkout-action@v9 - - uses: actions/setup-java@v6 + - uses: actions/checkout@v5 + - uses: actions/setup-java@v5 with: - distribution: 'temurin' java-version: 21 - cache: "" # namespace handles this - - name: Set up cache - uses: namespacelabs/nscloud-cache-action@v1 - with: - cache: gradle - - name: Setup gradle build cache - run: | - nsc cache gradle setup --init-gradle /tmp/init.gradle + distribution: 'temurin' - name: Setup Gradle uses: gradle/actions/setup-gradle@v6 - with: - cache-disabled: true # namespace handles this - name: Deploy release - run: ./gradlew --init-script=/tmp/init.gradle publishPlugins --no-daemon --stacktrace + run: ./gradlew publishAllPublicationsToCanvasMC_ReleasesRepository --no-daemon --stacktrace env: - GRADLE_PUBLISH_KEY: "${{ secrets.GRADLE_PLUGIN_PORTAL_KEY }}" - GRADLE_PUBLISH_SECRET: "${{ secrets.GRADLE_PLUGIN_PORTAL_SECRET }}" + PUBLISH_USER: ${{ secrets.PUBLISH_USER }} + PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} - name: Parse tag id: vars - run: echo "tag=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" + run: echo ::set-output name=tag::${GITHUB_REF#refs/*/} - name: Create release and changelog uses: MC-Machinations/auto-release-changelog@v1.1.3 with: token: ${{ secrets.GITHUB_TOKEN }} - title: paperweight ${{ steps.vars.outputs.tag }} + title: weaver ${{ steps.vars.outputs.tag }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 21655a720..75617ce4c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,30 +9,20 @@ jobs: # Only run on PRs if the source branch is on someone else's repo if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }} name: Test - runs-on: namespace-profile-linux-default + runs-on: 'ubuntu-latest' steps: - - uses: namespacelabs/nscloud-checkout-action@v9 - - uses: actions/setup-java@v6 + - uses: actions/checkout@v5 + - uses: actions/setup-java@v5 with: - distribution: 'temurin' java-version: 21 - cache: "" # namespace handles this - - name: Set up cache - uses: namespacelabs/nscloud-cache-action@v1 - with: - cache: gradle - - name: Setup gradle build cache - run: | - nsc cache gradle setup --init-gradle /tmp/init.gradle + distribution: 'temurin' - name: Setup Gradle uses: gradle/actions/setup-gradle@v6 - with: - cache-disabled: true # namespace handles this - name: Execute Gradle build run: | git config --global user.email "no-reply@github.com" git config --global user.name "GitHub Actions" - ./gradlew --init-script=/tmp/init.gradle build --no-daemon --stacktrace + ./gradlew build --no-daemon --stacktrace - name: Publish Test Report uses: mikepenz/action-junit-report@v6 if: always() diff --git a/build-logic/build.gradle.kts b/build-logic/build.gradle.kts new file mode 100644 index 000000000..a87d19889 --- /dev/null +++ b/build-logic/build.gradle.kts @@ -0,0 +1,28 @@ +plugins { + `kotlin-dsl` +} + +repositories { + mavenCentral() + gradlePluginPortal() +} + +dependencies { + implementation(libs.gradle.ktlint) + implementation(libs.gradle.level.headered) + implementation(libs.gradle.shadow) + implementation(libs.gradle.kotlin.dsl) + implementation(kotlin("gradle-plugin", embeddedKotlinVersion)) + implementation(libs.gradle.plugin.publish) + + /* + constraints { + // spotless carries 1.9.10 and kotlin-dsl plugin has a strictly 2.4.0 constraint + implementation("org.jetbrains.kotlin:kotlin-stdlib") { + version { + strictly(embeddedKotlinVersion) + } + } + } + */ +} diff --git a/build-logic/settings.gradle.kts b/build-logic/settings.gradle.kts new file mode 100644 index 000000000..c450d63d2 --- /dev/null +++ b/build-logic/settings.gradle.kts @@ -0,0 +1,13 @@ +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" +} + +dependencyResolutionManagement { + versionCatalogs { + register("libs") { + from(files("../gradle/libs.versions.toml")) + } + } +} + +rootProject.name = "build-logic" diff --git a/buildSrc/src/main/kotlin/config-kotlin.gradle.kts b/build-logic/src/main/kotlin/config-kotlin.gradle.kts similarity index 91% rename from buildSrc/src/main/kotlin/config-kotlin.gradle.kts rename to build-logic/src/main/kotlin/config-kotlin.gradle.kts index 50bf7af62..8652483b0 100644 --- a/buildSrc/src/main/kotlin/config-kotlin.gradle.kts +++ b/build-logic/src/main/kotlin/config-kotlin.gradle.kts @@ -2,6 +2,7 @@ import net.octyl.levelheadered.HeaderApplyTask import net.octyl.levelheadered.HeaderVerifyTask import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestLogEvent +import org.jetbrains.kotlin.gradle.dsl.JvmDefaultMode import org.jetbrains.kotlin.gradle.dsl.JvmTarget plugins { @@ -25,14 +26,15 @@ kotlin { } compilerOptions { jvmTarget = JvmTarget.JVM_21 - freeCompilerArgs = listOf("-Xjvm-default=all", "-Xjdk-release=21") + jvmDefault = JvmDefaultMode.NO_COMPATIBILITY + freeCompilerArgs = listOf("-Xjdk-release=21") } } repositories { maven("https://repo.papermc.io/repository/maven-public/") { mavenContent { - includeGroup("codechicken") + includeGroup("io.codechicken") includeGroup("net.fabricmc") includeGroupAndSubgroups("io.papermc") } @@ -103,7 +105,7 @@ ktlint { } levelHeadered { - headerTemplate(rootProject.file("license/copyright.txt")) + headerTemplate(isolated.rootProject.projectDirectory.file("license/copyright.txt").asFile) } tasks.named("applyTestHeader") { diff --git a/buildSrc/src/main/kotlin/config-publish.gradle.kts b/build-logic/src/main/kotlin/config-publish.gradle.kts similarity index 62% rename from buildSrc/src/main/kotlin/config-publish.gradle.kts rename to build-logic/src/main/kotlin/config-publish.gradle.kts index 96f35bc3d..245fa1632 100644 --- a/buildSrc/src/main/kotlin/config-publish.gradle.kts +++ b/build-logic/src/main/kotlin/config-publish.gradle.kts @@ -2,7 +2,6 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import org.gradle.plugin.compatibility.compatibility plugins { - id("org.jetbrains.kotlin.jvm") id("com.gradleup.shadow") id("com.gradle.plugin-publish") } @@ -17,21 +16,34 @@ if (noRelocate) { } } -val shade = configurations.create("shade") +val sourcesJar = configurations.dependencyScope("sourcesJar") +val sourcesJarResolvable = configurations.resolvable("sourcesJarResolvable") { + extendsFrom(sourcesJar) +} + +dependencies { + sourcesJar(project(":paperweight-lib", "sourcesJar")) +} + +val shade = configurations.dependencyScope("shade") +val shadeResolvable = configurations.resolvable("shadeResolvable") { + extendsFrom(shade) +} + configurations.implementation { extendsFrom(shade) } configurations.shadowRuntimeElements { - compatibilityAttributes(objects) + compatibilityAttributes() } configurations.runtimeElements { - compatibilityAttributes(objects) + compatibilityAttributes() } fun ShadowJar.configureStandard() { - configurations = listOf(shade) - filesMatching("META-INF/services/**") { + configurations.setFrom(listOf(shadeResolvable)) + filesMatching("META-INF/**") { duplicatesStrategy = DuplicatesStrategy.INCLUDE } filesMatching("META-INF/*.kotlin_module") { @@ -48,23 +60,25 @@ fun ShadowJar.configureStandard() { mergeServiceFiles() } -val sourcesJar = tasks.named("sourcesJar") { - from( - zipTree(project(":paperweight-lib").tasks - .named("sourcesJar", AbstractArchiveTask::class) - .flatMap { it.archiveFile }) - ) { +private fun SetProperty.setFrom(configurations: List>) { + empty() + configurations.forEach { add(it) } +} + +val libSourcesJar = tasks.named("sourcesJar") { + from(zipTree(sourcesJarResolvable.flatMap { it.elements.map { it.single().asFile } })) { exclude("META-INF/**") } } gradlePlugin { - website.set("https://github.com/PaperMC/paperweight") - vcsUrl.set("https://github.com/PaperMC/paperweight") + website.set("https://github.com/CraftCanvasMC/weaver/") + vcsUrl.set("https://github.com/CraftCanvasMC/weaver/") plugins.configureEach { compatibility { features { configurationCache = true + isolatedProjects = true } } } @@ -81,8 +95,8 @@ val shadowJar = tasks.named("shadowJar") { val prefix = "paper.libs" listOf( - "codechicken.diffpatch", - /* -> */ "codechicken.repack", + "io.codechicken.diffpatch", + /* -> */ "io.codechicken.repack", "com.github.salomonbrys.kotson", "com.google.gson", "dev.denwav.hypo", @@ -112,9 +126,19 @@ val shadowJar = tasks.named("shadowJar") { publishing { repositories { - maven("https://artifactory.papermc.io/artifactory/snapshots/") { - credentials(PasswordCredentials::class) - name = "paper" + maven("https://maven.canvasmc.io/snapshots") { + name = "CanvasMC_Snapshots" + credentials { + username = providers.environmentVariable("PUBLISH_USER").orNull + password = providers.environmentVariable("PUBLISH_TOKEN").orNull + } + } + maven("https://maven.canvasmc.io/releases") { + name = "CanvasMC_Releases" + credentials { + username = providers.environmentVariable("PUBLISH_USER").orNull + password = providers.environmentVariable("PUBLISH_TOKEN").orNull + } } } @@ -128,13 +152,13 @@ publishing { } fun MavenPom.pomConfig() { - val repoPath = "PaperMC/paperweight" + val repoPath = "CraftCanvasMC/weaver" val repoUrl = "https://github.com/$repoPath" - name.set("paperweight") - description.set("Gradle plugin for the PaperMC project") + name.set("weaver") + description.set("Gradle plugin for the CanvasMC project") url.set(repoUrl) - inceptionYear.set("2020") + inceptionYear.set("2025") licenses { license { @@ -151,10 +175,9 @@ fun MavenPom.pomConfig() { developers { developer { - id.set("DenWav") - name.set("Kyle Wood") - email.set("kyle@denwav.dev") - url.set("https://github.com/DenWav") + id.set("CanvasMC") + name.set("Canvas") + url.set("https://github.com/CraftCanvasMC") } } diff --git a/buildSrc/src/main/kotlin/utils.kt b/build-logic/src/main/kotlin/utils.kt similarity index 65% rename from buildSrc/src/main/kotlin/utils.kt rename to build-logic/src/main/kotlin/utils.kt index 03f5a982d..b53596294 100644 --- a/buildSrc/src/main/kotlin/utils.kt +++ b/build-logic/src/main/kotlin/utils.kt @@ -2,23 +2,22 @@ import org.gradle.api.Action import org.gradle.api.artifacts.Configuration import org.gradle.api.attributes.java.TargetJvmVersion import org.gradle.api.attributes.plugin.GradlePluginApiVersion -import org.gradle.api.model.ObjectFactory import org.gradle.kotlin.dsl.* import org.gradle.plugin.devel.GradlePluginDevelopmentExtension import org.gradle.plugin.devel.PluginDeclaration -fun Configuration.compatibilityAttributes(objects: ObjectFactory) { +fun Configuration.compatibilityAttributes() { attributes { attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) - attribute(GradlePluginApiVersion.GRADLE_PLUGIN_API_VERSION_ATTRIBUTE, objects.named("9.7.1")) + attribute(GradlePluginApiVersion.GRADLE_PLUGIN_API_VERSION_ATTRIBUTE, named("9.7.1")) } } fun GradlePluginDevelopmentExtension.setupPlugin(prefix: String, op: Action) { - plugins.register("paperweight-$prefix") { - id = "io.papermc.paperweight." + prefix - displayName = "paperweight $prefix" - tags.set(listOf("paper", "minecraft")) + plugins.register("weaver-$prefix") { + id = "io.canvasmc.weaver." + prefix + displayName = "weaver $prefix" + tags.set(listOf("paper", "minecraft", "canvas")) op.execute(this) } } diff --git a/build.gradle.kts b/build.gradle.kts index addb5ebc4..3353e0523 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,7 @@ +plugins { + `kotlin-dsl` apply false +} + tasks.register("printVersion") { val ver = project.version doFirst { diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts deleted file mode 100644 index ef2bb6cfa..000000000 --- a/buildSrc/build.gradle.kts +++ /dev/null @@ -1,22 +0,0 @@ -plugins { - `kotlin-dsl` - `kotlin-dsl-precompiled-script-plugins` -} - -repositories { - mavenCentral() - gradlePluginPortal() -} - -dependencies { - implementation(libs.gradle.ktlint) - implementation(libs.gradle.level.headered) - implementation(libs.gradle.shadow) - implementation(libs.gradle.kotlin.dsl) - implementation(libs.gradle.plugin.kotlin.withVersion(embeddedKotlinVersion)) - implementation(libs.gradle.plugin.publish) -} - -fun Provider.withVersion(version: String): Provider { - return map { "${it.module.group}:${it.module.name}:$version" } -} diff --git a/buildSrc/settings.gradle.kts b/buildSrc/settings.gradle.kts deleted file mode 100644 index 62991c1ef..000000000 --- a/buildSrc/settings.gradle.kts +++ /dev/null @@ -1,9 +0,0 @@ -rootProject.name = "buildSrc" - -dependencyResolutionManagement { - versionCatalogs { - create("libs") { - from(files("../gradle/libs.versions.toml")) - } - } -} diff --git a/gradle.properties b/gradle.properties index 8b2f05e41..65c21c1f3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,8 @@ -group = io.papermc.paperweight -version = 2.0.0-SNAPSHOT +group = io.canvasmc.weaver +version = 2.5.2-SNAPSHOT org.gradle.caching = true org.gradle.configuration-cache = true org.gradle.parallel = true +org.gradle.tooling.parallel = true +org.gradle.isolated-projects = true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index aa4091c7b..1aed08898 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -34,7 +34,7 @@ hypo-mappings = { module = "dev.denwav.hypo:hypo-mappings", version.ref = "hypo" lorenzTiny = "net.fabricmc:lorenz-tiny:3.0.0" jbsdiff = "io.sigpipe:jbsdiff:1.0" -diffpatch = "io.codechicken:DiffPatch:1.5.0.30" +diffpatch = "io.codechicken:DiffPatch:2.1.0.43" serialize-core = { module = "org.jetbrains.kotlinx:kotlinx-serialization-core", version.ref = "serialize" } serialize-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "serialize" } @@ -51,7 +51,6 @@ gradle-ktlint = "org.jlleitschuh.gradle.ktlint:org.jlleitschuh.gradle.ktlint.gra gradle-level-headered = "net.octyl.level-headered:net.octyl.level-headered.gradle.plugin:0.1.2" gradle-shadow = "com.gradleup.shadow:com.gradleup.shadow.gradle.plugin:9.6.1" gradle-kotlin-dsl = "org.gradle.kotlin.kotlin-dsl:org.gradle.kotlin.kotlin-dsl.gradle.plugin:6.7.6" -gradle-plugin-kotlin = { module = "org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin" } gradle-plugin-publish = "com.gradle.publish:plugin-publish-plugin:2.2.1" # for renovate diff --git a/paperweight-core/build.gradle.kts b/paperweight-core/build.gradle.kts index b89f06804..09aa7ebef 100644 --- a/paperweight-core/build.gradle.kts +++ b/paperweight-core/build.gradle.kts @@ -1,6 +1,6 @@ plugins { - `config-kotlin` - `config-publish` + id("config-kotlin") + id("config-publish") } dependencies { diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/PaperweightDependencyBridge.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/PaperweightDependencyBridge.kt new file mode 100644 index 000000000..da1b36ef5 --- /dev/null +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/PaperweightDependencyBridge.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 + +import io.papermc.paperweight.util.constants.JST_CLASSPATH_ATTRIBUTE +import io.papermc.paperweight.util.constants.JST_CLASSPATH_CONFIG +import javax.inject.Inject +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.artifacts.ConfigurationContainer +import org.gradle.api.plugins.JavaPlugin + +abstract class PaperweightDependencyBridge : Plugin { + + @get:Inject + abstract val configurations: ConfigurationContainer + + override fun apply(target: Project) { + configurations.consumable(JST_CLASSPATH_CONFIG) { + attributes { + attribute(JST_CLASSPATH_ATTRIBUTE, true) + } + extendsFrom(configurations.named(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME)) + } + } + // TODO +} diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/PaperweightSourceGeneratorHelper.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/PaperweightSourceGeneratorHelper.kt index b2f4ff3f8..accf6eecb 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/PaperweightSourceGeneratorHelper.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/PaperweightSourceGeneratorHelper.kt @@ -50,7 +50,7 @@ abstract class PaperweightSourceGeneratorHelper : Plugin { afterEvaluate { if (ext.addVanillaServerToImplementation.get()) { configurations.named("implementation") { - extendsFrom(vanilla.get()) + extendsFrom(vanilla) } } } 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 00009043b..cbfbc47f2 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 @@ -28,6 +28,8 @@ import io.papermc.paperweight.core.extension.PaperweightCoreExtension import io.papermc.paperweight.core.taskcontainers.CoreTasks import io.papermc.paperweight.core.taskcontainers.DevBundleTasks import io.papermc.paperweight.core.taskcontainers.PaperclipTasks +import io.papermc.paperweight.core.tasks.patching.ApplyBasePatches +import io.papermc.paperweight.core.tasks.patching.ApplyFilePatches import io.papermc.paperweight.core.tasks.patchroulette.PatchRouletteTasks import io.papermc.paperweight.core.util.coreExt import io.papermc.paperweight.tasks.* @@ -61,7 +63,7 @@ abstract class PaperweightCore : Plugin { override fun apply(target: Project) { Git.checkForGit(target.providers) - printId("paperweight-core", target.gradle) + printId("weaver-core", target.gradle) val ext = target.extensions.create(PAPERWEIGHT_EXTENSION, target) @@ -75,7 +77,7 @@ abstract class PaperweightCore : Plugin { delete(layout.cache) } - target.configurations.create(REMAPPER_CONFIG) { + target.configurations.register(REMAPPER_CONFIG) { defaultDependencies { // Join list to avoid relocations breaking the string val coordinates = "${listOf("net", "fabricmc").joinToString(".")}:tiny-remapper:${LibraryVersions.TINY_REMAPPER}:fat" @@ -83,8 +85,8 @@ abstract class PaperweightCore : Plugin { add(remapper) } } - target.configurations.create(PAPERCLIP_CONFIG) - val macheConfig = target.configurations.create(MACHE_CONFIG) { + target.configurations.register(PAPERCLIP_CONFIG) + val macheConfig = target.configurations.register(MACHE_CONFIG) { attributes.attribute(MacheOutput.ATTRIBUTE, objects.named(MacheOutput.ZIP)) } target.configurations.register(MACHE_CODEBOOK_CONFIG) { isTransitive = false } @@ -96,7 +98,7 @@ abstract class PaperweightCore : Plugin { extendsFrom(macheConfig) } target.configurations.register(MACHE_MINECRAFT_CONFIG) { - extendsFrom(macheMinecraftLibrariesConfig.get()) + extendsFrom(macheMinecraftLibrariesConfig) } target.configurations.consumable(MAPPED_JAR_OUTGOING_CONFIG) // For source generator modules target.configurations.register(JST_CONFIG) { @@ -106,9 +108,19 @@ abstract class PaperweightCore : Plugin { } } + target.configurations.register(JST_CLASSPATH_CONFIG) { + attributes { + attribute(JST_CLASSPATH_ATTRIBUTE, true) + } + extendsFrom( + target.configurations.named(MACHE_MINECRAFT_CONFIG), + target.configurations.named(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME) + ) + } + // impl extends minecraft target.configurations.named(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME) { - extendsFrom(macheMinecraftLibrariesConfig.get()) + extendsFrom(macheMinecraftLibrariesConfig) } if (target.providers.gradleProperty("paperweight.dev").orNull == "true") { @@ -165,6 +177,10 @@ abstract class PaperweightCore : Plugin { } repositories { + maven(ext.jstRepo) { + name = JST_REPO_NAME + content { onlyForConfigurations(JST_CONFIG) } + } maven(ext.macheRepo) { name = MACHE_REPO_NAME content { onlyForConfigurations(MACHE_CONFIG) } @@ -183,10 +199,12 @@ abstract class PaperweightCore : Plugin { ) if (coreExt.updatingMinecraft.oldPaperCommit.isPresent || target.providers.gradleProperty("updatingMinecraft").orNull == "true") { - tasks.paperPatchingTasks.applySourcePatches.configure { + tasks.paperPatchingTasks.applyBasePatches.configure { additionalRemote = layout.cache.resolve( "$OLD_PAPER_PATH/${coreExt.updatingMinecraft.oldPaperCommit.get()}/paper-server/src/minecraft/java" ).absolutePathString() + } + tasks.paperPatchingTasks.applySourcePatches.configure { emitRejects = false } @@ -197,6 +215,40 @@ abstract class PaperweightCore : Plugin { coreExt.paper.rejectsDir, layout.projectDirectory.dir("src/minecraft/java"), ) + } else if (coreExt.activeFork.isPresent && coreExt.updatingMinecraft.oldForkCommit.isPresent) { + // old commit fetching for forks through a gradle property + target.tasks.named("applyMinecraftBasePatches").configure { + additionalRemote = coreExt.activeFork.map { + layout.cache + .resolve( + "$PAPER_PATH/old${it.name.capitalized()}/${coreExt.updatingMinecraft.oldForkCommit.get()}/${it.name}-server/src/minecraft/java" + ) + .absolutePathString() + } + } + target.tasks.named("applyMinecraftSourcePatches").configure { + emitRejects = false + } + + PatchRouletteTasks( + target, + coreExt.activeFork.get().name.lowercase(), + coreExt.minecraftVersion, + coreExt.activeFork.flatMap { it.rejectsDir }, + layout.projectDirectory.dir("src/minecraft/java"), + ) + + coreExt.activeFork.get().upstream { + directoryPatchSets.forEach { + PatchRouletteTasks( + target, + it.name, + coreExt.minecraftVersion.map { ver -> "${it.name}-$ver" }, + it.rejectsDir, + it.outputDir.get(), + ) + } + } } } } diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/AdditionalUpstreamConfig.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/AdditionalUpstreamConfig.kt new file mode 100644 index 000000000..3f7fbabd0 --- /dev/null +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/AdditionalUpstreamConfig.kt @@ -0,0 +1,117 @@ +/* + * 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.extension + +import javax.inject.Inject +import org.gradle.api.Action +import org.gradle.api.Named +import org.gradle.api.NamedDomainObjectContainer +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.Property +import org.gradle.kotlin.dsl.domainObjectContainer +import org.gradle.kotlin.dsl.newInstance + +abstract class AdditionalUpstreamConfig @Inject constructor( + private val configName: String, + objects: ObjectFactory, +) : Named { + override fun getName(): String { + return configName + } + + abstract val repo: Property + abstract val ref: Property + val sourceGenerationConfig: SourceGenerationConfig = objects.newInstance() + val patchGenerationConfig: PatchGenerationConfig = objects.newInstance() + + fun sourceGeneration(op: Action) { + op.execute(sourceGenerationConfig) + } + + fun patchGeneration(op: Action) { + op.execute(patchGenerationConfig) + } + + @Suppress("UNUSED_PARAMETER") + abstract class SourceGenerationConfig @Inject constructor( + objects: ObjectFactory, + ) { + val generationConfig: NamedDomainObjectContainer = objects.domainObjectContainer( + GenerationConfig::class + ) { name -> objects.newInstance(name, objects) } + + @Suppress("UNUSED_PARAMETER") + abstract class GenerationConfig @Inject constructor( + private val setName: String, + objects: ObjectFactory, + ) : Named { + override fun getName(): String { + return setName + } + + abstract val generateSources: Property + abstract val generateResources: Property + abstract val generateTestSources: Property + abstract val generateTestResources: Property + + abstract val sourcesOutputDir: DirectoryProperty + abstract val resourcesOutputDir: DirectoryProperty + abstract val testSourcesOutputDir: DirectoryProperty + abstract val testResourcesOutputDir: DirectoryProperty + + abstract val additionalAts: RegularFileProperty + + abstract val additionalPatch: RegularFileProperty + } + } + + abstract class PatchGenerationConfig @Inject constructor( + objects: ObjectFactory + ) { + abstract val outputDir: DirectoryProperty + + abstract val patchesDirOutput: Property + + val inputConfig: NamedDomainObjectContainer = objects.domainObjectContainer( + InputConfig::class + ) { name -> objects.newInstance(name, objects) } + + @Suppress("UNUSED_PARAMETER") + abstract class InputConfig @Inject constructor( + private val setName: String, + objects: ObjectFactory, + ) : Named { + override fun getName(): String { + return setName + } + + abstract val additionalAts: RegularFileProperty + + abstract val additionalPatch: RegularFileProperty + } + } + + fun github(owner: String, repo: String): String = "https://github.com/$owner/$repo.git" +} diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/ForkConfig.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/ForkConfig.kt index 176352ca0..ef0a668b0 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/ForkConfig.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/ForkConfig.kt @@ -45,10 +45,11 @@ abstract class ForkConfig @Inject constructor( return configName } - val rootDirectory: DirectoryProperty = objects.directoryProperty().convention(project.rootProject.layout.projectDirectory).finalizedOnRead() + val rootDirectory: DirectoryProperty = objects.directoryProperty().convention(project.isolated.rootProject.projectDirectory).finalizedOnRead() val serverDirectory: DirectoryProperty = objects.dirFrom(rootDirectory, providers.provider { "$name-server" }) val serverPatchesDir: DirectoryProperty = objects.dirFrom(serverDirectory, "minecraft-patches") val rejectsDir: DirectoryProperty = objects.dirFrom(serverPatchesDir, "rejected") + val basePatchDir: DirectoryProperty = objects.dirFrom(serverPatchesDir, "base") val sourcePatchDir: DirectoryProperty = objects.dirFrom(serverPatchesDir, "sources") val resourcePatchDir: DirectoryProperty = objects.dirFrom(serverPatchesDir, "resources") val featurePatchDir: DirectoryProperty = objects.dirFrom(serverPatchesDir, "features") 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 af3db8fd0..fb7f3ea81 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 @@ -31,10 +31,11 @@ import org.gradle.api.model.ObjectFactory abstract class PaperExtension @Inject constructor(objects: ObjectFactory, project: Project) { - val rootDirectory: DirectoryProperty = objects.directoryProperty().convention(project.rootProject.layout.projectDirectory) + val rootDirectory: DirectoryProperty = objects.directoryProperty().convention(project.isolated.rootProject.projectDirectory) val paperServerDir: DirectoryProperty = objects.dirFrom(rootDirectory, "paper-server") val serverPatchesDir: DirectoryProperty = objects.dirFrom(paperServerDir, "patches") val rejectsDir: DirectoryProperty = objects.dirFrom(serverPatchesDir, "rejected") + val basePatchDir: DirectoryProperty = objects.dirFrom(serverPatchesDir, "base") val sourcePatchDir: DirectoryProperty = objects.dirFrom(serverPatchesDir, "sources") val resourcePatchDir: DirectoryProperty = objects.dirFrom(serverPatchesDir, "resources") val featurePatchDir: DirectoryProperty = objects.dirFrom(serverPatchesDir, "features") 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 ab3e282ce..b6a8162d1 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 @@ -40,6 +40,7 @@ abstract class PaperweightCoreExtension @Inject constructor(objects: ObjectFacto val bundlerJarName: Property = objects.property().convention("paper") val macheRepo: Property = objects.property().convention(PAPER_MAVEN_REPO_URL) + val jstRepo: Property = objects.property().convention(PAPER_MAVEN_REPO_URL) val gitFilePatches: Property = objects.property().convention(false) val filterPatches: Property = objects.property().convention(true) @@ -66,4 +67,6 @@ abstract class PaperweightCoreExtension @Inject constructor(objects: ObjectFacto fun updatingMinecraft(action: Action) { action.execute(updatingMinecraft) } + + val validateATs: Property = objects.property().convention(true) } diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/UpdatingMinecraftExtension.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/UpdatingMinecraftExtension.kt index d8164ffc1..87f7577a5 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/UpdatingMinecraftExtension.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/UpdatingMinecraftExtension.kt @@ -26,4 +26,5 @@ import org.gradle.api.provider.Property interface UpdatingMinecraftExtension { val oldPaperCommit: Property + val oldForkCommit: Property } diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/UpstreamConfig.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/UpstreamConfig.kt index c448db831..6307717b1 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/UpstreamConfig.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/extension/UpstreamConfig.kt @@ -35,6 +35,7 @@ import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.provider.Provider +import org.gradle.api.provider.ProviderFactory import org.gradle.api.provider.SetProperty import org.gradle.kotlin.dsl.* @@ -93,6 +94,7 @@ abstract class UpstreamConfig @Inject constructor( abstract class DirectoryPatchSet @Inject constructor( objects: ObjectFactory, + providers: ProviderFactory, private val setName: String, ) : Named { override fun getName(): String = setName @@ -101,17 +103,21 @@ abstract class UpstreamConfig @Inject constructor( abstract val excludes: SetProperty abstract val outputDir: DirectoryProperty + val buildDataDir: DirectoryProperty = objects.directoryProperty().convention(outputDir.dir("../build-data")) + val additionalAts: RegularFileProperty = objects.fileFrom(buildDataDir, providers.provider { "$name.at" }) abstract val patchesDir: DirectoryProperty val rejectsDir: DirectoryProperty = objects.dirFrom(patchesDir, "rejected") + val basePatchDir: DirectoryProperty = objects.dirFrom(patchesDir, "base") val filePatchDir: DirectoryProperty = objects.dirFrom(patchesDir, "files") val featurePatchDir: DirectoryProperty = objects.dirFrom(patchesDir, "features") } abstract class RepoPatchSet @Inject constructor( objects: ObjectFactory, + providers: ProviderFactory, name: String, - ) : DirectoryPatchSet(objects, name) { + ) : DirectoryPatchSet(objects, providers, name) { abstract val upstreamRepo: Property fun Provider.patchedRepo(name: String): Provider = 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 283318bd6..e6e7d9bb0 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 @@ -23,13 +23,12 @@ package io.papermc.paperweight.core.taskcontainers import io.papermc.paperweight.DownloadService -import io.papermc.paperweight.core.extension.PaperweightCoreExtension -import io.papermc.paperweight.core.util.coreExt import io.papermc.paperweight.tasks.* import io.papermc.paperweight.util.* import io.papermc.paperweight.util.constants.* import java.nio.file.Path import org.gradle.api.Project +import org.gradle.api.artifacts.ConfigurationContainer import org.gradle.api.artifacts.component.ModuleComponentIdentifier import org.gradle.api.plugins.JavaPlugin import org.gradle.api.provider.Provider @@ -39,9 +38,9 @@ import org.gradle.kotlin.dsl.* @Suppress("MemberVisibilityCanBePrivate") open class AllTasks( project: Project, + configurations: ConfigurationContainer = project.configurations, tasks: TaskContainer = project.tasks, cache: Path = project.layout.cache, - extension: PaperweightCoreExtension = project.coreExt, downloadService: Provider = project.download ) : InitialTasks(project) { @@ -56,7 +55,7 @@ open class AllTasks( val downloadRuntimeClasspathSources = tasks.register("downloadRuntimeClasspathSources") { paperDependencies.set( - project.configurations.named(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME).map { configuration -> + configurations.named(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME).map { configuration -> val view = configuration.incoming.artifactView { componentFilter { it is ModuleComponentIdentifier } } diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/CoreTasks.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/CoreTasks.kt index 4ee9c26ee..754e02360 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/CoreTasks.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/CoreTasks.kt @@ -38,6 +38,7 @@ import io.papermc.paperweight.util.constants.* import io.papermc.paperweight.util.data.mache.* import java.nio.file.Files import org.gradle.api.Project +import org.gradle.api.artifacts.ConfigurationContainer import org.gradle.api.provider.Property import org.gradle.api.tasks.TaskContainer import org.gradle.kotlin.dsl.* @@ -45,6 +46,7 @@ import org.gradle.kotlin.dsl.* class CoreTasks( val project: Project, val mache: Property, + val configurations: ConfigurationContainer = project.configurations, tasks: TaskContainer = project.tasks ) : AllTasks(project) { lateinit var paperPatchingTasks: MinecraftPatchingTasks @@ -53,9 +55,9 @@ class CoreTasks( serverJar.set(extractFromBundler.flatMap { it.serverJar }) codebookArgs.set(mache.map { it.remapperArgs }) - codebookClasspath.from(project.configurations.named(MACHE_CODEBOOK_CONFIG)) - minecraftClasspath.from(project.configurations.named(MACHE_MINECRAFT_LIBRARIES_CONFIG)) - constants.from(project.configurations.named(MACHE_CONSTANTS_CONFIG)) + codebookClasspath.from(configurations.named(MACHE_CODEBOOK_CONFIG)) + minecraftClasspath.from(configurations.named(MACHE_MINECRAFT_LIBRARIES_CONFIG)) + constants.from(configurations.named(MACHE_CONSTANTS_CONFIG)) outputJar.set(layout.cache.resolve(FINAL_REMAPPED_CODEBOOK_JAR)) } @@ -64,14 +66,15 @@ class CoreTasks( inputJar.set(macheRemapJar.flatMap { it.outputJar }) decompilerArgs.set(mache.map { it.decompilerArgs }) - minecraftClasspath.from(project.configurations.named(MACHE_MINECRAFT_LIBRARIES_CONFIG)) - decompiler.from(project.configurations.named(MACHE_DECOMPILER_CONFIG)) + minecraftClasspath.from(configurations.named(MACHE_MINECRAFT_LIBRARIES_CONFIG)) + decompiler.from(configurations.named(MACHE_DECOMPILER_CONFIG)) outputJar.set(layout.cache.resolve(FINAL_DECOMPILE_JAR)) } val collectPaperATsFromPatches = tasks.register("collectPaperATsFromPatches") { - patchDir.set(project.coreExt.paper.featurePatchDir.fileExists()) + basePatchDir.set(project.coreExt.paper.basePatchDir.fileExists()) + featurePatchDir.set(project.coreExt.paper.featurePatchDir.fileExists()) } val mergePaperATs = tasks.register("mergePaperATs") { @@ -87,14 +90,14 @@ class CoreTasks( } val importLibraryFiles = tasks.register("importPaperLibraryFiles") { - patches.from(project.coreExt.paper.sourcePatchDir, project.coreExt.paper.featurePatchDir) + patches.from(project.coreExt.paper.basePatchDir, project.coreExt.paper.sourcePatchDir, project.coreExt.paper.featurePatchDir) devImports.set(project.coreExt.paper.devImports.fileExists()) libraryFileIndex.set(indexLibraryFiles.flatMap { it.outputFile }) libraries.from(indexLibraryFiles.map { it.libraries }) } private fun SetupMinecraftSources.configureSetupMacheSources() { - mache.from(project.configurations.named(MACHE_CONFIG)) + mache.from(configurations.named(MACHE_CONFIG)) oldPaperCommit.convention(project.coreExt.updatingMinecraft.oldPaperCommit) inputFile.set(macheDecompileJar.flatMap { it.outputJar }) predicate.set { Files.isRegularFile(it) && it.toString().endsWith(".java") } @@ -107,8 +110,9 @@ class CoreTasks( outputZip.set(layout.cache.resolve(BASE_PROJECT).resolve("sources.zip")) atFile.set(mergePaperATs.flatMap { it.outputFile }) - ats.jstClasspath.from(project.configurations.named(MACHE_MINECRAFT_LIBRARIES_CONFIG)) - ats.jst.from(project.configurations.named(JST_CONFIG)) + ats.jstClasspath.from(configurations.named(MACHE_MINECRAFT_LIBRARIES_CONFIG)) + ats.jst.from(configurations.named(JST_CONFIG)) + validateATs.set(project.coreExt.validateATs) } val extractMacheSources = tasks.register("extractMacheSources") { @@ -182,6 +186,7 @@ class CoreTasks( true, this, hasFork, + project.coreExt.paper.basePatchDir, project.coreExt.paper.sourcePatchDir, project.coreExt.paper.rejectsDir, project.coreExt.paper.resourcePatchDir, @@ -218,6 +223,7 @@ class CoreTasks( false, this, !activeFork, + cfg.basePatchDir, cfg.sourcePatchDir, cfg.rejectsDir, cfg.resourcePatchDir, @@ -247,6 +253,7 @@ class CoreTasks( } else { "upstream server patching" }, + project.coreExt.validateATs, project.coreExt.gitFilePatches, project.coreExt.filterPatches, null, @@ -264,6 +271,13 @@ class CoreTasks( ) // setup aggregate Minecraft & upstream -server patching tasks + val applyAllServerBasePatches = project.tasks.register("applyAllServerBasePatches") { + group = "patching" + description = "Applies all Minecraft and upstream server base patches " + + "(equivalent to '${serverTasks.applyBasePatches.name} applyServerBasePatches')" + dependsOn(serverTasks.applyBasePatches) + dependsOn("applyServerBasePatches") + } val applyAllServerFilePatches = project.tasks.register("applyAllServerFilePatches") { group = "patching" description = "Applies all Minecraft and upstream server file patches " + @@ -285,6 +299,13 @@ class CoreTasks( dependsOn(serverTasks.applyPatches) dependsOn("applyServerPatches") } + val rebuildAllServerBasePatches = project.tasks.register("rebuildAllServerBasePatches") { + group = "patching" + description = "Rebuilds all Minecraft and upstream server base patches " + + "(equivalent to '${serverTasks.rebuildBasePatchesName} rebuildServerBasePatches')" + dependsOn(serverTasks.rebuildBasePatchesName) + dependsOn("rebuildServerBasePatches") + } val rebuildAllServerFilePatches = project.tasks.register("rebuildAllServerFilePatches") { group = "patching" description = "Rebuilds all Minecraft and upstream server file patches " + diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/DevBundleTasks.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/DevBundleTasks.kt index a17f1d50a..a080493d6 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/DevBundleTasks.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/DevBundleTasks.kt @@ -28,6 +28,7 @@ import io.papermc.paperweight.tasks.* import io.papermc.paperweight.util.* import io.papermc.paperweight.util.constants.* import org.gradle.api.Project +import org.gradle.api.artifacts.ConfigurationContainer import org.gradle.api.artifacts.repositories.MavenArtifactRepository import org.gradle.api.file.RegularFile import org.gradle.api.plugins.JavaPluginExtension @@ -35,15 +36,15 @@ import org.gradle.api.provider.Provider import org.gradle.api.tasks.TaskContainer import org.gradle.kotlin.dsl.* -@Suppress("MemberVisibilityCanBePrivate") class DevBundleTasks( project: Project, private val coreTasks: CoreTasks, + private val configurations: ConfigurationContainer = project.configurations, tasks: TaskContainer = project.tasks, ) { val serverBundlerForDevBundle = tasks.register("serverBundlerForDevBundle") { mainClass.set(project.coreExt.mainClass) - paperclip.from(project.configurations.named(PAPERCLIP_CONFIG)) + paperclip.from(configurations.named(PAPERCLIP_CONFIG)) serverLibrariesList.set(coreTasks.extractFromBundler.flatMap { it.serverLibrariesList }) vanillaBundlerJar.set(coreTasks.downloadServerJar.flatMap { it.outputJar }) } @@ -82,7 +83,7 @@ class DevBundleTasks( } generateDevelopmentBundle { macheUrl.set(project.repositories.named(MACHE_REPO_NAME).map { it.url.toString() }) - macheDep.set(determineArtifactCoordinates(project.configurations.getByName(MACHE_CONFIG)).single()) + macheDep.set(determineArtifactCoordinates(configurations.named(MACHE_CONFIG)).map { it.single() }) } } } 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 123ea5466..8ead8bf62 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 @@ -35,7 +35,6 @@ import org.gradle.api.provider.Provider import org.gradle.api.tasks.TaskContainer import org.gradle.kotlin.dsl.* -@Suppress("MemberVisibilityCanBePrivate") open class InitialTasks( project: Project, tasks: TaskContainer = project.tasks, diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/MinecraftPatchingTasks.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/MinecraftPatchingTasks.kt index 8de9acb5a..8656f398b 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/MinecraftPatchingTasks.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/MinecraftPatchingTasks.kt @@ -25,17 +25,23 @@ package io.papermc.paperweight.core.taskcontainers import io.papermc.paperweight.core.extension.ForkConfig import io.papermc.paperweight.core.tasks.ImportLibraryFiles import io.papermc.paperweight.core.tasks.SetupForkMinecraftSources +import io.papermc.paperweight.core.tasks.patching.ApplyBasePatches import io.papermc.paperweight.core.tasks.patching.ApplyFeaturePatches import io.papermc.paperweight.core.tasks.patching.ApplyFilePatches import io.papermc.paperweight.core.tasks.patching.ApplyFilePatchesFuzzy +import io.papermc.paperweight.core.tasks.patching.CreateBasePatch +import io.papermc.paperweight.core.tasks.patching.FixupBasePatches +import io.papermc.paperweight.core.tasks.patching.FixupFeaturePatches import io.papermc.paperweight.core.tasks.patching.FixupFilePatches import io.papermc.paperweight.core.tasks.patching.RebuildFilePatches +import io.papermc.paperweight.core.util.coreExt import io.papermc.paperweight.tasks.* import io.papermc.paperweight.util.* import io.papermc.paperweight.util.constants.* import java.nio.file.Path import org.gradle.api.Project import org.gradle.api.Task +import org.gradle.api.artifacts.ConfigurationContainer import org.gradle.api.file.Directory import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.RegularFileProperty @@ -49,6 +55,7 @@ class MinecraftPatchingTasks( paper: Boolean, private val coreTasks: CoreTasks, private val readOnly: Boolean, + private val basePatchDir: DirectoryProperty, private val sourcePatchDir: DirectoryProperty, private val rejectsDir: DirectoryProperty, private val resourcePatchDir: DirectoryProperty, @@ -62,6 +69,7 @@ class MinecraftPatchingTasks( private val outputSrc: Path = outputRoot.resolve("src/minecraft/java"), private val outputResources: Path = outputRoot.resolve("src/minecraft/resources"), private val outputSrcFile: Path = outputRoot.resolve("file/src/minecraft/java"), + private val configurations: ConfigurationContainer = project.configurations, private val tasks: TaskContainer = project.tasks ) { private val taskGroup = if (readOnly) "upstream minecraft patching" else "minecraft patching" @@ -70,10 +78,26 @@ class MinecraftPatchingTasks( } private val namePart = if (readOnly) "${configName.capitalized()}Minecraft" else if (paper) "" else "Minecraft" + private val gitMutationLockService = project.gitMutationLockService private fun ApplyFilePatches.configureApplyFilePatches() { group() description = "Applies $configName file patches to the Minecraft sources" + dependsOn(applyBasePatches) + + if (readOnly) { + input.set(applyBasePatches.flatMap { it.output }) + } + output.set(outputSrc) + patches.set(sourcePatchDir.fileExists()) + rejectsDir.set(this@MinecraftPatchingTasks.rejectsDir) + gitFilePatches.set(this@MinecraftPatchingTasks.gitFilePatches) + identifier = configName + } + + private fun ApplyBasePatches.configureApplyBasePatches() { + group() + description = "Applies $configName base patches to the Minecraft sources" input.set(baseSources) if (readOnly) { @@ -81,12 +105,14 @@ class MinecraftPatchingTasks( } else { output.set(outputSrc) } - patches.set(sourcePatchDir.fileExists()) - rejectsDir.set(this@MinecraftPatchingTasks.rejectsDir) - gitFilePatches.set(this@MinecraftPatchingTasks.gitFilePatches) + patches.set(basePatchDir.fileExists()) identifier = configName } + val applyBasePatches = tasks.register("apply${namePart}BasePatches") { + configureApplyBasePatches() + } + val applySourcePatches = tasks.register("apply${namePart}SourcePatches") { configureApplyFilePatches() } @@ -104,6 +130,7 @@ class MinecraftPatchingTasks( patches.set(resourcePatchDir.fileExists()) // TODO rejects? gitFilePatches.set(this@MinecraftPatchingTasks.gitFilePatches) + baseRef.set("main") identifier = configName } @@ -128,9 +155,10 @@ class MinecraftPatchingTasks( val applyPatches = tasks.register("apply${namePart}Patches") { group() description = "Applies all $configName Minecraft patches" - dependsOn(applyFilePatches, applyFeaturePatches) + dependsOn(applyBasePatches, applyFilePatches, applyFeaturePatches) } + val rebuildBasePatchesName = "rebuild${namePart}BasePatches" val rebuildSourcePatchesName = "rebuild${namePart}SourcePatches" val rebuildResourcePatchesName = "rebuild${namePart}ResourcePatches" val rebuildFilePatchesName = "rebuild${namePart}FilePatches" @@ -145,7 +173,8 @@ class MinecraftPatchingTasks( fun setupFork(config: ForkConfig) { val collectAccessTransform = tasks.register("collect${configName.capitalized()}ATsFromPatches") { - patchDir.set(featurePatchDir.fileExists()) + basePatchDir.set(this@MinecraftPatchingTasks.basePatchDir.fileExists()) + featurePatchDir.set(this@MinecraftPatchingTasks.featurePatchDir.fileExists()) } val mergeCollectedAts = tasks.register("merge${configName.capitalized()}ATs") { @@ -154,7 +183,8 @@ class MinecraftPatchingTasks( } val importLibFiles = tasks.register("import${configName.capitalized()}LibraryFiles") { - patches.from(config.featurePatchDir, config.sourcePatchDir) + patches.from(config.featurePatchDir, config.sourcePatchDir, config.basePatchDir) + atFile.set(mergeCollectedAts.flatMap { it.outputFile }) devImports.set(config.devImports.fileExists()) libraryFileIndex.set(coreTasks.indexLibraryFiles.flatMap { it.outputFile }) libraries.from(coreTasks.indexLibraryFiles.map { it.libraries }) @@ -167,28 +197,26 @@ class MinecraftPatchingTasks( outputDir.set(layout.cache.resolve(paperTaskOutput())) identifier.set(configName) + if (namePart == "Minecraft") { // only configure this when we're the target fork + oldCommit.convention(project.coreExt.updatingMinecraft.oldForkCommit) + oldOutputDir.set(layout.cache.resolve("$PAPER_PATH/old${configName.capitalized()}")) + } + libraryImports.set(importLibFiles.flatMap { it.outputDir }) atFile.set(mergeCollectedAts.flatMap { it.outputFile }) - ats.jst.from(project.configurations.named(JST_CONFIG)) - ats.jstClasspath.from(project.configurations.named(MACHE_MINECRAFT_LIBRARIES_CONFIG)) + ats.jst.from(configurations.named(JST_CONFIG)) + ats.jstClasspath.from(configurations.named(JST_CLASSPATH_CONFIG)) + validateATs.set(project.coreExt.validateATs) } - applySourcePatches.configure { + applyBasePatches.configure { input.set(setup.flatMap { it.outputDir }) } - applySourcePatchesFuzzy.configure { - input.set(setup.flatMap { it.outputDir }) - } - val name = "rebuild${namePart}SourcePatches" - if (name in tasks.names) { - tasks.named(name) { - base.set(setup.flatMap { it.outputDir }) - } - } } private fun setupWritable() { listOf( + applyBasePatches, applySourcePatches, applySourcePatchesFuzzy, applyFeaturePatches, @@ -199,29 +227,45 @@ class MinecraftPatchingTasks( } } + val rebuildBasePatches = tasks.register(rebuildBasePatchesName) { + group() + description = "Rebuilds $configName base patches to the Minecraft source" + usesService(gitMutationLockService) + + inputDir.set(outputSrc) + patchDir.set(basePatchDir) + baseRef.set("base") + stopRef.set("basepatches~1") // ~1 cuz we dont want to rebuild the marker commit + filterPatches.set(this@MinecraftPatchingTasks.filterPatches) + identifier = configName + } + val rebuildSourcePatches = tasks.register(rebuildSourcePatchesName) { group() description = "Rebuilds $configName file patches to the Minecraft sources" + usesService(gitMutationLockService) + dependsOn(rebuildBasePatches) - base.set(baseSources) input.set(outputSrc) patches.set(sourcePatchDir) gitFilePatches.set(this@MinecraftPatchingTasks.gitFilePatches) - ats.jstClasspath.from(project.configurations.named(MACHE_MINECRAFT_CONFIG)) - ats.jst.from(project.configurations.named(JST_CONFIG)) + ats.jstClasspath.from(configurations.named(MACHE_MINECRAFT_CONFIG)) + ats.jst.from(configurations.named(JST_CONFIG)) atFile.set(additionalAts.fileExists()) atFileOut.set(additionalAts.fileExists()) + identifier = configName } val rebuildResourcePatches = tasks.register(rebuildResourcePatchesName) { group() description = "Rebuilds $configName file patches to the Minecraft resources" + usesService(gitMutationLockService) - base.set(baseResources) input.set(outputResources) patches.set(resourcePatchDir) gitFilePatches.set(this@MinecraftPatchingTasks.gitFilePatches) + identifier = configName } val rebuildFilePatches = tasks.register(rebuildFilePatchesName) { @@ -233,6 +277,7 @@ class MinecraftPatchingTasks( val rebuildFeaturePatches = tasks.register(rebuildFeaturePatchesName) { group() description = "Rebuilds all $configName feature patches to the Minecraft sources" + usesService(gitMutationLockService) dependsOn(rebuildFilePatches) inputDir.set(outputSrc) @@ -244,7 +289,25 @@ class MinecraftPatchingTasks( val rebuildPatches = tasks.register(rebuildPatchesName) { group() description = "Rebuilds all $configName patches to Minecraft" - dependsOn(rebuildFilePatches, rebuildFeaturePatches) + dependsOn(rebuildBasePatches, rebuildFilePatches, rebuildFeaturePatches) + } + + val createBasePatch = tasks.register("create${namePart}BasePatch") { + group() + description = "Puts the latest changes under the $configName Minecraft sources base patches commit" + + repo.set(outputSrc) + identifier = configName + } + + val fixupBasePatches = tasks.register("fixup${namePart}BasePatches") { + group() + description = "Puts the currently tracked source changes into the specified $configName Minecraft base patch commit" + + repo.set(outputSrc) + patches.set(basePatchDir) + upstream.set("upstream/main") + identifier = configName } val fixupSourcePatches = tasks.register("fixup${namePart}SourcePatches") { @@ -252,7 +315,7 @@ class MinecraftPatchingTasks( description = "Puts the currently tracked source changes into the $configName Minecraft sources file patches commit" repo.set(outputSrc) - upstream.set("upstream/main") + upstream.set("basepatches") } val fixupResourcePatches = tasks.register("fixup${namePart}ResourcePatches") { @@ -263,6 +326,15 @@ class MinecraftPatchingTasks( upstream.set("upstream/main") } + val fixupFeaturePatches = tasks.register("fixup${namePart}FeaturePatches") { + group() + description = "Puts the currently tracked source changes into the specified $configName Minecraft feature patch commit" + + repo.set(outputSrc) + upstream.set("file") + patches.set(featurePatchDir) + } + val applyOrMoveSourcePatches = tasks.register("applyOrMove${namePart}SourcePatches") { configureApplyFilePatches() description = "Applies $configName file patches to the Minecraft sources as Git patches, moving any failed patches to the rejects dir. " + diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/PatchingTasks.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/PatchingTasks.kt index d9cf03739..7bc6f5ba5 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/PatchingTasks.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/PatchingTasks.kt @@ -22,22 +22,33 @@ package io.papermc.paperweight.core.taskcontainers +import io.papermc.paperweight.core.tasks.SetupForkUpstreamSources +import io.papermc.paperweight.core.tasks.patching.ApplyBasePatches import io.papermc.paperweight.core.tasks.patching.ApplyFeaturePatches import io.papermc.paperweight.core.tasks.patching.ApplyFilePatches import io.papermc.paperweight.core.tasks.patching.ApplyFilePatchesFuzzy +import io.papermc.paperweight.core.tasks.patching.CreateBasePatch +import io.papermc.paperweight.core.tasks.patching.FixupBasePatches +import io.papermc.paperweight.core.tasks.patching.FixupFeaturePatches import io.papermc.paperweight.core.tasks.patching.FixupFilePatches import io.papermc.paperweight.core.tasks.patching.RebuildFilePatches import io.papermc.paperweight.tasks.* import io.papermc.paperweight.util.* +import io.papermc.paperweight.util.constants.JST_CLASSPATH_CONFIG +import io.papermc.paperweight.util.constants.JST_CONFIG import io.papermc.paperweight.util.constants.paperTaskOutput +import io.papermc.paperweight.util.set import java.nio.file.Path import org.gradle.api.Project import org.gradle.api.Task +import org.gradle.api.artifacts.ConfigurationContainer import org.gradle.api.file.Directory import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.Provider import org.gradle.api.tasks.TaskContainer import org.gradle.kotlin.dsl.* +import org.gradle.kotlin.dsl.register class PatchingTasks( private val project: Project, @@ -45,20 +56,40 @@ class PatchingTasks( private val patchSetName: String, private val taskGroup: String, private val readOnly: Boolean, + private val validateAts: Provider, + private val basePatchDir: DirectoryProperty, private val filePatchDir: DirectoryProperty, private val rejectsDir: DirectoryProperty, private val featurePatchDir: DirectoryProperty, + private val additionalAts: RegularFileProperty, private val baseDir: Provider, private val gitFilePatches: Provider, private val filterPatches: Provider, private val outputDir: Path, + private val configurations: ConfigurationContainer = project.configurations, private val tasks: TaskContainer = project.tasks, ) { private val namePart: String = if (readOnly) "${forkName.capitalized()}${patchSetName.capitalized()}" else patchSetName.capitalized() + private val gitMutationLockService = project.gitMutationLockService private fun ApplyFilePatches.configureApplyFilePatches() { group = taskGroup description = "Applies $patchSetName file patches" + dependsOn(applyBasePatches) + + if (readOnly) { + input.set(applyBasePatches.flatMap { it.output }) + } + output.set(outputDir) + patches.set(filePatchDir.fileExists()) + rejectsDir.set(this@PatchingTasks.rejectsDir) + gitFilePatches.set(this@PatchingTasks.gitFilePatches) + identifier = "$forkName $patchSetName" + } + + private fun ApplyBasePatches.configureApplyBasePatches() { + group = taskGroup + description = "Applies $patchSetName base patches" input.set(baseDir) if (readOnly) { @@ -66,13 +97,15 @@ class PatchingTasks( } else { output.set(outputDir) } - patches.set(filePatchDir.fileExists()) - rejectsDir.set(this@PatchingTasks.rejectsDir) - gitFilePatches.set(this@PatchingTasks.gitFilePatches) + patches.set(basePatchDir.fileExists()) baseRef.set("base") identifier = "$forkName $patchSetName" } + val applyBasePatches = tasks.register("apply${namePart}BasePatches") { + configureApplyBasePatches() + } + val applyFilePatches = tasks.register("apply${namePart}FilePatches") { configureApplyFilePatches() } @@ -96,11 +129,15 @@ class PatchingTasks( val applyPatches = tasks.register("apply${namePart}Patches") { group = taskGroup description = "Applies all $patchSetName patches" - dependsOn(applyFilePatches, applyFeaturePatches) + dependsOn(applyBasePatches, applyFilePatches, applyFeaturePatches) } + val rebuildBasePatchesName = "rebuild${namePart}BasePatches" val rebuildFilePatchesName = "rebuild${namePart}FilePatches" + val createBasePatchName = "create${namePart}BasePatch" + val fixupBasePatchesName = "fixup${namePart}BasePatches" val fixupFilePatchesName = "fixup${namePart}FilePatches" + val fixupFeaturePatchesName = "fixup${namePart}FeaturePatches" val rebuildFeaturePatchesName = "rebuild${namePart}FeaturePatches" val rebuildPatchesName = "rebuild${namePart}Patches" @@ -110,8 +147,38 @@ class PatchingTasks( } } + fun setupUpstream() { + val collectAccessTransform = tasks.register("collect${namePart}ATsFromPatches") { + basePatchDir.set(this@PatchingTasks.basePatchDir.fileExists()) + featurePatchDir.set(this@PatchingTasks.featurePatchDir.fileExists()) + } + + val mergeCollectedAts = tasks.register("merge${namePart}ATs") { + firstFile.set(additionalAts.fileExists()) + secondFile.set(collectAccessTransform.flatMap { it.outputFile }) + } + + val setup = tasks.register("run${namePart}Setup") { + description = "Applies $forkName ATs to $namePart sources" + + inputDir.set(baseDir) + outputDir.set(layout.cache.resolve(paperTaskOutput())) + identifier.set(namePart) + + atFile.set(mergeCollectedAts.flatMap { it.outputFile }) + ats.jst.from(configurations.named(JST_CONFIG)) + ats.jstClasspath.from(configurations.named(JST_CLASSPATH_CONFIG)) + validateAts.set(this@PatchingTasks.validateAts) + } + + applyBasePatches.configure { + input.set(setup.flatMap { it.outputDir }) + } + } + private fun setupWritable() { listOf( + applyBasePatches, applyFilePatches, applyFilePatchesFuzzy, applyFeaturePatches, @@ -121,14 +188,51 @@ class PatchingTasks( } } + val rebuildBasePatches = tasks.register(rebuildBasePatchesName) { + group = taskGroup + description = "Rebuilds $patchSetName base patches" + usesService(gitMutationLockService) + + inputDir.set(outputDir) + patchDir.set(basePatchDir) + baseRef.set("base") + stopRef.set("basepatches~1") // ~1 cuz we dont want to rebuild the marker commit + filterPatches.set(this@PatchingTasks.filterPatches) + identifier = "$forkName $patchSetName" + } val rebuildFilePatches = tasks.register(rebuildFilePatchesName) { group = taskGroup description = "Rebuilds $patchSetName file patches" + usesService(gitMutationLockService) + dependsOn(rebuildBasePatches) - base.set(baseDir) input.set(outputDir) patches.set(filePatchDir) gitFilePatches.set(this@PatchingTasks.gitFilePatches) + + ats.jstClasspath.from(configurations.named(JST_CLASSPATH_CONFIG)) + ats.jst.from(configurations.named(JST_CONFIG)) + atFile.set(additionalAts.fileExists()) + atFileOut.set(additionalAts.fileExists()) + identifier = "$forkName $patchSetName" + } + + val createBasePatch = tasks.register(createBasePatchName) { + group = taskGroup + description = "Puts the latest changes under the $patchSetName base patches commit" + + repo.set(outputDir) + identifier = "$forkName $patchSetName" + } + + val fixupBasePatches = tasks.register(fixupBasePatchesName) { + group = taskGroup + description = "Puts the currently tracked source changes into the specified $patchSetName base patch commit" + + repo.set(outputDir) + patches.set(basePatchDir) + upstream.set("base") + identifier = "$forkName $patchSetName" } val fixupFilePatches = tasks.register(fixupFilePatchesName) { @@ -136,12 +240,22 @@ class PatchingTasks( description = "Puts the currently tracked source changes into the $patchSetName file patches commit" repo.set(outputDir) - upstream.set("base") + upstream.set("basepatches") + } + + val fixupFeaturePatches = tasks.register(fixupFeaturePatchesName) { + group = taskGroup + description = "Puts the currently tracked source changes into the specified $patchSetName feature patch commit" + + repo.set(outputDir) + upstream.set("file") + patches.set(featurePatchDir) } val rebuildFeaturePatches = tasks.register(rebuildFeaturePatchesName) { group = taskGroup description = "Rebuilds $patchSetName feature patches" + usesService(gitMutationLockService) dependsOn(rebuildFilePatches) inputDir.set(outputDir) @@ -153,7 +267,7 @@ class PatchingTasks( val rebuildPatches = tasks.register(rebuildPatchesName) { group = taskGroup description = "Rebuilds all $patchSetName patches" - dependsOn(rebuildFilePatches, rebuildFeaturePatches) + dependsOn(rebuildBasePatches, rebuildFilePatches, rebuildFeaturePatches) } val applyOrMoveFilePatches = tasks.register("applyOrMove${namePart}FilePatches") { diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/UpstreamConfigTasks.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/UpstreamConfigTasks.kt index 70676a12f..5cb228181 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/UpstreamConfigTasks.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/taskcontainers/UpstreamConfigTasks.kt @@ -22,14 +22,13 @@ package io.papermc.paperweight.core.taskcontainers -import codechicken.diffpatch.util.PatchMode +import io.codechicken.diffpatch.util.PatchMode import io.papermc.paperweight.core.extension.UpstreamConfig import io.papermc.paperweight.core.tasks.FilterRepo import io.papermc.paperweight.core.tasks.RunNestedBuild import io.papermc.paperweight.core.tasks.patching.ApplySingleFilePatches import io.papermc.paperweight.core.tasks.patching.RebuildSingleFilePatches import io.papermc.paperweight.util.* -import kotlin.io.path.* import org.gradle.api.Project import org.gradle.api.file.Directory import org.gradle.api.provider.Provider @@ -43,6 +42,7 @@ class UpstreamConfigTasks( private val upstreamDir: Provider, private val readOnly: Boolean, private val taskGroup: String, + private val validateATs: Provider, private val gitFilePatches: Provider, private val filterPatches: Provider, private val setupUpstream: TaskProvider?, @@ -118,20 +118,25 @@ class UpstreamConfigTasks( createBaseFromDirectoryInRepo(cfg) } - return PatchingTasks( + val tasks = PatchingTasks( target, forkName, cfg.name, taskGroup, readOnly, + validateATs, + cfg.basePatchDir, cfg.filePatchDir, cfg.rejectsDir, cfg.featurePatchDir, + cfg.additionalAts, base, gitFilePatches, filterPatches, cfg.outputDir.path, ) + tasks.setupUpstream() + return tasks } private fun createBaseFromRepo(cfg: UpstreamConfig.RepoPatchSet): Provider { @@ -166,6 +171,13 @@ class UpstreamConfigTasks( } fun setupAggregateTasks(namePart: String, desc: String, descSingleFile: String = desc) { + val applyBase = target.tasks.register("apply${namePart}BasePatches") { + group = taskGroup + description = "Applies $desc base patches" + patchingTasks.values.forEach { t -> + dependsOn(t.applyBasePatches) + } + } val applyFile = target.tasks.register("apply${namePart}FilePatches") { group = taskGroup description = "Applies $desc file patches" @@ -180,6 +192,13 @@ class UpstreamConfigTasks( dependsOn(t.applyFeaturePatches) } } + val rebuildBase = target.tasks.register("rebuild${namePart}BasePatches") { + group = taskGroup + description = "Rebuilds $desc base patches" + patchingTasks.values.forEach { t -> + dependsOn(t.rebuildBasePatchesName) + } + } val rebuildFile = target.tasks.register("rebuild${namePart}FilePatches") { group = taskGroup description = "Rebuilds $desc file patches" diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/GeneratePatches.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/GeneratePatches.kt new file mode 100644 index 000000000..cd7d84825 --- /dev/null +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/GeneratePatches.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.core.tasks + +import io.papermc.paperweight.tasks.BaseTask +import io.papermc.paperweight.util.* +import io.papermc.paperweight.util.constants.paperTaskOutput +import java.nio.file.Path +import kotlin.io.path.* +import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.* +import org.gradle.kotlin.dsl.support.uppercaseFirstChar + +@UntrackedTask(because = "GeneratePatches should always run when requested.") +abstract class GeneratePatches : BaseTask() { + @get:Input + abstract val forkName: Property + + @get:Input + abstract val forkUrl: Property + + @get:Input + abstract val commitHash: Property + + @get:Input + abstract val inputFrom: Property + + @get:InputFiles + @get:PathSensitive(PathSensitivity.NONE) + abstract val preparedSource: ConfigurableFileCollection + + @get:Input + @get:Optional + abstract val patchesDirOutput: Property + + @get:OutputDirectory + abstract val serverProjectDir: DirectoryProperty + + @get:OutputDirectory + abstract val apiProjectDir: DirectoryProperty + + @get:OutputDirectory + abstract val outputDir: DirectoryProperty + + @get:Internal + abstract val tempOutput: DirectoryProperty + + override fun init() { + tempOutput.set(layout.cache.resolve(paperTaskOutput())) + } + + @TaskAction + fun run() { + val forkName = forkName.get() + val commit = commitHash.get() + val url = forkUrl.get() + val repoTypes = inputFrom.get().split(",") + val inputDirs = preparedSource.files.map { it.toPath() } + + val outputToPatchesDirectory = patchesDirOutput.getOrElse(true) + val outputDir = outputDir.get() + val cacheOutput = tempOutput.get().asFile.toPath() + val tempOutput = cacheOutput.cleanFile() + val outputDirPath = outputDir.asFile.toPath() + + for (inputDir in inputDirs) { + inputDir.copyRecursivelyTo(tempOutput) + for (repoType in repoTypes) { + val repository = tempOutput.resolve(repoType) + if (!repository.exists()) continue + val dirName = repository.fileName.toString() + val repoName = capitalizedName(dirName, dirName.isApi()) + val cutRepo = dirName.substringBefore("-") + val git = Git(repository) + git("reset", "base", "--soft").runSilently(silenceErr = true) + if (git("status", "--porcelain").getText().trim().isBlank()) continue + git("add", ".").runSilently(silenceErr = true) + git.commit(forkName, repoName, url, commit) + git( + "format-patch", + "--diff-algorithm=myers", "--zero-commit", "--full-index", "--no-signature", "--no-stat", "-N", + "HEAD~1..HEAD", "-o", + outputPath(outputToPatchesDirectory, dirName.isApi(), outputDirPath, cutRepo) + ).runSilently(silenceErr = true) + } + } + } + private fun Git.commit(name: String, repoName: String, url: String, commit: String) { + this( + "commit", + "-m", + "${name.capitalized()} $repoName Patches", + "-m", + "Patch generated from ${commitLink(url, commit)}", + "--author=Generated " + ).runSilently(silenceErr = true) + } + private fun capitalizedName(name: String, api: Boolean): String { + val trimmed = name.split("-").joinToString("") { it.uppercaseFirstChar() } + return when { + api -> trimmed.replace("Api", "API") + else -> trimmed + } + } + private fun String.isApi() = contains("-api") + private fun commitLink(url: String, hash: String): String { + val cleanUrl = url.removeSuffix(".git") + return "$cleanUrl/commit/$hash" + } + private fun outputPath(patchDir: Boolean, api: Boolean, outputDir: Path, repoName: String): String { + val serverOutput = serverProjectDir.get().asFile.toPath() + val apiOutput = apiProjectDir.get().asFile.toPath() + return when { + patchDir && api -> apiOutput.resolve("$repoName-patches/base").absolutePathString() + patchDir && repoName == "minecraft" -> serverOutput.resolve("$repoName-patches/base").absolutePathString() + patchDir -> serverOutput.resolve("$repoName-patches/base").absolutePathString() + else -> outputDir.absolutePathString() + } + } +} diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/GenerateSources.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/GenerateSources.kt new file mode 100644 index 000000000..9b47deaa3 --- /dev/null +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/GenerateSources.kt @@ -0,0 +1,204 @@ +/* + * 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.tasks + +import io.papermc.paperweight.core.util.ApplySourceATs +import io.papermc.paperweight.tasks.JavaLauncherTask +import io.papermc.paperweight.util.* +import io.papermc.paperweight.util.constants.paperTaskOutput +import java.nio.file.Path +import kotlin.io.path.* +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.kotlin.dsl.newInstance + +@UntrackedTask(because = "GenerateSources should always run when requested.") +abstract class GenerateSources : JavaLauncherTask() { + @get:Input + abstract val forkName: Property + + @get:Input + abstract val forkUrl: Property + + @get:Input + abstract val commitHash: Property + + @get:Input + abstract val inputFrom: Property + + @get:InputDirectory + @get:PathSensitive(PathSensitivity.NONE) + abstract val workDir: DirectoryProperty + + @get:Internal + abstract val tempOutput: DirectoryProperty + + @get:Nested + val ats: ApplySourceATs = objects.newInstance() + + @get:InputFile + @get:Optional + @get:PathSensitive(PathSensitivity.NONE) + abstract val atFile: RegularFileProperty + + @get:Input + abstract val validateATs: Property + + @get:InputFile + @get:Optional + @get:PathSensitive(PathSensitivity.NONE) + abstract val additionalPatch: RegularFileProperty + + @get:Input + abstract val generateSources: Property + + @get:Input + abstract val generateResources: Property + + @get:Input + abstract val generateTestSources: Property + + @get:Input + abstract val generateTestResources: Property + + @get:OutputDirectory + abstract val sourceOutput: DirectoryProperty + + @get:OutputDirectory + abstract val resourceOutput: DirectoryProperty + + @get:OutputDirectory + abstract val testSourceOutput: DirectoryProperty + + @get:OutputDirectory + abstract val testResourceOutput: DirectoryProperty + + override fun init() { + super.init() + tempOutput.set(layout.cache.resolve(paperTaskOutput())) + } + + @TaskAction + fun run() { + val commit = commitHash.get() + val url = forkUrl.get() + val generatedOutput = sourceOutput.get().asFile.toPath() + val generatedResourcesOutput = resourceOutput.get().asFile.toPath() + val generatedTestOutput = testSourceOutput.get().asFile.toPath() + val generatedTestResourcesOutput = testResourceOutput.get().asFile.toPath() + + val cacheOutput = tempOutput.get().asFile.toPath() + val tempOutput = cacheOutput.cleanFile() + + val outputName = inputFrom.get().substringBefore("-") + val workDirectory = workDir.get().asFile.toPath() + + val sourceDir = workDirectory.resolve("$outputName/${inputFrom.get()}/src") + if (!sourceDir.exists()) return + val srcDirs = sourceDir.listDirectoryEntries().filter { it.isDirectory() } + if (srcDirs.size == 1 && srcDirs.first().name == "minecraft") return + sourceDir.copyRecursivelyTo(tempOutput) + + val atDirPath = tempOutput.resolve("main/java") + val patchDir = tempOutput + + if (additionalPatch.isPresent) { + val git = Git(patchDir) + git("am", "--3way", "--ignore-whitespace", additionalPatch.path.toString()).runSilently() + } + + if (atFile.isPresent && atFile.path.readText().isNotBlank() && atDirPath.exists()) { + ats.run( + launcher.get(), + atDirPath, + atDirPath, + atFile.path, + temporaryDir.toPath(), + validate = validateATs.get(), + ) + } + + val outputs: List = listOfNotNull( + generatedOutput.takeIf { generateSources.get() }, + generatedResourcesOutput.takeIf { generateResources.get() }, + generatedTestOutput.takeIf { generateTestSources.get() }, + generatedTestResourcesOutput.takeIf { generateTestResources.get() } + ) + + for (output in outputs) { + val sourceDir = when (output) { + generatedOutput -> tempOutput.resolve("main/java") + generatedResourcesOutput -> tempOutput.resolve("main/resources") + generatedTestOutput -> tempOutput.resolve("test/java") + generatedTestResourcesOutput -> tempOutput.resolve("test/resources") + else -> continue + } + val packageRegex = Regex("""^\s*package\s+([\w.]+)\s*;""", RegexOption.MULTILINE) + val packagesToRemove = mutableSetOf() + val packages = mutableSetOf() + + sourceDir.filesMatchingRecursive("*.java").forEach { + val content = it.readText() + val pkg = packageRegex.find(content)?.groups?.get(1)?.value + if (pkg != null) packages += pkg + } + + output.filesMatchingRecursive("package-info.java").forEach { + val content = it.readText() + val pkg = packageRegex.find(content)?.groups?.get(1)?.value + if (pkg != null) { + if (content.contains(" * @apiNote Generated from ${forkName.get()}")) { + packagesToRemove += pkg + } + } + } + packagesToRemove.forEach { pkg -> + val dir = output.resolve(pkg.replace('.', '/')) + dir.cleanDir() + } + packages.forEach { pkg -> + val srcDir = sourceDir.resolve(pkg.replace('.', '/')) + val dir = output.resolve(pkg.replace('.', '/')) + if (srcDir.exists() && srcDir.listDirectoryEntries().isNotEmpty()) { + srcDir.copyRecursivelyTo(dir) + val packageInfo = dir.resolve("package-info.java") + val javadoc = buildString { + appendLine("/**") + appendLine(" * @apiNote Generated from ${forkName.get()}") + appendLine(" */") + appendLine("package $pkg;") + } + packageInfo.writeText(javadoc) + } + } + } + } + + private fun commitLink(url: String, hash: String): String { + val cleanUrl = url.removeSuffix(".git") + if (cleanUrl.contains("github.com")) return "$cleanUrl/tree/$hash" + return "$cleanUrl/commit/$hash" + } +} diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/ImportLibraryFiles.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/ImportLibraryFiles.kt index 00dc5d9e5..e7b2895fa 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/ImportLibraryFiles.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/ImportLibraryFiles.kt @@ -118,6 +118,11 @@ abstract class ImportLibraryFiles : BaseTask() { @get:PathSensitive(PathSensitivity.RELATIVE) abstract val patches: ConfigurableFileCollection + @get:Optional + @get:InputFile + @get:PathSensitive(PathSensitivity.NONE) + abstract val atFile: RegularFileProperty + @get:Optional @get:InputFile @get:PathSensitive(PathSensitivity.NONE) @@ -143,6 +148,7 @@ abstract class ImportLibraryFiles : BaseTask() { ioDispatcher("ImportLibraryFiles").use { dispatcher -> importLibraryFiles( patchFiles, + atFile.pathOrNull, devImports.pathOrNull, outputDir.path, libraries.sourcesJars(), @@ -156,6 +162,7 @@ abstract class ImportLibraryFiles : BaseTask() { private fun importLibraryFiles( patches: Iterable, + atFile: Path?, importsFile: Path?, targetDir: Path, libFiles: List, @@ -164,7 +171,7 @@ abstract class ImportLibraryFiles : BaseTask() { dispatcher: CoroutineDispatcher, ) = runBlocking { // Import library classes - val allImports = findLibraryImports(importsFile, libFiles, index, patches, dispatcher) + val allImports = findLibraryImports(importsFile, libFiles, index, patches, atFile, dispatcher) val importsByLib = allImports.groupBy { it.libraryFileName } logger.log(if (printOutput) LogLevel.LIFECYCLE else LogLevel.DEBUG, "Importing {} classes from library sources...", allImports.size) @@ -203,6 +210,7 @@ abstract class ImportLibraryFiles : BaseTask() { libFiles: List, index: Set, patchFiles: Iterable, + atFile: Path?, dispatcher: CoroutineDispatcher, ): Set { val result = hashSetOf() @@ -219,14 +227,15 @@ abstract class ImportLibraryFiles : BaseTask() { } } - // Scan patches for necessary imports - result += findNeededLibraryImports(patchFiles, index, dispatcher) + // Scan patches and the AT file for necessary imports + result += findNeededLibraryImports(patchFiles, atFile, index, dispatcher) return result } private suspend fun findNeededLibraryImports( patchFiles: Iterable, + atFile: Path?, index: Set, dispatcher: CoroutineDispatcher, ): Set { @@ -243,6 +252,20 @@ abstract class ImportLibraryFiles : BaseTask() { needed += value } } + + atFile?.useLines { lines -> + lines.filterNot { it.startsWith("#") } + .forEach { line -> + val parts = line.split(' ') + if (parts.size < 2) return@forEach + val className = parts[1] + val key = className.replace('.', '/').substringBefore('$') + ".java" + val value = knownImportMap[key] + if (value != null) { + needed += value + } + } + } return needed } } diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/PrepareForPatchGeneration.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/PrepareForPatchGeneration.kt new file mode 100644 index 000000000..78391241c --- /dev/null +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/PrepareForPatchGeneration.kt @@ -0,0 +1,104 @@ +/* + * 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.tasks + +import io.papermc.paperweight.core.util.ApplySourceATs +import io.papermc.paperweight.tasks.JavaLauncherTask +import io.papermc.paperweight.util.* +import io.papermc.paperweight.util.cache +import io.papermc.paperweight.util.constants.paperTaskOutput +import kotlin.io.path.* +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.kotlin.dsl.newInstance + +@UntrackedTask(because = "PrepareForPatchGeneration doesn't have stable inputs.") +abstract class PrepareForPatchGeneration : JavaLauncherTask() { + + @get:Input + abstract val forkName: Property + + @get:Input + abstract val repoName: Property + + @get:InputDirectory + @get:PathSensitive(PathSensitivity.NONE) + abstract val workDir: DirectoryProperty + + @get:Nested + val ats: ApplySourceATs = objects.newInstance() + + @get:InputFile + @get:Optional + @get:PathSensitive(PathSensitivity.NONE) + abstract val atFile: RegularFileProperty + + @get:Input + abstract val validateATs: Property + + @get:InputFile + @get:Optional + @get:PathSensitive(PathSensitivity.NONE) + abstract val additionalPatch: RegularFileProperty + + @get:OutputDirectory + abstract val outputDir: DirectoryProperty + + override fun init() { + super.init() + outputDir.set(layout.cache.resolve(paperTaskOutput())) + } + + @TaskAction + fun run() { + val outputName = forkName.get() + val workDirectory = workDir.get().asFile.toPath() + + val sourceDir = if (repoName.get() == "minecraft") { + workDirectory.resolve("$outputName/$outputName-server/src/minecraft/java") + } else { + workDirectory.resolve("$outputName/${repoName.get()}") + } + val outputDir = outputDir.get().asFile.toPath().resolve(repoName.get()) + val outputDirPath = outputDir.cleanDir() + sourceDir.copyRecursivelyTo(outputDirPath) + + if (additionalPatch.isPresent) { + val git = Git(outputDirPath) + git("am", "--3way", "--ignore-whitespace", additionalPatch.path.toString()).runSilently() + } + + if (atFile.isPresent && atFile.path.readText().isNotBlank()) { + ats.run( + launcher.get(), + outputDirPath, + outputDirPath, + atFile.path, + temporaryDir.toPath(), + validate = validateATs.get(), + ) + } + } +} diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/SetupForkMinecraftSources.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/SetupForkMinecraftSources.kt index 3913a9141..d0cd19123 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/SetupForkMinecraftSources.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/SetupForkMinecraftSources.kt @@ -22,12 +22,17 @@ package io.papermc.paperweight.core.tasks +import io.papermc.paperweight.PaperweightException import io.papermc.paperweight.core.util.ApplySourceATs +import io.papermc.paperweight.core.util.coreExt import io.papermc.paperweight.tasks.* import io.papermc.paperweight.util.* import io.papermc.paperweight.util.constants.paperTaskOutput +import java.util.concurrent.TimeUnit import kotlin.io.path.* import org.eclipse.jgit.api.Git +import org.eclipse.jgit.api.ResetCommand +import org.eclipse.jgit.transport.URIish import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.RegularFileProperty import org.gradle.api.provider.Property @@ -54,6 +59,10 @@ abstract class SetupForkMinecraftSources : JavaLauncherTask() { @get:OutputDirectory abstract val outputDir: DirectoryProperty + @get:OutputDirectory + @get:Optional + abstract val oldOutputDir: DirectoryProperty + @get:Internal abstract val atWorkingDir: DirectoryProperty @@ -65,6 +74,9 @@ abstract class SetupForkMinecraftSources : JavaLauncherTask() { @get:PathSensitive(PathSensitivity.NONE) abstract val atFile: RegularFileProperty + @get:Input + abstract val validateATs: Property + @get:Optional @get:InputDirectory @get:PathSensitive(PathSensitivity.RELATIVE) @@ -73,9 +85,17 @@ abstract class SetupForkMinecraftSources : JavaLauncherTask() { @get:Input abstract val identifier: Property + @get:Internal + abstract val forkName: Property + + @get:Input + @get:Optional + abstract val oldCommit: Property + override fun init() { super.init() atWorkingDir.set(layout.cache.resolve(paperTaskOutput(name = "${name}_atWorkingDir"))) + forkName.convention(project.coreExt.activeFork.map { it.name.capitalized() }) } @TaskAction @@ -85,16 +105,8 @@ abstract class SetupForkMinecraftSources : JavaLauncherTask() { val git = Git.open(outputDir.path.toFile()) - if (atFile.isPresent && atFile.path.readText().isNotBlank()) { - println("Applying access transformers...") - ats.run( - launcher.get(), - inputDir.path, - outputDir.path, - atFile.path, - atWorkingDir.path, - ) - commitAndTag(git, "ATs", "${identifier.get()} ATs") + if (oldCommit.isPresent) { + setupOld() } if (libraryImports.isPresent) { @@ -105,10 +117,100 @@ abstract class SetupForkMinecraftSources : JavaLauncherTask() { it.copyTo(outFile.createParentDirectories()) } } - commitAndTag(git, "Imports", "${identifier.get()} Imports") } + if (atFile.isPresent && atFile.path.readText().isNotBlank()) { + logger.lifecycle("Applying access transformers...") + ats.run( + launcher.get(), + outputDir.path, + outputDir.path, + atFile.path, + atWorkingDir.path, + validate = validateATs.get(), + ) + commitAndTag(git, "ATs", "${identifier.get()} ATs") + } + git.close() } + + private fun setupOld() { + val name = forkName.get() + logger.lifecycle("Setting up $name commit ${oldCommit.get()} to use as base for 3-way apply...") + + val rootProjectDir = layout.projectDirectory.dir("../").path + val oldDir = oldOutputDir.get().path.resolve(oldCommit.get()) + val oldLog = oldOutputDir.get().path.resolve("${oldCommit.get()}.log") + + val oldGit: Git + if (oldDir.exists()) { + oldGit = Git.open(oldDir.toFile()) + } else { + oldDir.createParentDirectories() + oldGit = Git.init() + .setDirectory(oldDir.toFile()) + .setInitialBranch("main") + .call() + oldGit.remoteRemove().setRemoteName("origin").call() + oldGit.remoteAdd().setName("origin").setUri(URIish(rootProjectDir.absolutePathString())).call() + } + + val upstream = Git.open(rootProjectDir.toFile()) + val upstreamConfig = upstream.repository.config + val upstreamReachableSHA1 = upstreamConfig.getString("uploadpack", null, "allowreachablesha1inwant") + val upstreamConfigContainsUploadPack = upstreamConfig.sections.contains("uploadpack") + try { + // Temporarily allow fetching reachable sha1 refs from the "upstream" repository. + upstreamConfig.setBoolean("uploadpack", null, "allowreachablesha1inwant", true) + upstreamConfig.save() + oldGit.fetch().setDepth(1).setRemote("origin").setRefSpecs(oldCommit.get()).call() + oldGit.reset().setMode(ResetCommand.ResetType.HARD).setRef(oldCommit.get()).call() + } finally { + if (upstreamReachableSHA1 == null) { + if (upstreamConfigContainsUploadPack) { + upstreamConfig.unset("uploadpack", null, "allowreachablesha1inwant") + } else { + upstreamConfig.unsetSection("uploadpack", null) + } + } else { + upstreamConfig.setString("uploadpack", null, "allowreachablesha1inwant", upstreamReachableSHA1) + } + upstreamConfig.save() + upstream.close() + } + + oldGit.close() + + val isWindows = System.getProperty("os.name").lowercase().contains("win") + oldLog.outputStream().use { logOut -> + val args = arrayOf( + "applyAllPatches", + "--console", + "plain", + "--stacktrace", + "-Dpaperweight.debug=true" + ) + val command = if (isWindows) { + listOf("cmd.exe", "/C", "gradlew.bat " + args.joinToString(" ")) + } else { + listOf("./gradlew", *args) + } + val processBuilder = ProcessBuilder(command) + processBuilder.directory(oldDir) + val process = processBuilder.start() + + val outFuture = redirect(process.inputStream, logOut) + val errFuture = redirect(process.errorStream, logOut) + + val exit = process.waitFor() + outFuture.get(500L, TimeUnit.MILLISECONDS) + errFuture.get(500L, TimeUnit.MILLISECONDS) + + if (exit != 0) { + throw PaperweightException("Failed to apply old $name, see log at $oldLog") + } + } + } } diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/SetupForkUpstreamSources.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/SetupForkUpstreamSources.kt new file mode 100644 index 000000000..d9b676651 --- /dev/null +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/SetupForkUpstreamSources.kt @@ -0,0 +1,103 @@ +/* + * 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.tasks + +import io.papermc.paperweight.core.util.ApplySourceATs +import io.papermc.paperweight.tasks.* +import io.papermc.paperweight.util.* +import io.papermc.paperweight.util.constants.paperTaskOutput +import io.papermc.paperweight.util.set +import kotlin.io.path.* +import org.eclipse.jgit.api.Git +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.file.RegularFileProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputDirectory +import org.gradle.api.tasks.InputFile +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.Nested +import org.gradle.api.tasks.Optional +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.kotlin.dsl.* +import org.gradle.work.DisableCachingByDefault + +@DisableCachingByDefault(because = "Generated Git repository history is not reused across builds") +abstract class SetupForkUpstreamSources : JavaLauncherTask() { + + @get:InputDirectory + @get:PathSensitive(PathSensitivity.RELATIVE) + abstract val inputDir: DirectoryProperty + + @get:OutputDirectory + abstract val outputDir: DirectoryProperty + + @get:Internal + abstract val atWorkingDir: DirectoryProperty + + @get:Nested + val ats: ApplySourceATs = objects.newInstance() + + @get:InputFile + @get:Optional + @get:PathSensitive(PathSensitivity.NONE) + abstract val atFile: RegularFileProperty + + @get:Input + abstract val validateAts: Property + + @get:Input + abstract val identifier: Property + + override fun init() { + super.init() + atWorkingDir.set(layout.cache.resolve(paperTaskOutput(name = "${name}_atWorkingDir"))) + } + + @TaskAction + fun run() { + val out = outputDir.path.cleanDir() + inputDir.path.copyRecursivelyTo(out) + + val git = Git.open(outputDir.path.toFile()) + + if (atFile.isPresent && atFile.path.readText().isNotBlank()) { + println("Applying access transformers...") + ats.run( + launcher.get(), + inputDir.path, + outputDir.path, + atFile.path, + atWorkingDir.path, + validate = validateAts.get(), + ) + commitAndTag(git, "ATs", "${identifier.get()} ATs") + } + commitAndTag(git, "base") + + git.close() + } +} diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/SetupMinecraftSources.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/SetupMinecraftSources.kt index 70110a9c3..0902960b9 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/SetupMinecraftSources.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/SetupMinecraftSources.kt @@ -22,9 +22,10 @@ package io.papermc.paperweight.core.tasks -import codechicken.diffpatch.cli.PatchOperation -import codechicken.diffpatch.util.LoggingOutputStream -import codechicken.diffpatch.util.archiver.ArchiveFormat +import io.codechicken.diffpatch.cli.PatchOperation +import io.codechicken.diffpatch.util.Input as DiffInput +import io.codechicken.diffpatch.util.Output as DiffOutput +import io.codechicken.diffpatch.util.archiver.ArchiveFormat import io.papermc.paperweight.PaperweightException import io.papermc.paperweight.core.util.ApplySourceATs import io.papermc.paperweight.tasks.* @@ -69,6 +70,10 @@ abstract class SetupMinecraftSources : JavaLauncherZippedTask() { @get:Input abstract val oldPaperCommit: Property + @get:Optional + @get:Input + abstract val validateATs: Property + @get:Nested val ats: ApplySourceATs = objects.newInstance() @@ -123,7 +128,7 @@ abstract class SetupMinecraftSources : JavaLauncherZippedTask() { git.tag().setName("ROOT").setTagger(rootIdent).setSigned(false).call() } - println("Copy initial sources...") + logger.lifecycle("Copy initial sources...") inputFile.path.openZip().use { inputFileFs -> inputFileFs.walkSequence() .filter(predicate.get()::test) @@ -144,21 +149,21 @@ abstract class SetupMinecraftSources : JavaLauncherZippedTask() { } } - println("Setup git repo...") + logger.lifecycle("Setup git repo...") if (!oldPaperCommit.isPresent) { commitAndTag(git, "Vanilla") } if (!mache.isEmpty) { - println("Applying mache patches...") + logger.lifecycle("Applying mache patches...") val result = PatchOperation.builder() - .logTo(LoggingOutputStream(logger, LogLevel.LIFECYCLE)) - .basePath(outputPath.convertToPath()) - .outputPath(outputPath.convertToPath()) - .patchesPath(mache.singleFile.toPath(), ArchiveFormat.ZIP) + .logTo(logger::lifecycle) + .baseInput(DiffInput.MultiInput.folder(outputPath.convertToPath())) + .patchedOutput(DiffOutput.MultiOutput.folder(outputPath.convertToPath())) + .patchesInput(DiffInput.MultiInput.archive(ArchiveFormat.ZIP, mache.singleFile.toPath())) .patchesPrefix("patches") - .level(codechicken.diffpatch.util.LogLevel.INFO) + .level(io.codechicken.diffpatch.util.LogLevel.INFO) .ignorePrefix(".git") .build() .operate() @@ -168,20 +173,21 @@ abstract class SetupMinecraftSources : JavaLauncherZippedTask() { } if (result.exit != 0) { - throw Exception("Failed to apply ${result.summary.failedMatches} mache patches") + throw Exception("Failed to apply ${result.summary?.failedMatches} mache patches") } - logger.lifecycle("Applied ${result.summary.changedFiles} mache patches") + logger.lifecycle("Applied ${result.summary?.changedFiles} mache patches") } if (atFile.isPresent) { - println("Applying access transformers...") + logger.lifecycle("Applying access transformers...") ats.run( launcher.get(), outputPath, outputPath, atFile.path, atWorkingDir.path, + validate = validateATs.get(), ) if (!oldPaperCommit.isPresent) { commitAndTag(git, "ATs", "paper ATs") diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/ApplyBasePatches.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/ApplyBasePatches.kt new file mode 100644 index 000000000..43f633f29 --- /dev/null +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/ApplyBasePatches.kt @@ -0,0 +1,233 @@ +/* + * 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.tasks.patching + +import io.papermc.paperweight.PaperweightException +import io.papermc.paperweight.tasks.* +import io.papermc.paperweight.util.* +import java.nio.file.Path +import java.time.Instant +import kotlin.io.path.* +import org.eclipse.jgit.api.Git +import org.eclipse.jgit.lib.PersonIdent +import org.eclipse.jgit.transport.URIish +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputDirectory +import org.gradle.api.tasks.Optional +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.work.DisableCachingByDefault + +@DisableCachingByDefault(because = "The task produces a Git working repository, may fetch a remote and retains failure state for manual recovery") +abstract class ApplyBasePatches : ControllableOutputTask() { + + @get:PathSensitive(PathSensitivity.NONE) + @get:InputDirectory + abstract val input: DirectoryProperty + + @get:OutputDirectory + abstract val output: DirectoryProperty + + @get:Optional + @get:Input + abstract val baseRef: Property + + @get:PathSensitive(PathSensitivity.NONE) + @get:InputDirectory + @get:Optional + abstract val patches: DirectoryProperty + + @get:Input + abstract val verbose: Property + + @get:Input + @get:Optional + abstract val identifier: Property + + // An additional remote to add and fetch from before applying patches (to bring in objects for 3-way merge). + @get:Input + @get:Optional + abstract val additionalRemote: Property + + @get:Input + abstract val additionalRemoteName: Property + + override fun init() { + printOutput.convention(false).finalizeValueOnRead() + additionalRemoteName.convention("old") + verbose.convention(false) + } + + @TaskAction + fun run() { + io.papermc.paperweight.util.Git.checkForGit() + + val outputPath = output.path + recreateCloneDirectory(outputPath) + + checkoutRepoFromUpstream( + Git(outputPath), + input.path, + baseRef.getOrElse("main"), + "upstream", + "main", + baseRef.isPresent, + ) + + if (additionalRemote.isPresent) { + val jgit = Git.open(outputPath.toFile()) + jgit.remoteRemove().setRemoteName(additionalRemoteName.get()).call() + jgit.remoteAdd().setName(additionalRemoteName.get()).setUri(URIish(additionalRemote.get())).call() + jgit.fetch().setRemote(additionalRemoteName.get()).call() + } + + setupGitHook(outputPath) + + tagBase() + + if (!patches.isPresent) { + commit() + } else { + applyGitPatches("server repo", outputPath, patches.path, printOutput.get(), verbose.get()) + } + } + + private fun recreateCloneDirectory(target: Path) { + if (target.exists()) { + if (target.resolve(".git").isDirectory()) { + val git = Git(target) + git("clean", "-fxd").runSilently(silenceErr = true) + git("reset", "--hard", "HEAD").runSilently(silenceErr = true) + } else { + for (entry in target.listDirectoryEntries()) { + entry.deleteRecursive() + } + target.createDirectories() + } + } else { + target.createDirectories() + } + } + + private fun tagBase() { + val git = Git.open(output.path.toFile()) + val ident = PersonIdent("base", "noreply+automated@papermc.io") + git.tagDelete().setTags("base").call() + git.tag().setName("base").setTagger(ident).setSigned(false).call() + git.close() + } + + 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(PersonIdent("Base Patches", "noreply+automated@papermc.io"), Instant.parse("1997-04-20T13:37:42.69Z")) + val git = Git.open(output.path.toFile()) + git.add().addFilepattern(".").call() + git.commit() + .setMessage("${identifier.get()} Base Patches") + .setAuthor(ident) + .setAllowEmpty(true) + .setSign(false) + .call() + git.tagDelete().setTags("basepatches").call() + git.tag().setName("basepatches").setTagger(ident).setSigned(false).call() + git.close() + } + + private fun applyGitPatches( + target: String, + outputDir: Path, + patchDir: Path?, + printOutput: Boolean, + verbose: Boolean, + ) { + if (printOutput) { + logger.lifecycle("Applying patches to $target...") + } + + val git = Git(outputDir) + val statusFile = outputDir.resolve(".git/patch-apply-failed") + statusFile.deleteForcefully() + val logFile = outputDir.resolve(".git/patch-apply-logs.log") + logFile.deleteForcefully() + outputDir.filesMatchingRecursive("*.rej").forEach { it.deleteForcefully() } + + git("am", "--abort").runSilently(silenceErr = true) + + val patches = patchDir?.useDirectoryEntries("*.patch") { it.toMutableList() } ?: mutableListOf() + if (patches.isEmpty()) { + if (printOutput) { + logger.lifecycle("No patches found") + } + commit() + return + } + + // This prevents the `git am` command line from getting too big with too many patches + // mostly an issue with Windows + layout.cache.createDirectories() + val tempDir = createTempDirectory(layout.cache, "paperweight") + try { + val mailDir = tempDir.resolve("new") + mailDir.createDirectories() + + for (patch in patches) { + patch.copyTo(mailDir.resolve(patch.fileName)) + } + + val gitOut = printOutput && verbose + val result = git("am", "--3way", "--ignore-whitespace", tempDir.absolutePathString()).captureOut(gitOut) + + if (result.exit != 0) { + statusFile.writeText("1") + + if (!gitOut) { + // Log the output anyway on failure + logger.error(result.out) + } + logger.error("*** Please review above details and finish the apply then") + logger.error("*** save the changes with `./gradlew rebuildPatches`") + + throw PaperweightException("Failed to apply patches") + } else { + statusFile.deleteForcefully() + logFile.deleteForcefully() + if (printOutput) { + logger.lifecycle("${patches.size} patches applied cleanly to $target") + } + } + } finally { + tempDir.deleteRecursive() + } + commit() + } +} diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/ApplyFeaturePatches.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/ApplyFeaturePatches.kt index 419064d25..c2b6a34b0 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/ApplyFeaturePatches.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/ApplyFeaturePatches.kt @@ -109,6 +109,9 @@ abstract class ApplyFeaturePatches : ControllableOutputTask() { val statusFile = outputDir.resolve(".git/patch-apply-failed") statusFile.deleteForcefully() + val logFile = outputDir.resolve(".git/patch-apply-logs.log") + logFile.deleteForcefully() + outputDir.filesMatchingRecursive("*.rej").forEach { it.deleteForcefully() } git("am", "--abort").runSilently(silenceErr = true) @@ -134,12 +137,13 @@ abstract class ApplyFeaturePatches : ControllableOutputTask() { val gitOut = printOutput && verbose val result = git("am", "--3way", "--ignore-whitespace", tempDir.absolutePathString()).captureOut(gitOut) + if (result.exit != 0) { statusFile.writeText("1") if (!gitOut) { // Log the output anyway on failure - logger.lifecycle(result.out) + logger.error(result.out) } logger.error("*** Please review above details and finish the apply then") logger.error("*** save the changes with `./gradlew rebuildPatches`") @@ -147,6 +151,7 @@ abstract class ApplyFeaturePatches : ControllableOutputTask() { throw PaperweightException("Failed to apply patches") } else { statusFile.deleteForcefully() + logFile.deleteForcefully() if (printOutput) { logger.lifecycle("${patches.size} patches applied cleanly to $target") } diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/ApplyFilePatches.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/ApplyFilePatches.kt index 999f74b0b..f81e3f999 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/ApplyFilePatches.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/ApplyFilePatches.kt @@ -22,28 +22,26 @@ package io.papermc.paperweight.core.tasks.patching -import codechicken.diffpatch.cli.PatchOperation -import codechicken.diffpatch.match.FuzzyLineMatcher -import codechicken.diffpatch.util.LoggingOutputStream -import codechicken.diffpatch.util.PatchMode +import io.codechicken.diffpatch.cli.PatchOperation +import io.codechicken.diffpatch.match.FuzzyLineMatcher +import io.codechicken.diffpatch.util.Input as DiffInput +import io.codechicken.diffpatch.util.Output as DiffOutput +import io.codechicken.diffpatch.util.PatchMode import io.papermc.paperweight.PaperweightException import io.papermc.paperweight.tasks.* import io.papermc.paperweight.util.* -import java.io.PrintStream import java.nio.file.Path import java.time.Instant import kotlin.io.path.* import org.eclipse.jgit.api.Git import org.eclipse.jgit.lib.PersonIdent -import org.eclipse.jgit.transport.URIish import org.gradle.api.file.DirectoryProperty -import org.gradle.api.logging.LogLevel import org.gradle.api.provider.Property import org.gradle.api.tasks.* import org.gradle.api.tasks.options.Option import org.gradle.work.DisableCachingByDefault -@DisableCachingByDefault(because = "The task produces a Git working repository and may fetch a remote") +@DisableCachingByDefault(because = "The task mutates a Git repository") abstract class ApplyFilePatches : BaseTask() { @get:Input @@ -55,6 +53,7 @@ abstract class ApplyFilePatches : BaseTask() { @get:PathSensitive(PathSensitivity.NONE) @get:InputDirectory + @get:Optional abstract val input: DirectoryProperty @get:OutputDirectory @@ -72,7 +71,6 @@ abstract class ApplyFilePatches : BaseTask() { @get:Input abstract val gitFilePatches: Property - @get:Optional @get:Input abstract val baseRef: Property @@ -80,14 +78,6 @@ abstract class ApplyFilePatches : BaseTask() { @get:Optional abstract val identifier: Property - // An additional remote to add and fetch from before applying patches (to bring in objects for 3-way merge). - @get:Input - @get:Optional - abstract val additionalRemote: Property - - @get:Input - abstract val additionalRemoteName: Property - @get:Input abstract val moveFailedGitPatchesToRejects: Property @@ -98,9 +88,9 @@ abstract class ApplyFilePatches : BaseTask() { run { verbose.convention(false) gitFilePatches.convention(false) - additionalRemoteName.convention("old") moveFailedGitPatchesToRejects.convention(false) emitRejects.convention(true) + baseRef.convention("basepatches") } } @@ -109,32 +99,45 @@ abstract class ApplyFilePatches : BaseTask() { io.papermc.paperweight.util.Git.checkForGit() val outputPath = output.path - recreateCloneDirectory(outputPath) - - checkoutRepoFromUpstream( - Git(outputPath), - input.path, - baseRef.getOrElse("main"), - "upstream", - "main", - baseRef.isPresent, - ) - - if (additionalRemote.isPresent) { - val jgit = Git.open(outputPath.toFile()) - jgit.remoteRemove().setRemoteName(additionalRemoteName.get()).call() - jgit.remoteAdd().setName(additionalRemoteName.get()).setUri(URIish(additionalRemote.get())).call() - jgit.fetch().setRemote(additionalRemoteName.get()).call() - } - - setupGitHook(outputPath) - tagBase() + // special handling for resource patches + if (input.pathOrNull != null && baseRef.get() == "main") { + recreateCloneDirectory(outputPath) + checkoutRepoFromUpstream( + Git(outputPath), + input.path, + "main", + "upstream", + baseRef.get(), + false, // we need to set ref to false for patching to properly work + ) + setupGitHook(outputPath) + tagBase() + } else { + // rest of the original logic + if (input.pathOrNull != null && input.path.toAbsolutePath() != outputPath.toAbsolutePath()) { + recreateCloneDirectory(outputPath) + val git = Git(outputPath.createDirectories()) + checkoutRepoFromUpstream( + git, + input.path, + baseRef.get(), + branchName = "main", + ref = true, + ) + } + val git = Git(outputPath) + if (git("checkout", "main").runSilently(silenceErr = true) != 0) { + git("checkout", "-b", "main").runSilently(silenceErr = true) + } + git("reset", "--hard", baseRef.get()).runSilently(silenceErr = true) + git("gc").runSilently(silenceErr = true) + } val result = if (!patches.isPresent) { commit() 0 - } else if (gitFilePatches.get()) { + } else if (gitFilePatches.get() && shouldApplyWithGit(outputPath)) { applyWithGit(outputPath) } else { applyWithDiffPatch() @@ -170,6 +173,16 @@ abstract class ApplyFilePatches : BaseTask() { git.close() } + private fun shouldApplyWithGit(outputPath: Path): Boolean { + val patchFiles = patches.path.filesMatchingRecursive("*.patch") + val git = Git(outputPath) + val canApply = patchFiles.any { patch -> + val result = git("apply", "--check", patch.absolutePathString()).getText(ignoreErr = true) + result.contains("error: corrupt patch at line") + } + return !canApply + } + private fun applyWithGit(outputPath: Path): Int { val git = Git(outputPath) val patchFiles = patches.path.filesMatchingRecursive("*.patch") @@ -212,21 +225,20 @@ abstract class ApplyFilePatches : BaseTask() { return patchFiles.size } - private fun applyWithDiffPatch(): Int { - val printStream = PrintStream(LoggingOutputStream(logger, LogLevel.LIFECYCLE)) + private fun applyWithDiffPatch(): Int? { val builder = PatchOperation.builder() - .logTo(printStream) - .basePath(output.path) - .patchesPath(patches.path) - .outputPath(output.path) - .level(if (verbose.get()) codechicken.diffpatch.util.LogLevel.ALL else codechicken.diffpatch.util.LogLevel.INFO) + .logTo(logger::lifecycle) + .baseInput(DiffInput.MultiInput.folder(output.path)) + .patchesInput(DiffInput.MultiInput.folder(patches.path)) + .patchedOutput(DiffOutput.MultiOutput.folder(output.path)) + .level(if (verbose.get()) io.codechicken.diffpatch.util.LogLevel.ALL else io.codechicken.diffpatch.util.LogLevel.INFO) .mode(mode()) .minFuzz(minFuzz()) .summary(verbose.get()) .lineEnding("\n") .ignorePrefix(".git") if (rejectsDir.isPresent && emitRejects.get()) { - builder.rejectsPath(rejectsDir.path) + builder.rejectsOutput(DiffOutput.MultiOutput.folder(rejectsDir.path)) } val result = builder.build().operate() @@ -234,12 +246,12 @@ abstract class ApplyFilePatches : BaseTask() { 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") + val total = (result.summary?.failedMatches ?: 0) + (result.summary?.exactMatches ?: 0) + + (result.summary?.accessMatches ?: 0) + (result.summary?.offsetMatches ?: 0) + (result.summary?.fuzzyMatches ?: 0) + throw Exception("Failed to apply ${result.summary?.failedMatches}/$total hunks") } - return result.summary.changedFiles + return result.summary?.changedFiles } private fun setupGitHook(outputPath: Path) { diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/ApplyFilePatchesFuzzy.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/ApplyFilePatchesFuzzy.kt index 091d8b7fe..df34318b9 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/ApplyFilePatchesFuzzy.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/ApplyFilePatchesFuzzy.kt @@ -22,7 +22,7 @@ package io.papermc.paperweight.core.tasks.patching -import codechicken.diffpatch.util.PatchMode +import io.codechicken.diffpatch.util.PatchMode import io.papermc.paperweight.core.util.defaultMinFuzz import javax.inject.Inject import org.gradle.api.provider.Property diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/ApplySingleFilePatches.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/ApplySingleFilePatches.kt index 9751fa59a..0cad24fa6 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/ApplySingleFilePatches.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/ApplySingleFilePatches.kt @@ -22,9 +22,11 @@ package io.papermc.paperweight.core.tasks.patching -import codechicken.diffpatch.cli.PatchOperation -import codechicken.diffpatch.util.LogLevel -import codechicken.diffpatch.util.PatchMode +import io.codechicken.diffpatch.cli.PatchOperation +import io.codechicken.diffpatch.util.Input as DiffInput +import io.codechicken.diffpatch.util.LogLevel +import io.codechicken.diffpatch.util.Output as DiffOutput +import io.codechicken.diffpatch.util.PatchMode import io.papermc.paperweight.PaperweightException import io.papermc.paperweight.core.util.defaultMinFuzz import io.papermc.paperweight.tasks.* @@ -135,10 +137,10 @@ abstract class ApplySingleFilePatches : BaseTask() { .mode(mode.get()) .minFuzz(minFuzz.get().toFloat()) .summary(false) - .basePath(tmpWork) - .patchesPath(tmpPatch) - .outputPath(tmpWork) - .rejectsPath(tmpRej) + .baseInput(DiffInput.MultiInput.folder(tmpWork)) + .patchesInput(DiffInput.MultiInput.folder(tmpPatch)) + .patchedOutput(DiffOutput.MultiOutput.folder(tmpWork)) + .rejectsOutput(DiffOutput.MultiOutput.folder(tmpRej)) .build() op.operate() diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/CreateBasePatch.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/CreateBasePatch.kt new file mode 100644 index 000000000..57e30d0da --- /dev/null +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/CreateBasePatch.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.core.tasks.patching + +import io.papermc.paperweight.tasks.* +import io.papermc.paperweight.util.* +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputDirectory +import org.gradle.api.tasks.Optional +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 run when requested") +abstract class CreateBasePatch : BaseTask() { + + @get:InputDirectory + @get:PathSensitive(PathSensitivity.NONE) + abstract val repo: DirectoryProperty + + @get:Input + @get:Optional + @get:Option(option = "message", description = "Commit message") + abstract val message: Property + + @get:Input + @get:Optional + @get:Option(option = "description", description = "Commit description") + abstract val commitDescription: Property + + @get:Input + abstract val identifier: Property + + @TaskAction + fun run() { + val git = Git(repo) + if (message.isPresent) { + val additionalArgs = if (commitDescription.isPresent) arrayOf("-m", commitDescription.get()) else arrayOf() + git("add", ".").executeOut() + git("commit", "-m", message.get(), *additionalArgs).executeOut() + } + val baseCommit = git("rev-parse", "basepatches").getText().trim() + val headCommit = git("rev-parse", "HEAD").getText().trim() + git("branch", "-f", "fixup/basepatches").executeOut() + git("reset", "basepatches~1", "--hard").executeOut() + git("cherry-pick", headCommit).executeOut() + git("cherry-pick", "$baseCommit~1..$headCommit~1", "--keep-redundant-commits").executeOut() + git("switch", "-C", "main", "HEAD").executeOut() + git("branch", "-D", "fixup/basepatches").executeOut() + tagCommits(git) + } + + fun tagCommits(git: Git) { + // single commit, since if its more than that it means the repo state is corrupted and we can't rebuild safely + val baseCommit = getCommitByIdentifier(git, identifier, "Base", "single").joinToString() + // retag + git("tag", "-f", "basepatches", baseCommit).executeOut() + } +} diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/FixupBasePatches.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/FixupBasePatches.kt new file mode 100644 index 000000000..eb9b7459f --- /dev/null +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/FixupBasePatches.kt @@ -0,0 +1,100 @@ +/* + * 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.tasks.patching + +import io.papermc.paperweight.tasks.* +import io.papermc.paperweight.util.* +import kotlin.io.path.listDirectoryEntries +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputDirectory +import org.gradle.api.tasks.Optional +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 fixup when requested") +abstract class FixupBasePatches : BaseTask() { + + @get:InputDirectory + @get:PathSensitive(PathSensitivity.NONE) + abstract val repo: DirectoryProperty + + @get:Input + abstract val upstream: Property + + @get:InputDirectory + @get:PathSensitive(PathSensitivity.NONE) + abstract val patches: DirectoryProperty + + @get:Input + abstract val identifier: Property + + @get:Input + @get:Optional + @get:Option(option = "patch-number", description = "Select the patch to modify") + abstract val patchNumber: Property + + @TaskAction + fun run() { + val git = Git(repo) + var index = Int.MIN_VALUE + if (patchNumber.isPresent) { + index = patchNumber.get().minus(1) + } else { + logger.lifecycle("===============================================") + logger.lifecycle("Please enter the patch number into which the current changes should be merged") + logger.lifecycle("===============================================") + val patches = patches.get().path.listDirectoryEntries("*.patch").toList().sortedBy { it.fileName.toString().substringBefore("-").toInt() } + logger.lifecycle("Possible patches:") + for (patch in patches) { + logger.lifecycle(patch.fileName.toString()) + } + logger.lifecycle("===============================================") + while (index == Int.MIN_VALUE) { + index = System.`in`.bufferedReader().readLine().toInt().minus(1) + } + } + val hasBasePatchesTag = git("rev-parse", "-q", "--verify", "basepatches").getText() + val headTag = if (hasBasePatchesTag.isNotEmpty()) "basepatches" else "HEAD" + val commits = git("rev-list", "base..$headTag").getText().trim().lines().filter { it.isNotBlank() }.reversed() + if (index < 0 || index >= commits.size) { + error("Patch index out of range: $index (size=${commits.size})") + } + val selectedCommit = commits[index] + git("add", ".").executeOut() + git("commit", "--fixup", selectedCommit).executeOut() + git("-c", "sequence.editor=:", "rebase", "-i", "--autosquash", upstream.get()).executeOut() + tagCommits(git) + } + + fun tagCommits(git: Git) { + // single commit, since if its more than that it means the repo state is corrupted and we can't rebuild safely + val baseCommit = getCommitByIdentifier(git, identifier, "Base", "single").joinToString() + // retag + git("tag", "-f", "basepatches", baseCommit).executeOut() + } +} diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/FixupFeaturePatches.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/FixupFeaturePatches.kt new file mode 100644 index 000000000..d3a922355 --- /dev/null +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/FixupFeaturePatches.kt @@ -0,0 +1,87 @@ +/* + * 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.tasks.patching + +import io.papermc.paperweight.tasks.* +import io.papermc.paperweight.util.* +import kotlin.io.path.listDirectoryEntries +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.InputDirectory +import org.gradle.api.tasks.Optional +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 fixup when requested") +abstract class FixupFeaturePatches : BaseTask() { + + @get:InputDirectory + @get:PathSensitive(PathSensitivity.NONE) + abstract val repo: DirectoryProperty + + @get:Input + abstract val upstream: Property + + @get:InputDirectory + @get:PathSensitive(PathSensitivity.NONE) + abstract val patches: DirectoryProperty + + @get:Input + @get:Optional + @get:Option(option = "patch-number", description = "Select the patch to modify") + abstract val patchNumber: Property + + @TaskAction + fun run() { + val git = Git(repo) + var index = Int.MIN_VALUE + if (patchNumber.isPresent) { + index = patchNumber.get() - 1 // -1 as the commits index starts from 0 whereas patches start from 1 + } else { + logger.lifecycle("===============================================") + logger.lifecycle("Please enter the patch number into which the current changes should be merged") + logger.lifecycle("===============================================") + val patches = patches.get().path.listDirectoryEntries("*.patch").toList().sortedBy { it.fileName.toString().substringBefore("-").toInt() } + logger.lifecycle("Possible patches:") + for (patch in patches) { + logger.lifecycle(patch.fileName.toString()) + } + logger.lifecycle("===============================================") + while (index == Int.MIN_VALUE) { + index = System.`in`.bufferedReader().readLine().toInt() - 1 + } + } + val commits = git("rev-list", "file..HEAD").getText().trim().lines().filter { it.isNotBlank() }.reversed() + if (index < 0 || index >= commits.size) { + error("Patch index out of range: $index (size=${commits.size})") + } + val selectedCommit = commits[index] + git("add", ".").executeOut() + git("commit", "--fixup", selectedCommit).executeOut() + git("-c", "sequence.editor=:", "rebase", "-i", "--autosquash", upstream.get()).executeOut() + } +} diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/RebuildFilePatches.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/RebuildFilePatches.kt index a9c4d0ae3..c3264cd05 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/RebuildFilePatches.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/RebuildFilePatches.kt @@ -22,14 +22,15 @@ package io.papermc.paperweight.core.tasks.patching -import codechicken.diffpatch.cli.DiffOperation -import codechicken.diffpatch.util.LogLevel -import codechicken.diffpatch.util.LoggingOutputStream +import io.codechicken.diffpatch.cli.DiffOperation +import io.codechicken.diffpatch.util.Input as DiffInput +import io.codechicken.diffpatch.util.LogLevel +import io.codechicken.diffpatch.util.Output as DiffOutput import io.papermc.paperweight.PaperweightException import io.papermc.paperweight.core.util.ApplySourceATs import io.papermc.paperweight.tasks.* import io.papermc.paperweight.util.* -import java.io.PrintStream +import io.papermc.paperweight.util.constants.paperTaskOutput import java.nio.file.Path import kotlin.io.path.* import org.cadixdev.at.AccessTransformSet @@ -53,11 +54,11 @@ abstract class RebuildFilePatches : JavaLauncherTask() { ) abstract val verbose: Property - @get:Internal - abstract val input: DirectoryProperty - @get:InputDirectory @get:PathSensitive(PathSensitivity.RELATIVE) + abstract val input: DirectoryProperty + + @get:Internal abstract val base: DirectoryProperty @get:OutputDirectory @@ -80,11 +81,15 @@ abstract class RebuildFilePatches : JavaLauncherTask() { @get:Nested val ats: ApplySourceATs = objects.newInstance() + @get:Input + abstract val identifier: Property + override fun init() { super.init() contextLines.convention(3) verbose.convention(false) gitFilePatches.convention(false) + base.set(layout.cache.resolve(paperTaskOutput())) } @TaskAction @@ -94,9 +99,20 @@ abstract class RebuildFilePatches : JavaLauncherTask() { val baseDir = base.convertToPath() val git = Git(inputDir) + + // single commit, since if its more than that it means the repo state is corrupted and we can't rebuild safely + val fileCommit = getCommitByIdentifier(git, identifier, "File", "single").joinToString() + + // we update the appropriate tag to reflect the new repo state + git("tag", "-f", "file", fileCommit).executeSilently(silenceErr = true) + + // now we can safely work with the repo, having updated the tag git("stash", "push").executeSilently(silenceErr = true) git("checkout", "file").executeSilently(silenceErr = true) + val baseCommit = "file~1" + git("worktree", "add", "--detach", "--force", baseDir.absolutePathString(), baseCommit).executeSilently(silenceErr = true) + val filesWithNewAts = if (!ats.jst.isEmpty) { handleAts( baseDir, @@ -123,6 +139,7 @@ abstract class RebuildFilePatches : JavaLauncherTask() { rebuildWithDiffPatch(baseDir, inputDir, patchDir) } + git("worktree", "remove", "--force", baseDir.absolutePathString()).executeSilently(silenceErr = true) git("switch", "-").executeSilently(silenceErr = true) if (filesWithNewAts.isNotEmpty()) { try { @@ -131,7 +148,7 @@ abstract class RebuildFilePatches : JavaLauncherTask() { // and then execs for all the files that remove the papter // todo detect if sed is not present (windows) and switch out sed for something else @Language("Shell Script") - val sequenceEditor = "sed -i -e 0,/pick/{s/pick/drop/}" + val sequenceEditor = "sed -i '/File Patches/ s/^pick /drop /' \"\$1\"" // maybe begin some work? val execs = filesWithNewAts .map { "sed -i -e 's|// Paper-AT:.*||g' $it && ((git add $it && git commit --amend --no-edit) || true)" } .flatMap { listOf("--exec", it) }.toTypedArray() @@ -182,13 +199,12 @@ abstract class RebuildFilePatches : JavaLauncherTask() { baseDir: Path, inputDir: Path, patchDir: Path - ): Int { - val printStream = PrintStream(LoggingOutputStream(logger, org.gradle.api.logging.LogLevel.LIFECYCLE)) + ): Int? { val result = DiffOperation.builder() - .logTo(printStream) - .aPath(baseDir) - .bPath(inputDir) - .outputPath(patchDir) + .logTo(logger::lifecycle) + .baseInput(DiffInput.MultiInput.folder(baseDir)) + .changedInput(DiffInput.MultiInput.folder(inputDir)) + .patchesOutput(DiffOutput.MultiOutput.folder(patchDir)) .autoHeader(true) .level(if (verbose.get()) LogLevel.ALL else LogLevel.INFO) .lineEnding("\n") @@ -200,7 +216,7 @@ abstract class RebuildFilePatches : JavaLauncherTask() { .summary(verbose.get()) .build() .operate() - return result.summary.changedFiles + return result.summary?.changedFiles } private fun handleAts( @@ -258,6 +274,7 @@ abstract class RebuildFilePatches : JavaLauncherTask() { at, temporaryDir.toPath().resolve("jst_work"), singleFile = true, + validate = true, ) println("NEW: " + decomp.readText()) } diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/RebuildSingleFilePatches.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/RebuildSingleFilePatches.kt index 98611330c..c4278c8ce 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/RebuildSingleFilePatches.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/tasks/patching/RebuildSingleFilePatches.kt @@ -22,8 +22,10 @@ package io.papermc.paperweight.core.tasks.patching -import codechicken.diffpatch.cli.DiffOperation -import codechicken.diffpatch.util.LogLevel +import io.codechicken.diffpatch.cli.DiffOperation +import io.codechicken.diffpatch.util.Input as DiffInput +import io.codechicken.diffpatch.util.LogLevel +import io.codechicken.diffpatch.util.Output as DiffOutput import io.papermc.paperweight.tasks.* import io.papermc.paperweight.util.* import java.io.PrintStream @@ -94,9 +96,9 @@ abstract class RebuildSingleFilePatches : BaseTask() { val result = DiffOperation.builder() .logTo(logOut) - .aPath(tmpA) - .bPath(tmpB) - .outputPath(tmpPatch) + .baseInput(DiffInput.MultiInput.folder(tmpA)) + .changedInput(DiffInput.MultiInput.folder(tmpB)) + .patchesOutput(DiffOutput.MultiOutput.folder(tmpPatch)) .autoHeader(true) .level(LogLevel.ALL) .lineEnding("\n") diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/util/ApplySourceATs.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/util/ApplySourceATs.kt index b19114435..dc6cd8d89 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/util/ApplySourceATs.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/util/ApplySourceATs.kt @@ -53,6 +53,7 @@ abstract class ApplySourceATs { atFile: Path, workDir: Path, singleFile: Boolean = false, + validate: Boolean, ) { workDir.deleteRecursive() workDir.createDirectories() @@ -61,7 +62,7 @@ abstract class ApplySourceATs { workDir, workDir.resolve("log.txt"), jvmArgs = listOf("-Xmx${memory.get()}"), - args = jstArgs(input, output, atFile, singleFile).toTypedArray() + args = jstArgs(input, output, atFile, singleFile, validate).toTypedArray() ) } @@ -70,8 +71,10 @@ abstract class ApplySourceATs { outputDir: Path, atFile: Path, singleFile: Boolean = false, + validate: Boolean, ): List { val format = if (singleFile) "FILE" else "FOLDER" + val validation = if (validate) "ERROR" else "LOG" return listOf( "--in-format=$format", "--out-format=$format", @@ -79,7 +82,7 @@ abstract class ApplySourceATs { "--access-transformer=$atFile", "--access-transformer-inherit-method=true", "--hidden-prefix=.git", - // "--access-transformer-validation=ERROR", + "--access-transformer-validation=$validation", *jstClasspath.files.map { "--classpath=${it.absolutePath}" }.toTypedArray(), inputDir.absolutePathString(), outputDir.absolutePathString(), diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/util/project-util.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/util/project-util.kt index 130d91c5d..5954f4a71 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/util/project-util.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/core/util/project-util.kt @@ -31,7 +31,7 @@ fun Task.reobfRequiresDebug() { if (!paperweightDebug()) { throw PaperweightException( "Reobfuscated server jars are no longer supported and only exist for debugging purposes.\n" + - "If you are attempting to build a paperclip or bundler jar, use the 'mojmap' variant instead of 'reobf'.\n" + + "If you are attempting to build a publisher, paperclip or bundler jar, use the 'mojmap' variant instead of 'reobf'.\n" + "Enable paperweight debug mode to bypass this error.\n" ) } diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/patcher/PaperweightPatcher.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/patcher/PaperweightPatcher.kt index 2e58266fc..4c0afaae5 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/patcher/PaperweightPatcher.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/patcher/PaperweightPatcher.kt @@ -24,20 +24,28 @@ package io.papermc.paperweight.patcher import io.papermc.paperweight.core.taskcontainers.UpstreamConfigTasks import io.papermc.paperweight.core.tasks.CheckoutRepo +import io.papermc.paperweight.core.tasks.GeneratePatches +import io.papermc.paperweight.core.tasks.GenerateSources +import io.papermc.paperweight.core.tasks.PrepareForPatchGeneration import io.papermc.paperweight.core.tasks.RunNestedBuild +import io.papermc.paperweight.core.tasks.patchroulette.PatchRouletteTasks import io.papermc.paperweight.patcher.extension.PaperweightPatcherExtension import io.papermc.paperweight.util.* import io.papermc.paperweight.util.constants.* import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.api.file.Directory +import org.gradle.api.provider.Provider import org.gradle.api.tasks.Delete +import org.gradle.api.tasks.TaskProvider import org.gradle.kotlin.dsl.* +import org.gradle.kotlin.dsl.support.uppercaseFirstChar abstract class PaperweightPatcher : Plugin { override fun apply(target: Project) { Git.checkForGit(target.providers) - printId("paperweight-patcher", target.gradle) + printId("weaver-patcher", target.gradle) val patcher = target.extensions.create(PAPERWEIGHT_EXTENSION, PaperweightPatcherExtension::class) @@ -47,7 +55,34 @@ abstract class PaperweightPatcher : Plugin { delete(target.layout.cache) } - target.afterEvaluate { afterEvaluate(patcher) } + target.configurations.register(JST_CONFIG) { + defaultDependencies { + // add(project.dependencies.create("net.neoforged.jst:jst-cli-bundle:${LibraryVersions.JST}")) + add(target.dependencies.create("io.papermc.jst:jst-cli-bundle:${LibraryVersions.JST}")) + } + } + + target.configurations.register(JST_CLASSPATH_CONFIG) { + attributes { + attribute(JST_CLASSPATH_ATTRIBUTE, true) + } + } + + target.afterEvaluate { + repositories { + maven(patcher.jstRepo) { + name = JST_REPO_NAME + content { onlyForConfigurations(JST_CONFIG) } + } + maven(PAPER_MAVEN_REPO_URL) { + content { onlyForConfigurations(JST_CLASSPATH_CONFIG) } + } + mavenCentral { + content { onlyForConfigurations(JST_CLASSPATH_CONFIG) } + } + } + afterEvaluate(patcher) + } } private fun Project.afterEvaluate(patcher: PaperweightPatcherExtension) { @@ -78,6 +113,7 @@ abstract class PaperweightPatcher : Plugin { checkoutTask.flatMap { it.outputDir }, !isBaseExecution, "patching", + patcher.validateATs, patcher.gitFilePatches, patcher.filterPatches, applyUpstream, @@ -90,15 +126,128 @@ abstract class PaperweightPatcher : Plugin { upstream.directoryPatchSets.names.joinToString(", ") + ", ${upstream.name} single file" ) applyForDownstream { dependsOn("apply${upstream.name.capitalized()}Patches") } + tasks.register("applyAllPatches") { group = "patching" val depend = "apply${upstream.name.capitalized()}Patches" tasks.addAll("applyAllServerPatches") - description = "Applies all patches defined in the paperweight-patcher project and the server project. " + - "(equivalent to running '$depend' and then '${tasks.get().single()}' in a second Gradle invocation)" + description = "Applies all patches defined in the weaver-patcher project and the server project. " + + "(equivalent to running '$depend' and then ${tasks.get().single()}' in a second Gradle invocation)" projectDir.set(layout.projectDirectory) dependsOn(depend) } + // TODO: maybe lock it behind a property like the server tasks? + upstream.directoryPatchSets.configureEach { + PatchRouletteTasks( + this@afterEvaluate, + name, + upstream.ref.map { ref -> "$name-git-${ref.take(7)}" }, + rejectsDir, + outputDir.get(), + ) + } + } + patcher.additionalUpstreams.forEach { upstream -> + val checkoutTask = tasks.register("checkout${upstream.name.capitalized()}RepoForGeneration") { + repoName.set(upstream.name) + url.set(upstream.repo) + ref.set(upstream.ref) + workDir.set(workDirFromProp) + } + + val applyAdditionalUpstream = tasks.register("apply${upstream.name.capitalized()}ForGeneration") { + projectDir.set(checkoutTask.flatMap { it.outputDir }) + tasks.add("applyAllPatches") + } + + val depend: List> = upstream.patchGenerationConfig.inputConfig.map { input -> + val name = if (input.name == "minecraft") { + "Minecraft" + } else { + input.name.split("-").joinToString("") { + it.uppercaseFirstChar() + } + } + tasks.register("prepare${upstream.name.capitalized()}${name}ForPatchGeneration") { + group = INTERNAL_TASK_GROUP + dependsOn(applyAdditionalUpstream) + forkName.set(upstream.name) + repoName.set(input.name) + workDir.set(workDirFromProp) + atFile.set(input.additionalAts.fileExists()) + ats.jst.from(project.configurations.named(JST_CONFIG)) + validateATs.set(patcher.validateATs) + additionalPatch.set(input.additionalPatch.fileExists()) + } + } + + val sourceGenDepend: List> = upstream.sourceGenerationConfig.generationConfig.map { input -> + val name = input.name.split("-").joinToString("") { + it.uppercaseFirstChar() + } + val outputType = input.name.substringAfter("-") + val projectDir: Provider = project.provider { project.layout.projectDirectory.dir("${rootProject.name}-$outputType") } + + tasks.register("generate${name}Sources") { + group = "source generation" + description = "Generates sources from ${input.name}" + dependsOn(checkoutTask) + forkName.set(upstream.name) + forkUrl.set(upstream.repo) + inputFrom.set(input.name) + commitHash.set(upstream.ref) + workDir.set(workDirFromProp) + atFile.set(input.additionalAts.fileExists()) + ats.jst.from(project.configurations.named(JST_CONFIG)) + validateATs.set(patcher.validateATs) + additionalPatch.set(input.additionalPatch.fileExists()) + generateSources.set(input.generateSources.orElse(true)) + generateResources.set(input.generateResources.orElse(true)) + generateTestSources.set(input.generateTestSources.orElse(true)) + generateTestResources.set(input.generateTestResources.orElse(true)) + sourceOutput.set( + input.sourcesOutputDir.orElse(projectDir.map { it.dir("src/generated/main/java") }) + ) + resourceOutput.set( + input.resourcesOutputDir.orElse(projectDir.map { it.dir("src/generated/main/resources") }) + ) + testSourceOutput.set( + input.testSourcesOutputDir.orElse(projectDir.map { it.dir("src/generated/test/java") }) + ) + testResourceOutput.set( + input.testResourcesOutputDir.orElse(projectDir.map { it.dir("src/generated/test/resources") }) + ) + } + } + val apiProject: Provider = project.provider { project.layout.projectDirectory.dir("${rootProject.name}-api") } + val serverProject: Provider = project.provider { project.layout.projectDirectory.dir("${rootProject.name}-server") } + + val genPatches = tasks.register("generate${upstream.name.capitalized()}Patches") { + dependsOn(depend.map { it }) + group = "patch generation" + description = "Condenses ${upstream.name} changes for every inputConfig into a corresponding patch file" + forkName.set(upstream.name) + forkUrl.set(upstream.repo) + commitHash.set(upstream.ref) + inputFrom.set(upstream.patchGenerationConfig.inputConfig.joinToString(",") { it.name }) + preparedSource.from(depend.map { it.flatMap { t -> t.outputDir } }) + patchesDirOutput.set(upstream.patchGenerationConfig.patchesDirOutput) + serverProjectDir.set(serverProject) + apiProjectDir.set(apiProject) + outputDir.set(upstream.patchGenerationConfig.outputDir.orElse(project.layout.cacheDir(paperTaskOutput()))) + } + + val genSources = tasks.register("generate${upstream.name.capitalized()}Sources") { + group = "source generation" + description = "Generates sources from ${upstream.name}" + } + + val generate = tasks.register("generate${upstream.name.capitalized()}") { + group = "generation" + description = "Generates patches and sources from ${upstream.name}" + } + genSources { dependsOn(sourceGenDepend.map { it }) } + generate { dependsOn(genPatches, genSources) } } } } diff --git a/paperweight-core/src/main/kotlin/io/papermc/paperweight/patcher/extension/PaperweightPatcherExtension.kt b/paperweight-core/src/main/kotlin/io/papermc/paperweight/patcher/extension/PaperweightPatcherExtension.kt index 18fbc9591..adf6dc22b 100644 --- a/paperweight-core/src/main/kotlin/io/papermc/paperweight/patcher/extension/PaperweightPatcherExtension.kt +++ b/paperweight-core/src/main/kotlin/io/papermc/paperweight/patcher/extension/PaperweightPatcherExtension.kt @@ -22,7 +22,9 @@ package io.papermc.paperweight.patcher.extension +import io.papermc.paperweight.core.extension.AdditionalUpstreamConfig import io.papermc.paperweight.core.extension.UpstreamConfig +import io.papermc.paperweight.util.constants.PAPER_MAVEN_REPO_URL import javax.inject.Inject import org.gradle.api.Action import org.gradle.api.NamedDomainObjectContainer @@ -36,11 +38,18 @@ abstract class PaperweightPatcherExtension @Inject constructor(private val objec val gitFilePatches: Property = objects.property().convention(false) val filterPatches: Property = objects.property().convention(true) + val validateATs: Property = objects.property().convention(true) + + val jstRepo: Property = objects.property().convention(PAPER_MAVEN_REPO_URL) val upstreams: NamedDomainObjectContainer = objects.domainObjectContainer(UpstreamConfig::class) { objects.newInstance(it, true) } + val additionalUpstreams: NamedDomainObjectContainer = objects.domainObjectContainer(AdditionalUpstreamConfig::class) { + objects.newInstance(it) + } + fun NamedDomainObjectContainer.paper( op: Action ): NamedDomainObjectProvider = register("paper") { @@ -48,4 +57,20 @@ abstract class PaperweightPatcherExtension @Inject constructor(private val objec applyUpstreamNested.convention(false) op.execute(this) } + + fun NamedDomainObjectContainer.folia( + op: Action + ): NamedDomainObjectProvider = register("folia") { + repo.convention(github("PaperMC", "Folia")) + applyUpstreamNested.convention(true) + op.execute(this) + } + + fun NamedDomainObjectContainer.canvas( + op: Action + ): NamedDomainObjectProvider = register("canvas") { + repo.convention(github("CraftCanvasMC", "Canvas")) + applyUpstreamNested.convention(true) + op.execute(this) + } } diff --git a/paperweight-core/src/main/resources/META-INF/gradle-plugins/io.canvasmc.weaver.dependency-bridge.properties b/paperweight-core/src/main/resources/META-INF/gradle-plugins/io.canvasmc.weaver.dependency-bridge.properties new file mode 100644 index 000000000..8a5fb9178 --- /dev/null +++ b/paperweight-core/src/main/resources/META-INF/gradle-plugins/io.canvasmc.weaver.dependency-bridge.properties @@ -0,0 +1 @@ +implementation-class=io.papermc.paperweight.PaperweightDependencyBridge diff --git a/paperweight-core/src/main/resources/META-INF/gradle-plugins/io.papermc.paperweight.paper-checkstyle.properties b/paperweight-core/src/main/resources/META-INF/gradle-plugins/io.canvasmc.weaver.paper-checkstyle.properties similarity index 100% rename from paperweight-core/src/main/resources/META-INF/gradle-plugins/io.papermc.paperweight.paper-checkstyle.properties rename to paperweight-core/src/main/resources/META-INF/gradle-plugins/io.canvasmc.weaver.paper-checkstyle.properties diff --git a/paperweight-core/src/main/resources/META-INF/gradle-plugins/io.papermc.paperweight.source-generator.properties b/paperweight-core/src/main/resources/META-INF/gradle-plugins/io.canvasmc.weaver.source-generator.properties similarity index 100% rename from paperweight-core/src/main/resources/META-INF/gradle-plugins/io.papermc.paperweight.source-generator.properties rename to paperweight-core/src/main/resources/META-INF/gradle-plugins/io.canvasmc.weaver.source-generator.properties diff --git a/paperweight-core/src/test/kotlin/io/papermc/paperweight/FunctionalTest.kt b/paperweight-core/src/test/kotlin/io/papermc/paperweight/FunctionalTest.kt index 937ed2662..ea8ea5e85 100644 --- a/paperweight-core/src/test/kotlin/io/papermc/paperweight/FunctionalTest.kt +++ b/paperweight-core/src/test/kotlin/io/papermc/paperweight/FunctionalTest.kt @@ -105,13 +105,26 @@ class FunctionalTest { git("rebase", "--autosquash", "upstream/main").executeSilently() } - println("\nrunning rebuildPatches again\n") + // base patch + println("\nrebuilding base patch\n") val rebP2 = gradleRunner + .withArguments("rebuildBasePatches", "--stacktrace", "-Dfake=true") + .withDebug(debug) + .build() + + assertEquals(TaskOutcome.SUCCESS, rebP2.task(":test-server:rebuildBasePatches")?.outcome) + assertEquals( + testResource.resolve("fake-patches/expected/0001-Test-Base.patch").readText(), + tempDir.resolve("fake-patches/base/0001-Test-Base.patch").readText() + ) + + println("\nrunning rebuildPatches again\n") + val rebP3 = gradleRunner .withArguments("rebuildPatches", "--stacktrace", "-Dfake=true") .withDebug(debug) .build() - assertEquals(TaskOutcome.SUCCESS, rebP2.task(":test-server:rebuildPatches")?.outcome) + assertEquals(TaskOutcome.SUCCESS, rebP3.task(":test-server:rebuildPatches")?.outcome) assertEquals( testResource.resolve("fake-patches/expected/Test.java.patch").readText(), tempDir.resolve("fake-patches/sources/Test.java.patch").readText() @@ -130,11 +143,11 @@ class FunctionalTest { } println("\nrebuilding feature patch\n") - val rebP3 = gradleRunner + val rebP4 = gradleRunner .withArguments("rebuildPatches", "--stacktrace", "-Dfake=true") .withDebug(debug) .build() - assertEquals(TaskOutcome.SUCCESS, rebP3.task(":test-server:rebuildPatches")?.outcome) + assertEquals(TaskOutcome.SUCCESS, rebP4.task(":test-server:rebuildPatches")?.outcome) assertEquals( testResource.resolve("fake-patches/expected/0001-Feature.patch").readText(), tempDir.resolve("fake-patches/features/0001-Feature.patch").readText() diff --git a/paperweight-core/src/test/kotlin/io/papermc/paperweight/checkstyle/PaperCheckstyleTest.kt b/paperweight-core/src/test/kotlin/io/papermc/paperweight/checkstyle/PaperCheckstyleTest.kt index c10c16cfd..b6a22d7c8 100644 --- a/paperweight-core/src/test/kotlin/io/papermc/paperweight/checkstyle/PaperCheckstyleTest.kt +++ b/paperweight-core/src/test/kotlin/io/papermc/paperweight/checkstyle/PaperCheckstyleTest.kt @@ -42,7 +42,7 @@ class PaperCheckstyleTest { @Test fun testPluginApplication(@TempDir tmpDir: Path) { val project = setupProject(tmpDir) - project.pluginManager.apply("io.papermc.paperweight.paper-checkstyle") + project.pluginManager.apply("io.canvasmc.weaver.paper-checkstyle") assertNotNull(project.plugins.getPlugin(PaperCheckstylePlugin::class)) assertNotNull(project.extensions.getByType(CheckstyleExtension::class)) diff --git a/paperweight-core/src/test/kotlin/io/papermc/paperweight/core/tasks/patching/ApplyFilePatchesTest.kt b/paperweight-core/src/test/kotlin/io/papermc/paperweight/core/tasks/patching/ApplyFilePatchesTest.kt index 4d9379152..fe490b605 100644 --- a/paperweight-core/src/test/kotlin/io/papermc/paperweight/core/tasks/patching/ApplyFilePatchesTest.kt +++ b/paperweight-core/src/test/kotlin/io/papermc/paperweight/core/tasks/patching/ApplyFilePatchesTest.kt @@ -30,12 +30,17 @@ import org.gradle.kotlin.dsl.* import org.junit.jupiter.api.io.TempDir class ApplyFilePatchesTest : TaskTest() { - private lateinit var task: ApplyFilePatches + private lateinit var task: ApplyBasePatches + private lateinit var task2: ApplyFilePatches @BeforeTest fun setup() { val project = setupProject() - task = project.tasks.register("applyPatches", ApplyFilePatches::class).get() + task = project.tasks.register("applyBasePatches", ApplyBasePatches::class).get() + task2 = project.tasks.register("applyPatches", ApplyFilePatches::class) { + dependsOn(task) + } + .get() } @Test @@ -51,11 +56,16 @@ class ApplyFilePatchesTest : TaskTest() { task.input.set(input) task.output.set(output) - task.patches.set(patches) - task.verbose.set(true) task.identifier.set("test") + task2.input.set(task.output) + task2.output.set(output) + task2.patches.set(patches) + task2.verbose.set(true) + task2.identifier.set("test") + task.run() + task2.run() val testOutput = testResource.resolve("output") compareDir(tempDir, testOutput, "source") diff --git a/paperweight-core/src/test/kotlin/io/papermc/paperweight/core/tasks/patching/RebuildFilePatchesTest.kt b/paperweight-core/src/test/kotlin/io/papermc/paperweight/core/tasks/patching/RebuildFilePatchesTest.kt index dcc491c59..34de497c4 100644 --- a/paperweight-core/src/test/kotlin/io/papermc/paperweight/core/tasks/patching/RebuildFilePatchesTest.kt +++ b/paperweight-core/src/test/kotlin/io/papermc/paperweight/core/tasks/patching/RebuildFilePatchesTest.kt @@ -59,7 +59,6 @@ class RebuildFilePatchesTest : TaskTest() { 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) 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 index c3f36a48d..d74e6b99f 100644 --- a/paperweight-core/src/test/resources/functional_test/build-data/paper.at +++ b/paperweight-core/src/test/resources/functional_test/build-data/paper.at @@ -1,3 +1,5 @@ # This file is auto generated, any changes may be overridden! # See CONTRIBUTING.md on how to add access transformers. public net.minecraft.core.Rotations y +public net.minecraft.CrashReport uncategorizedStackTrace +public-f net.minecraft.CrashReport systemReport diff --git a/paperweight-core/src/test/resources/functional_test/fake-patches/base/0001-Test-Base.patch b/paperweight-core/src/test/resources/functional_test/fake-patches/base/0001-Test-Base.patch new file mode 100644 index 000000000..2946588c8 --- /dev/null +++ b/paperweight-core/src/test/resources/functional_test/fake-patches/base/0001-Test-Base.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] Test Base + + +diff --git a/Test.java b/Test.java +index 1f7aa5bc6212dec883505d3672b6a108a785dd47..bf731c042bf7f59b60378df1d61302e1769a6a77 100644 +--- a/Test.java ++++ b/Test.java +@@ -7,7 +7,7 @@ public class Test { + } + + public String getTest() { +- return this.test; ++ return this.test; // WOOOO + } + + public final String getTest2() { 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 index 7d91209a3..a2cdcaa92 100644 --- 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 @@ -5,7 +5,7 @@ Subject: [PATCH] Feature diff --git a/Test.java b/Test.java -index 51f6794c111f68e72cc4054c01f0c8896afaf292..d047a159f76d162bc24b030a575252202e57080c 100644 +index ec4473011075a4028645a320ed777c8adce0f77d..55fb66e3462ad6acfb7054f416f07d142672b92c 100644 --- a/Test.java +++ b/Test.java @@ -13,4 +13,8 @@ public class Test { diff --git a/paperweight-core/src/test/resources/functional_test/fake-patches/expected/0001-Test-Base.patch b/paperweight-core/src/test/resources/functional_test/fake-patches/expected/0001-Test-Base.patch new file mode 100644 index 000000000..2946588c8 --- /dev/null +++ b/paperweight-core/src/test/resources/functional_test/fake-patches/expected/0001-Test-Base.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] Test Base + + +diff --git a/Test.java b/Test.java +index 1f7aa5bc6212dec883505d3672b6a108a785dd47..bf731c042bf7f59b60378df1d61302e1769a6a77 100644 +--- a/Test.java ++++ b/Test.java +@@ -7,7 +7,7 @@ public class Test { + } + + public String getTest() { +- return this.test; ++ return this.test; // WOOOO + } + + public final String getTest2() { 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 index fff1639a2..08ab79fc2 100644 --- 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 @@ -4,8 +4,8 @@ } public String getTest() { -- return this.test; -+ return this.test; // WOOOO +- return this.test; // WOOOO ++ return this.test; // WOOOO SOURCE } public String getTest2() { 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 index 8ca08d047..30383a12d 100644 --- 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 @@ -5,7 +5,7 @@ Subject: [PATCH] Feature diff --git a/Test.java b/Test.java -index 418548ec7dd11e57f0838d1dae048b99a2669ea3..95266c0cad0b100367ca840d286b7a004b93f4ef 100644 +index b5106a3b36987dfdd5141ae1cbd229e6db020cd9..804b0637acd5e86e420dbaa11559ca9f3017281b 100644 --- a/Test.java +++ b/Test.java @@ -13,4 +13,8 @@ public class Test { 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 index a524a2f10..492f2f93a 100644 --- 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 @@ -4,8 +4,8 @@ } public String getTest() { -- return this.test; -+ return this.test; // WOOOO +- return this.test; // WOOOO ++ return this.test; // WOOOO SOURCE } public final String getTest2() { 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 index a2065f984..19bf3b4cc 100644 --- a/paperweight-core/src/test/resources/functional_test/test-server/build.gradle +++ b/paperweight-core/src/test/resources/functional_test/test-server/build.gradle @@ -1,6 +1,6 @@ plugins { id "java" - id 'io.papermc.paperweight.core' + id 'io.canvasmc.weaver.core' } repositories { @@ -28,12 +28,14 @@ dependencies { } paperweight { + validateATs = false if (fake) { // use fake mojang data for testing minecraftVersion = 'fake' minecraftManifestUrl = 'file://project/../fake_mojang/version_manifest.json' paper { + basePatchDir.set(file('../fake-patches/base')) sourcePatchDir.set(file('../fake-patches/sources')) resourcePatchDir.set(file('../fake-patches/resources')) featurePatchDir.set(file('../fake-patches/features')) diff --git a/paperweight-core/src/test/resources/functional_test/test-server/patches/base/0001-Base.patch b/paperweight-core/src/test/resources/functional_test/test-server/patches/base/0001-Base.patch new file mode 100644 index 000000000..bd30c70b7 --- /dev/null +++ b/paperweight-core/src/test/resources/functional_test/test-server/patches/base/0001-Base.patch @@ -0,0 +1,19 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MiniDigger | Martin +Date: Sun, 31 Mar 2024 17:01:32 +0200 +Subject: [PATCH] Base + + +diff --git a/net/minecraft/CrashReport.java b/net/minecraft/CrashReport.java +index 01c9784075b31876a0a91e81df0ae50a42d246e3..25837ee13ac83e64c3bea23f5abf4e6dd1e39829 100644 +--- a/net/minecraft/CrashReport.java ++++ b/net/minecraft/CrashReport.java +@@ -29,7 +29,7 @@ public class CrashReport { + private @Nullable Path saveFile; + private boolean trackingStackTrace = true; + public StackTraceElement[] uncategorizedStackTrace = new StackTraceElement[0]; +- public SystemReport systemReport = new SystemReport(); ++ private SystemReport systemReport = new SystemReport(); // woooo at base test???? who knew + + public CrashReport(final String title, final Throwable t) { + this.title = title; diff --git a/paperweight-lib/build.gradle.kts b/paperweight-lib/build.gradle.kts index 99717f9a5..941c6af44 100644 --- a/paperweight-lib/build.gradle.kts +++ b/paperweight-lib/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - `config-kotlin` + id("config-kotlin") id("net.kyori.blossom") version "2.2.0" } @@ -40,15 +40,24 @@ dependencies { testImplementation(libs.mockk) } +configurations.consumable("sourcesJar") { + attributes { + attribute(Usage.USAGE_ATTRIBUTE, named(Usage.JAVA_RUNTIME)) + attribute(Category.CATEGORY_ATTRIBUTE, named(Category.DOCUMENTATION)) + attribute(DocsType.DOCS_TYPE_ATTRIBUTE, named(DocsType.SOURCES)) + } + outgoing.artifact(tasks.sourcesJar) +} + val testClassesJar = tasks.register("testClassesJar") { archiveClassifier.set("test-classes") - from(sourceSets.test.get().output.classesDirs) + from(sourceSets.test.map { it.output.classesDirs }) dependsOn(sourceSets.test.get().classesTaskName) } configurations.consumable("testClassesJar") { attributes { - attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME)) - attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.JAR)) + attribute(Usage.USAGE_ATTRIBUTE, named(Usage.JAVA_RUNTIME)) + attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, named(LibraryElements.JAR)) } outgoing.artifact(testClassesJar) } diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/GitMutationLockService.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/GitMutationLockService.kt new file mode 100644 index 000000000..46051e7b0 --- /dev/null +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/GitMutationLockService.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 + +import org.gradle.api.services.BuildService +import org.gradle.api.services.BuildServiceParameters + +abstract class GitMutationLockService : BuildService diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/CollectATsFromPatches.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/CollectATsFromPatches.kt index 2bccdafd8..714d9e435 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/CollectATsFromPatches.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/CollectATsFromPatches.kt @@ -45,7 +45,11 @@ abstract class CollectATsFromPatches : BaseTask() { @get:InputDirectory @get:Optional - abstract val patchDir: DirectoryProperty + abstract val basePatchDir: DirectoryProperty + + @get:InputDirectory + @get:Optional + abstract val featurePatchDir: DirectoryProperty @get:InputDirectory @get:Optional @@ -63,7 +67,10 @@ abstract class CollectATsFromPatches : BaseTask() { fun run() { outputFile.path.deleteForcefully() val patches = mutableListOf() - patchDir.orNull?.let { + basePatchDir.orNull?.let { + patches += it.path.listDirectoryEntries("*.patch") + } + featurePatchDir.orNull?.let { patches += it.path.listDirectoryEntries("*.patch") } extraPatchDir.orNull?.let { diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/GenerateDevBundle.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/GenerateDevBundle.kt index e4c40f642..d32e52837 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/GenerateDevBundle.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/GenerateDevBundle.kt @@ -22,8 +22,10 @@ package io.papermc.paperweight.tasks -import codechicken.diffpatch.cli.DiffOperation -import codechicken.diffpatch.util.LogLevel +import io.codechicken.diffpatch.cli.DiffOperation +import io.codechicken.diffpatch.util.Input as DiffInput +import io.codechicken.diffpatch.util.LogLevel +import io.codechicken.diffpatch.util.Output as DiffOutput import io.papermc.paperweight.util.* import io.papermc.paperweight.util.constants.* import java.io.PrintStream @@ -160,9 +162,9 @@ abstract class GenerateDevBundle : BaseTask() { PrintStream(logFile.toFile(), Charsets.UTF_8).use { logOut -> DiffOperation.builder() .logTo(logOut) - .aPath(a) - .bPath(b) - .outputPath(patchOut, null) + .baseInput(DiffInput.MultiInput.folder(a)) + .changedInput(DiffInput.MultiInput.folder(b)) + .patchesOutput(DiffOutput.MultiOutput.folder(patchOut)) .autoHeader(true) .level(LogLevel.ALL) .lineEnding("\n") diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/RebuildBaseGitPatches.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/RebuildBaseGitPatches.kt new file mode 100644 index 000000000..8de250ff2 --- /dev/null +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/tasks/RebuildBaseGitPatches.kt @@ -0,0 +1,185 @@ +/* + * 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.nio.file.Path +import java.util.concurrent.ConcurrentLinkedQueue +import java.util.concurrent.Executors +import java.util.concurrent.Future +import javax.inject.Inject +import kotlin.io.path.* +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.provider.Property +import org.gradle.api.provider.ProviderFactory +import org.gradle.api.tasks.* + +@UntrackedTask(because = "RebuildBaseGitPatches should always run when requested") +abstract class RebuildBaseGitPatches : ControllableOutputTask() { + + @get:InputDirectory + abstract val inputDir: DirectoryProperty + + @get:Input + abstract val baseRef: Property + + @get:Input + abstract val stopRef: Property + + @get:OutputDirectory + abstract val patchDir: DirectoryProperty + + @get:Input + abstract val filterPatches: Property + + @get:Inject + abstract val providers: ProviderFactory + + @get:Input + abstract val identifier: Property + + override fun init() { + printOutput.convention(true) + filterPatches.convention( + providers.gradleProperty("paperweight.filter-patches") + .map { it.toBoolean() } + .orElse(true) + ) + } + + @TaskAction + fun run() { + val git = Git(inputDir.path) + // single or null commit, since if its more than that it means the repo state is corrupted and we can't rebuild safely + val basepatchesCommit = getCommitByIdentifier(git, identifier, "Base", "singleOrNull") + val commitNumber = basepatchesCommit.size + + // we update the tag to reflect the new repo state + if (commitNumber == 1) { + git("tag", "-f", "basepatches", basepatchesCommit.joinToString()).executeSilently(silenceErr = true) + } + + val what = inputDir.path.name + val patchFolder = patchDir.path + if (!patchFolder.exists()) { + patchFolder.createDirectories() + } + + if (printOutput.get()) { + logger.lifecycle("Formatting patches for $what...") + } + + if (inputDir.path.resolve(".git/rebase-apply").exists()) { + // in middle of a rebase, be smarter + if (printOutput.get()) { + logger.lifecycle("REBASE DETECTED - PARTIAL SAVE") + val last = inputDir.path.resolve(".git/rebase-apply/last").readText().trim().toInt() + val next = inputDir.path.resolve(".git/rebase-apply/next").readText().trim().toInt() + val orderedFiles = patchFolder.useDirectoryEntries("*.patch") { it.toMutableList() } + orderedFiles.sort() + + for (i in 1..last) { + if (i < next) { + orderedFiles[i].deleteForcefully() + } + } + } + } else { + patchFolder.deleteRecursive() + patchFolder.createDirectories() + } + + val base = baseRef.get() + val stop = if (commitNumber == 1) stopRef.get() else "HEAD" // HEAD if null commit + val commitCount = git("rev-list", "--count", "$base..$stop").getText().trim().toInt() + + if (commitCount <= 0) return // nothing to rebuild + + val range = "$base..$stop" + git("fetch", "--all", "--prune", "--no-prune-tags").runSilently(silenceErr = true) + git( + "format-patch", + "--diff-algorithm=myers", "--zero-commit", "--full-index", "--no-signature", "--no-stat", "-N", + "-o", patchFolder.absolutePathString(), + range + ).executeSilently() + val patchDirGit = Git(patchFolder) + patchDirGit("add", "-A", ".").executeSilently() + + if (filterPatches.get()) { + cleanupPatches(patchDirGit) + } else { + if (printOutput.get()) { + val saved = patchFolder.listDirectoryEntries("*.patch").size + + logger.lifecycle("Saved $saved patches for $what to ${layout.projectDirectory.path.relativize(patchFolder)}/") + } + } + } + + private fun cleanupPatches(git: Git) { + val patchFiles = patchDir.path.useDirectoryEntries("*.patch") { it.toMutableList() } + if (patchFiles.isEmpty()) { + return + } + patchFiles.sort() + + val noChangesPatches = ConcurrentLinkedQueue() + val futures = mutableListOf>() + + // Calling out to git over and over again for each `git diff --staged` command is really slow from the JVM + // so to mitigate this we do it parallel + val executor = Executors.newWorkStealingPool() + try { + for (patch in patchFiles) { + futures += executor.submit { + val hasNoChanges = git("diff", "--diff-algorithm=myers", "--staged", patch.name).getText().lineSequence() + .filter { it.startsWith('+') || it.startsWith('-') } + .filterNot { it.startsWith("+++") || it.startsWith("---") } + .all { it.startsWith("+index") || it.startsWith("-index") } + + if (hasNoChanges) { + noChangesPatches.add(patch) + } + } + } + + futures.forEach { it.get() } + } finally { + executor.shutdownNow() + } + + if (noChangesPatches.isNotEmpty()) { + for (chunk in noChangesPatches.chunked(50)) { + git("reset", "HEAD", *chunk.map { it.name }.toTypedArray()).executeSilently() + git("checkout", "--", *chunk.map { it.name }.toTypedArray()).executeSilently() + } + } + + if (printOutput.get()) { + val saved = patchFiles.size - noChangesPatches.size + val relDir = layout.projectDirectory.path.relativize(patchDir.path) + logger.lifecycle("Saved modified patches ($saved/${patchFiles.size}) for ${inputDir.path.name} to $relDir/") + } + } +} 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 d8788d5e1..9566282b3 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 @@ -23,6 +23,7 @@ package io.papermc.paperweight.util.constants import org.gradle.api.Task +import org.gradle.api.attributes.Attribute const val PAPERWEIGHT_EXTENSION = "paperweight" const val PAPER_CHECKSTYLE_EXTENSION = "paperCheckstyle" @@ -34,6 +35,10 @@ const val MC_LIBRARY_URL = "https://libraries.minecraft.net/" const val MC_MANIFEST_URL = "https://piston-meta.mojang.com/mc/game/version_manifest_v2.json" +const val CANVAS_MAVEN_REPO_URL = "https://maven.canvasmc.io/public" + +const val CANVAS_MAVEN_RELEASES_REPO_URL = "https://maven.canvasmc.io/releases" + const val PAPER_MAVEN_REPO_URL = "https://repo.papermc.io/repository/maven-public/" const val MAVEN_CENTRAL_URL = "https://repo.maven.apache.org/maven2/" @@ -53,19 +58,23 @@ const val MACHE_MINECRAFT_LIBRARIES_CONFIG = "macheMinecraftLibraries" const val MACHE_MINECRAFT_CONFIG = "macheMinecraft" const val MAPPED_JAR_OUTGOING_CONFIG = "mappedJarOutgoing" const val JST_CONFIG = "javaSourceTransformer" +const val JST_CLASSPATH_CONFIG = "jstClasspath" const val DEV_BUNDLE_CONFIG = "paperweightDevelopmentBundle" const val MOJANG_MAPPED_SERVER_CONFIG = "mojangMappedServer" const val MOJANG_MAPPED_SERVER_RUNTIME_CONFIG = "mojangMappedServerRuntime" const val REOBF_CONFIG = "reobf" +val JST_CLASSPATH_ATTRIBUTE = Attribute.of("io.papermc.paperweight.jst-classpath", Boolean::class.javaObjectType) + const val PARAM_MAPPINGS_REPO_NAME = "paperweightParamMappingsRepository" const val DECOMPILER_REPO_NAME = "paperweightDecompilerRepository" const val REMAPPER_REPO_NAME = "paperweightRemapperRepository" const val PLUGIN_REMAPPER_REPO_NAME = "paperweightPluginRemapperRepository" const val MACHE_REPO_NAME = "paperweightMacheRepository" +const val JST_REPO_NAME = "paperweightJstRepository" const val CACHE_PATH = "caches" -private const val PAPER_PATH = "paperweight" +const val PAPER_PATH = "paperweight" const val LOCK_DIR = "$PAPER_PATH/lock" const val USERDEV_SETUP_LOCK = "$LOCK_DIR/userdev/setup.lock" @@ -114,6 +123,7 @@ const val FINAL_REMAPPED_CODEBOOK_JAR = "$TASK_CACHE/codebook-minecraft.jar" const val FINAL_DECOMPILE_JAR = "$TASK_CACHE/decompileJar.jar" const val DOWNLOAD_SERVICE_NAME = "paperweightDownloadService" +const val GIT_MUTATION_LOCK_SERVICE_NAME = "paperweightGitMutationLockService" private const val MACHE_PATH = "$PAPER_PATH/mache" const val BASE_PROJECT = "$MACHE_PATH/base" diff --git a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/dependencies.kt b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/dependencies.kt index edcc39ac6..3001cbf1e 100644 --- a/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/dependencies.kt +++ b/paperweight-lib/src/main/kotlin/io/papermc/paperweight/util/dependencies.kt @@ -22,12 +22,17 @@ package io.papermc.paperweight.util +import org.gradle.api.NamedDomainObjectProvider import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.ModuleDependency import org.gradle.api.artifacts.repositories.RepositoryContentDescriptor +import org.gradle.api.provider.Provider data class MavenDep(val url: String, val coordinates: List) +fun determineArtifactCoordinates(configuration: NamedDomainObjectProvider): Provider> = + configuration.map { config -> determineArtifactCoordinates(config) } + fun determineArtifactCoordinates(configuration: Configuration): List { return configuration.dependencies.filterIsInstance().map { dep -> sequenceOf( 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 2fa76bdc6..474d59755 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 @@ -211,6 +211,13 @@ class Command(private val processBuilder: ProcessBuilder, private val command: S } } + fun execute(ignoreErr: Boolean) { + val res = run() + if (!ignoreErr && res != 0) { + throw PaperweightException("Command finished with $res exit code: $command") + } + } + fun executeSilently(silenceOut: Boolean = true, silenceErr: Boolean = false) { silence(silenceOut, silenceErr) execute() @@ -240,6 +247,13 @@ class Command(private val processBuilder: ProcessBuilder, private val command: S return String(out.toByteArray(), Charset.defaultCharset()) } + fun getText(ignoreErr: Boolean): String { + val out = ByteArrayOutputStream() + setup(out, out) + execute(ignoreErr) + return String(out.toByteArray(), Charset.defaultCharset()) + } + @Suppress("unused") fun readText(): String? { val out = ByteArrayOutputStream() @@ -281,3 +295,49 @@ fun checkoutRepoFromUpstream( .executeSilently(silenceErr = true) git("gc").runSilently(silenceErr = true) } + +fun getCommitsByIdentifier(git: Git, identifier: Provider, kind: String): List { + return git( + "log", + "--format=%H %s", + "--grep=^${identifier.get()} $kind Patches$", + "base..HEAD" + ).getText() + .lineSequence() + .map(String::trim) + .filter(String::isNotEmpty) + .map { it.substringBefore(" ") } + .toList() +} + +fun getCommitByIdentifier(git: Git, identifier: Provider, kind: String, validation: String): List { + val commits = getCommitsByIdentifier(git, identifier, kind) + if (validation == "single") { + validateSingleCommit(identifier, kind, commits) + } else if (validation == "singleOrNull") { + validateSingleOrNullCommit(identifier, kind, commits) + } else { + throw PaperweightException("Invalid commit validation strategy passed: $validation\nSupported strategies: single, singleOrNull") + } + return commits +} + +fun validateSingleOrNullCommit(identifier: Provider, kind: String, commits: List): Int { + // > 1 hack bc its possible we encountered an apply error so the marker commit wasn't generated + if (commits.size > 1) { + throw PaperweightException( + "Invalid amount of commits with the identifier: '${identifier.get()} $kind Patches'!\n" + + "Got ${commits.size} commits, expected: ≤1" + ) + } + return commits.size +} + +fun validateSingleCommit(identifier: Provider, kind: String, commits: List) { + if (commits.size != 1) { + throw PaperweightException( + "Invalid amount of commits with the identifier: '${identifier.get()} $kind Patches'!\n" + + "Got ${commits.size} commits, expected: 1" + ) + } +} 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 ad0d5c825..053357b58 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 @@ -26,6 +26,7 @@ import com.github.salomonbrys.kotson.fromJson import com.google.gson.* import dev.denwav.hypo.model.ClassProviderRoot import io.papermc.paperweight.DownloadService +import io.papermc.paperweight.GitMutationLockService import io.papermc.paperweight.PaperweightException import io.papermc.paperweight.tasks.* import io.papermc.paperweight.util.constants.* @@ -70,6 +71,7 @@ import org.gradle.api.logging.LogLevel import org.gradle.api.logging.Logging import org.gradle.api.model.ObjectFactory import org.gradle.api.plugins.JavaPluginExtension +import org.gradle.api.project.IsolatedProject import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.provider.ProviderFactory @@ -100,8 +102,13 @@ inline fun Gson.fromJson(any: Any): T = when (any) { val ProjectLayout.cache: Path get() = projectDirectory.dir(".gradle/$CACHE_PATH").path +val IsolatedProject.cache: Path + get() = projectDirectory.dir(".gradle/$CACHE_PATH").path + fun ProjectLayout.cacheDir(path: String) = projectDirectory.dir(".gradle/$CACHE_PATH").dir(path) +fun IsolatedProject.cacheDir(path: String) = projectDirectory.dir(".gradle/$CACHE_PATH").dir(path) + fun Project.offlineMode(): Boolean = gradle.startParameter.isOffline fun Provider.fileExists(): Provider { @@ -110,7 +117,14 @@ fun Provider.fileExists(): Provider { @Suppress("UNCHECKED_CAST") val Project.download: Provider - get() = gradle.sharedServices.registrations.getByName(DOWNLOAD_SERVICE_NAME).service as Provider + get() = gradle.sharedServices.registerIfAbsent(DOWNLOAD_SERVICE_NAME, DownloadService::class) { + parameters.projectPath.set(isolated.projectDirectory) + } + +val Project.gitMutationLockService: Provider + get() = gradle.sharedServices.registerIfAbsent(GIT_MUTATION_LOCK_SERVICE_NAME, GitMutationLockService::class) { + maxParallelUsages.set(1) + } fun commentRegex(): Regex { return Regex("\\s*#.*") @@ -472,7 +486,7 @@ inline fun ObjectFactory.providerSet( fun Project.upstreamsDirectory(): Provider { val workDirProp = providers.gradleProperty(UPSTREAM_WORK_DIR_PROPERTY) val workDirFromProp = layout.dir(workDirProp.map { File(it) }) - return workDirFromProp.orElse(rootProject.layout.cacheDir(UPSTREAMS)) + return workDirFromProp.orElse(isolated.rootProject.cacheDir(UPSTREAMS)) } private val ioDispatcherCount = AtomicInteger(0) diff --git a/paperweight-userdev/build.gradle.kts b/paperweight-userdev/build.gradle.kts index 391576bed..51293a3cf 100644 --- a/paperweight-userdev/build.gradle.kts +++ b/paperweight-userdev/build.gradle.kts @@ -1,6 +1,6 @@ plugins { - `config-kotlin` - `config-publish` + id("config-kotlin") + id("config-publish") } dependencies { 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 e993323c2..8f0d1485e 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 @@ -88,7 +88,7 @@ abstract class PaperweightUser : Plugin { group = GENERAL_TASK_GROUP description = "Delete the project-local paperweight-userdev setup cache." delete(target.layout.cache) - delete(target.rootProject.layout.cache.resolve("paperweight-userdev")) + delete(target.isolated.rootProject.cache.resolve("paperweight-userdev")) } val cleanAll = target.tasks.register("cleanAllPaperweightUserdevCaches") { group = GENERAL_TASK_GROUP @@ -125,7 +125,7 @@ abstract class PaperweightUser : Plugin { target.dependencyFactory, ) - createConfigurations(target, target.provider { userdevSetup }, setupTask) + createConfigurations(target, target.provider { userdevSetup }, setupTask, userdev) val reobfJar = target.tasks.register("reobfJar") { group = GENERAL_TASK_GROUP @@ -178,6 +178,15 @@ abstract class PaperweightUser : Plugin { } } + if (userdev.injectCanvasRepositories.get()) { + repositories.maven(CANVAS_MAVEN_RELEASES_REPO_URL) { + content { onlyForConfigurations(DEV_BUNDLE_CONFIG) } + } + repositories.maven(CANVAS_MAVEN_REPO_URL) { + content { onlyForConfigurations(DEV_BUNDLE_CONFIG) } + } + } + if (userdev.applyJunitExclusionRule.get()) { applyJunitExclusionRule() } @@ -198,7 +207,7 @@ abstract class PaperweightUser : Plugin { userdevSetup.afterEvaluate(createContext(this, setupTask)) userdev.addServerDependencyTo.get().forEach { - it.extendsFrom(configurations.getByName(MOJANG_MAPPED_SERVER_CONFIG)) + it.extendsFrom(configurations.named(MOJANG_MAPPED_SERVER_CONFIG)) } // Clean v1 shared caches @@ -288,7 +297,7 @@ abstract class PaperweightUser : Plugin { if (hasDevBundle.isFailure || !hasDevBundle.getOrThrow()) { val message = "Unable to resolve a dev bundle, which is required for paperweight to function.\n" + "Add a dev bundle to the 'paperweightDevelopmentBundle' configuration (the dependencies.paperweight extension can" + - " help with this), and ensure there is a repository to resolve it from (the Paper repository is used by default)." + " help with this), and ensure there is a repository to resolve it from (the Paper and Canvas repositories are used by default)." val ex = PaperweightException(message, hasDevBundle.exceptionOrNull()) throw ex /* TODO migrate this to the Problems API when it comes out of incubating @@ -297,7 +306,7 @@ abstract class PaperweightUser : Plugin { id("paperweight-userdev-cannot-resolve-dev-bundle", message) solution( "Add a dev bundle to the 'paperweightDevelopmentBundle' configuration (the dependencies.paperweight extension can" + - " help with this), and ensure there is a repository to resolve it from (the Paper repository is used by default)." + " help with this), and ensure there is a repository to resolve it from (the Paper and Canvas repositories are used by default)." ) withException(ex) } @@ -323,6 +332,7 @@ abstract class PaperweightUser : Plugin { target: Project, userdevSetup: Provider, setupTask: TaskProvider, + userdev: PaperweightUserExtension, ) { target.configurations.register(MACHE_CONFIG) { dependenciesFrom { userdevSetup.get().mache } @@ -354,14 +364,14 @@ abstract class PaperweightUser : Plugin { target.configurations.register(MOJANG_MAPPED_SERVER_CONFIG) { defaultDependencies { userdevSetup.get() - .populateCompileConfiguration(createContext(target, setupTask), this) + .populateCompileConfiguration(createContext(target, setupTask), this, userdev.injectServerJar) } } target.configurations.register(MOJANG_MAPPED_SERVER_RUNTIME_CONFIG) { defaultDependencies { userdevSetup.get() - .populateRuntimeConfiguration(createContext(target, setupTask), this) + .populateRuntimeConfiguration(createContext(target, setupTask), this, userdev.injectServerJar) } } } @@ -374,7 +384,7 @@ abstract class PaperweightUser : Plugin { val devBundleZip = bundleConfig.map { it.singleFile }.convertToPath() val bundleHash = devBundleZip.sha256asHex() val cacheDir = if (!target.sharedCaches) { - target.rootProject.layout.cache.resolve("paperweight-userdev/v2/work") + target.isolated.rootProject.cache.resolve("paperweight-userdev/v2/work") } else { target.gradle.gradleUserHomeDir.toPath().resolve("caches/paperweight-userdev/v2/work") } diff --git a/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/PaperweightUserDependenciesExtension.kt b/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/PaperweightUserDependenciesExtension.kt index 702a339ea..cb14e43bd 100644 --- a/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/PaperweightUserDependenciesExtension.kt +++ b/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/PaperweightUserDependenciesExtension.kt @@ -85,6 +85,30 @@ abstract class PaperweightUserDependenciesExtension @Inject constructor( return dep } + /** + * Adds a dependency on Canvas's dev bundle to the dev bundle [org.gradle.api.artifacts.Configuration]. + * + * @param version dependency version + * @param group dependency group + * @param artifactId dependency artifactId + * @param devBundleConfigurationName name of the dev bundle [org.gradle.api.artifacts.Configuration] + * @param configurationAction action configuring the dependency + * @return dependency + */ + @JvmOverloads + fun canvasDevBundle( + version: String? = null, + group: String = "io.canvasmc.canvas", + artifactId: String = "dev-bundle", + devBundleConfigurationName: String = DEV_BUNDLE_CONFIG, + configurationAction: Action = nullAction() + ): ExternalModuleDependency { + val dep = dependencyFactory.create(buildDependencyString(group, artifactId, version)) + configurationAction(dep) + dependencies.add(devBundleConfigurationName, dep) + return dep + } + /** * Adds a dependency to the dev bundle [org.gradle.api.artifacts.Configuration]. * @@ -157,6 +181,43 @@ abstract class PaperweightUserDependenciesExtension @Inject constructor( dependencies.addProvider(DEV_BUNDLE_CONFIG, version.map { "dev.folia:dev-bundle:$it" }, configurationAction) } + /** + * Adds a dependency on the Canvas dev bundle to the [DEV_BUNDLE_CONFIG] configuration. + * + * Intended for use with Gradle version catalogs. + * + * @param version version provider + * @param configurationAction action configuring the dependency + */ + @JvmOverloads + fun canvasDevBundle( + version: Provider, + configurationAction: Action = nullAction() + ) { + dependencies.addProvider(DEV_BUNDLE_CONFIG, version.map { "io.canvasmc.canvas:dev-bundle:$it" }, configurationAction) + } + + /** + * Creates a Canvas dev bundle dependency without adding it to any configurations. + * + * @param version dependency version + * @param group dependency group + * @param artifactId dependency artifactId + * @param configurationAction action configuring the dependency + * @return dependency + */ + @JvmOverloads + fun canvasDevBundleDependency( + version: String? = null, + group: String = "io.canvasmc.canvas", + artifactId: String = "dev-bundle", + configurationAction: Action = nullAction() + ): ExternalModuleDependency { + val dep = dependencyFactory.create(buildDependencyString(group, artifactId, version)) + configurationAction(dep) + return dep + } + /** * Creates a Folia dev bundle dependency without adding it to any configurations. * diff --git a/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/PaperweightUserExtension.kt b/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/PaperweightUserExtension.kt index 44684cb90..7bbc4ac68 100644 --- a/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/PaperweightUserExtension.kt +++ b/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/PaperweightUserExtension.kt @@ -49,6 +49,13 @@ abstract class PaperweightUserExtension( */ val injectPaperRepository: Property = objects.property().convention(true) + /** + * Whether to inject the Canvas maven repositories for use by the dev bundle configuration. + * + * True by default to allow easily resolving Canvas development bundles. + */ + val injectCanvasRepositories: Property = objects.property().convention(true) + /** * Configurations to add the Minecraft server dependency to. */ @@ -59,6 +66,13 @@ abstract class PaperweightUserExtension( ) ) + /** + * Whether to inject the server jar into the generated compile/runtime configurations + * + * True by defaults. + */ + val injectServerJar: Property = objects.property().convention(true) + /** * Whether to patch dependencies to exclude `junit:junit` from the transitive dependencies of `com.googlecode.json-simple:json-simple`. * diff --git a/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/SetupHandler.kt b/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/SetupHandler.kt index 5e8a6ff73..1eae1c233 100644 --- a/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/SetupHandler.kt +++ b/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/SetupHandler.kt @@ -39,6 +39,8 @@ import org.gradle.api.artifacts.dsl.DependencyFactory import org.gradle.api.file.FileCollection import org.gradle.api.file.ProjectLayout import org.gradle.api.logging.Logger +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider import org.gradle.api.tasks.TaskProvider import org.gradle.internal.logging.progress.ProgressLogger import org.gradle.internal.logging.progress.ProgressLoggerFactory @@ -48,9 +50,9 @@ import org.gradle.kotlin.dsl.* import org.gradle.workers.WorkerExecutor interface SetupHandler { - fun populateCompileConfiguration(context: ConfigurationContext, dependencySet: DependencySet) + fun populateCompileConfiguration(context: ConfigurationContext, dependencySet: DependencySet, injectServerJar: Property) - fun populateRuntimeConfiguration(context: ConfigurationContext, dependencySet: DependencySet) + fun populateRuntimeConfiguration(context: ConfigurationContext, dependencySet: DependencySet, injectServerJar: Property) data class ArtifactsResult( val mainOutput: Path, @@ -96,7 +98,7 @@ interface SetupHandler { val project: Project, val dependencyFactory: DependencyFactory, val javaToolchainService: JavaToolchainService, - val devBundleCoordinates: String, + val devBundleCoordinates: Provider, val setupTask: TaskProvider, val layout: ProjectLayout = project.layout, ) { @@ -109,7 +111,7 @@ interface SetupHandler { project, dependencyFactory, javaToolchainService, - determineArtifactCoordinates(project.configurations.getByName(DEV_BUNDLE_CONFIG)).single(), + determineArtifactCoordinates(project.configurations.named(DEV_BUNDLE_CONFIG)).map { it.single() }, setupTask, ) } diff --git a/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/SetupHandlerImpl.kt b/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/SetupHandlerImpl.kt index f1f34c7aa..dd9da62e9 100644 --- a/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/SetupHandlerImpl.kt +++ b/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/SetupHandlerImpl.kt @@ -41,6 +41,7 @@ import io.papermc.paperweight.util.data.mache.* import java.nio.file.Path import org.gradle.api.artifacts.DependencySet import org.gradle.api.file.FileCollection +import org.gradle.api.provider.Property import org.gradle.kotlin.dsl.* class SetupHandlerImpl( @@ -144,13 +145,23 @@ class SetupHandlerImpl( return dispatcher } - override fun populateCompileConfiguration(context: SetupHandler.ConfigurationContext, dependencySet: DependencySet) { - dependencySet.add(context.dependencyFactory.create(context.layout.files(context.setupTask.flatMap { it.mappedServerJar }))) - dependencySet.add(context.dependencyFactory.create(context.devBundleCoordinates)) + override fun populateCompileConfiguration( + context: SetupHandler.ConfigurationContext, + dependencySet: DependencySet, + injectServerJar: Property + ) { + if (injectServerJar.get()) { + dependencySet.add(context.dependencyFactory.create(context.layout.files(context.setupTask.flatMap { it.mappedServerJar }))) + } + dependencySet.add(context.dependencyFactory.create(context.devBundleCoordinates.get())) } - override fun populateRuntimeConfiguration(context: SetupHandler.ConfigurationContext, dependencySet: DependencySet) { - populateCompileConfiguration(context, dependencySet) + override fun populateRuntimeConfiguration( + context: SetupHandler.ConfigurationContext, + dependencySet: DependencySet, + injectServerJar: Property + ) { + populateCompileConfiguration(context, dependencySet, injectServerJar) } @Volatile diff --git a/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/UserdevSetup.kt b/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/UserdevSetup.kt index 41154f8d1..dfc464334 100644 --- a/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/UserdevSetup.kt +++ b/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/UserdevSetup.kt @@ -66,12 +66,20 @@ abstract class UserdevSetup : BuildService, SetupHandle } // begin delegate to setup - override fun populateCompileConfiguration(context: SetupHandler.ConfigurationContext, dependencySet: DependencySet) { - setup.populateCompileConfiguration(context, dependencySet) + override fun populateCompileConfiguration( + context: SetupHandler.ConfigurationContext, + dependencySet: DependencySet, + injectServerJar: Property + ) { + setup.populateCompileConfiguration(context, dependencySet, injectServerJar) } - override fun populateRuntimeConfiguration(context: SetupHandler.ConfigurationContext, dependencySet: DependencySet) { - setup.populateRuntimeConfiguration(context, dependencySet) + override fun populateRuntimeConfiguration( + context: SetupHandler.ConfigurationContext, + dependencySet: DependencySet, + injectServerJar: Property + ) { + setup.populateRuntimeConfiguration(context, dependencySet, injectServerJar) } override fun generateArtifacts(context: SetupHandler.ExecutionContext): SetupHandler.ArtifactsResult { diff --git a/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/action/ApplyDevBundlePatchesAction.kt b/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/action/ApplyDevBundlePatchesAction.kt index ee72c6b61..7c20d009a 100644 --- a/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/action/ApplyDevBundlePatchesAction.kt +++ b/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/action/ApplyDevBundlePatchesAction.kt @@ -22,9 +22,11 @@ package io.papermc.paperweight.userdev.internal.setup.action -import codechicken.diffpatch.cli.PatchOperation -import codechicken.diffpatch.util.LogLevel -import codechicken.diffpatch.util.archiver.ArchiveFormat +import io.codechicken.diffpatch.cli.PatchOperation +import io.codechicken.diffpatch.util.Input as DiffInput +import io.codechicken.diffpatch.util.LogLevel +import io.codechicken.diffpatch.util.Output as DiffOutput +import io.codechicken.diffpatch.util.archiver.ArchiveFormat import io.papermc.paperweight.PaperweightException import io.papermc.paperweight.userdev.internal.action.FileValue import io.papermc.paperweight.userdev.internal.action.Input @@ -68,9 +70,9 @@ class ApplyDevBundlePatchesAction( .logTo(logOut) .level(LogLevel.ALL) .summary(true) - .basePath(decompiledJar.get(), ArchiveFormat.ZIP) - .patchesPath(tempPatchDir) - .outputPath(outputDir) + .baseInput(DiffInput.MultiInput.archive(ArchiveFormat.ZIP, decompiledJar.get())) + .patchesInput(DiffInput.MultiInput.folder(tempPatchDir)) + .patchedOutput(DiffOutput.MultiOutput.folder(outputDir)) .build() try { op.operate().throwOnError() diff --git a/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/action/SetupMacheSourcesAction.kt b/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/action/SetupMacheSourcesAction.kt index 018029e77..c9e98d33b 100644 --- a/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/action/SetupMacheSourcesAction.kt +++ b/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/action/SetupMacheSourcesAction.kt @@ -22,9 +22,11 @@ package io.papermc.paperweight.userdev.internal.setup.action -import codechicken.diffpatch.cli.PatchOperation -import codechicken.diffpatch.util.LogLevel -import codechicken.diffpatch.util.archiver.ArchiveFormat +import io.codechicken.diffpatch.cli.PatchOperation +import io.codechicken.diffpatch.util.Input as DiffInput +import io.codechicken.diffpatch.util.LogLevel +import io.codechicken.diffpatch.util.Output as DiffOutput +import io.codechicken.diffpatch.util.archiver.ArchiveFormat import io.papermc.paperweight.PaperweightException import io.papermc.paperweight.tasks.mache.macheDecompileJar import io.papermc.paperweight.userdev.internal.action.DirectoryValue @@ -72,9 +74,9 @@ class SetupMacheSourcesAction( val result = PrintStream(log.toFile(), Charsets.UTF_8).use { logOut -> PatchOperation.builder() .logTo(logOut) - .basePath(tempOut, ArchiveFormat.ZIP) - .outputPath(outputJar.get(), ArchiveFormat.ZIP) - .patchesPath(mache.get().singleFile.toPath(), ArchiveFormat.ZIP) + .baseInput(DiffInput.MultiInput.archive(ArchiveFormat.ZIP, tempOut)) + .patchedOutput(DiffOutput.MultiOutput.archive(ArchiveFormat.ZIP, outputJar.get())) + .patchesInput(DiffInput.MultiInput.archive(ArchiveFormat.ZIP, mache.get().singleFile.toPath())) .patchesPrefix("patches") .level(LogLevel.ALL) .summary(true) 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 34377702f..3d168a618 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 @@ -38,6 +38,7 @@ import io.papermc.paperweight.util.constants.* import java.nio.file.Path import kotlin.io.path.* import org.gradle.api.artifacts.DependencySet +import org.gradle.api.provider.Property import org.gradle.jvm.toolchain.JavaLanguageVersion import org.gradle.kotlin.dsl.* @@ -215,8 +216,14 @@ class SetupHandlerImplV2( return dispatcher } - override fun populateCompileConfiguration(context: SetupHandler.ConfigurationContext, dependencySet: DependencySet) { - dependencySet.add(context.dependencyFactory.create(context.layout.files(context.setupTask.flatMap { it.mappedServerJar }))) + override fun populateCompileConfiguration( + context: SetupHandler.ConfigurationContext, + dependencySet: DependencySet, + injectServerJar: Property + ) { + if (injectServerJar.get()) { + dependencySet.add(context.dependencyFactory.create(context.layout.files(context.setupTask.flatMap { it.mappedServerJar }))) + } listOfNotNull( bundle.config.apiCoordinates, bundle.config.mojangApiCoordinates @@ -228,7 +235,11 @@ class SetupHandlerImplV2( } } - override fun populateRuntimeConfiguration(context: SetupHandler.ConfigurationContext, dependencySet: DependencySet) { + override fun populateRuntimeConfiguration( + context: SetupHandler.ConfigurationContext, + dependencySet: DependencySet, + injectServerJar: Property + ) { dependencySet.add(context.dependencyFactory.create(context.layout.files(context.setupTask.flatMap { it.legacyPaperclipResult }))) } diff --git a/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/v5/SetupHandlerImplV5.kt b/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/v5/SetupHandlerImplV5.kt index 69cf54b60..c360a80e4 100644 --- a/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/v5/SetupHandlerImplV5.kt +++ b/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/v5/SetupHandlerImplV5.kt @@ -39,6 +39,7 @@ import io.papermc.paperweight.util.constants.* import java.nio.file.Path import kotlin.io.path.* import org.gradle.api.artifacts.DependencySet +import org.gradle.api.provider.Property import org.gradle.jvm.toolchain.JavaLanguageVersion import org.gradle.kotlin.dsl.* @@ -184,8 +185,14 @@ class SetupHandlerImplV5( return dispatcher } - override fun populateCompileConfiguration(context: SetupHandler.ConfigurationContext, dependencySet: DependencySet) { - dependencySet.add(context.dependencyFactory.create(context.layout.files(context.setupTask.flatMap { it.mappedServerJar }))) + override fun populateCompileConfiguration( + context: SetupHandler.ConfigurationContext, + dependencySet: DependencySet, + injectServerJar: Property + ) { + if (injectServerJar.get()) { + dependencySet.add(context.dependencyFactory.create(context.layout.files(context.setupTask.flatMap { it.mappedServerJar }))) + } listOfNotNull( bundle.config.apiCoordinates, bundle.config.mojangApiCoordinates @@ -197,8 +204,14 @@ class SetupHandlerImplV5( } } - override fun populateRuntimeConfiguration(context: SetupHandler.ConfigurationContext, dependencySet: DependencySet) { - dependencySet.add(context.dependencyFactory.create(context.layout.files(context.setupTask.flatMap { it.mappedServerJar }))) + override fun populateRuntimeConfiguration( + context: SetupHandler.ConfigurationContext, + dependencySet: DependencySet, + injectServerJar: Property + ) { + if (injectServerJar.get()) { + dependencySet.add(context.dependencyFactory.create(context.layout.files(context.setupTask.flatMap { it.mappedServerJar }))) + } listOfNotNull( bundle.config.apiCoordinates, bundle.config.mojangApiCoordinates diff --git a/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/v7/SetupHandlerImplV7.kt b/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/v7/SetupHandlerImplV7.kt index 4c74081dd..9840bf163 100644 --- a/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/v7/SetupHandlerImplV7.kt +++ b/paperweight-userdev/src/main/kotlin/io/papermc/paperweight/userdev/internal/setup/v7/SetupHandlerImplV7.kt @@ -45,6 +45,7 @@ import java.nio.file.Path import kotlin.io.path.* import org.gradle.api.artifacts.DependencySet import org.gradle.api.file.FileCollection +import org.gradle.api.provider.Property import org.gradle.kotlin.dsl.* class SetupHandlerImplV7( @@ -154,13 +155,23 @@ class SetupHandlerImplV7( return dispatcher } - override fun populateCompileConfiguration(context: SetupHandler.ConfigurationContext, dependencySet: DependencySet) { - dependencySet.add(context.dependencyFactory.create(context.layout.files(context.setupTask.flatMap { it.mappedServerJar }))) - dependencySet.add(context.dependencyFactory.create(context.devBundleCoordinates)) + override fun populateCompileConfiguration( + context: SetupHandler.ConfigurationContext, + dependencySet: DependencySet, + injectServerJar: Property + ) { + if (injectServerJar.get()) { + dependencySet.add(context.dependencyFactory.create(context.layout.files(context.setupTask.flatMap { it.mappedServerJar }))) + } + dependencySet.add(context.dependencyFactory.create(context.devBundleCoordinates.get())) } - override fun populateRuntimeConfiguration(context: SetupHandler.ConfigurationContext, dependencySet: DependencySet) { - populateCompileConfiguration(context, dependencySet) + override fun populateRuntimeConfiguration( + context: SetupHandler.ConfigurationContext, + dependencySet: DependencySet, + injectServerJar: Property + ) { + populateCompileConfiguration(context, dependencySet, injectServerJar) } @Volatile diff --git a/paperweight-userdev/src/test/kotlin/io/papermc/paperweight/userdev/PaperweightUserTest.kt b/paperweight-userdev/src/test/kotlin/io/papermc/paperweight/userdev/PaperweightUserTest.kt index d621ba131..5d5738f65 100644 --- a/paperweight-userdev/src/test/kotlin/io/papermc/paperweight/userdev/PaperweightUserTest.kt +++ b/paperweight-userdev/src/test/kotlin/io/papermc/paperweight/userdev/PaperweightUserTest.kt @@ -40,7 +40,7 @@ class PaperweightUserTest { @Test fun testPluginApplication(@TempDir tmpDir: Path) { val project = setupProject(tmpDir) - project.pluginManager.apply("io.papermc.paperweight.userdev") + project.pluginManager.apply("io.canvasmc.weaver.userdev") assertNotNull(project.extensions.getByType(PaperweightUserExtension::class)) assertNotNull(project.dependencies.extensions.getByType(PaperweightUserDependenciesExtension::class)) diff --git a/readme.md b/readme.md index 4945f2b35..326e8749d 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,5 @@ -## paperweight +## weaver +This is a modified paperweight version that implements `base` patches, which are feature patches that apply before per-file or feature patches in the Canvas server. `paperweight` consists of three Gradle plugins: - `paperweight-core`: Used to build Paper diff --git a/settings.gradle.kts b/settings.gradle.kts index 0b9f62eae..0d64c4099 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,8 +1,12 @@ +pluginManagement { + includeBuild("build-logic") +} + plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" } -rootProject.name = "paperweight" +rootProject.name = "weaver" include("paperweight-core", "paperweight-lib", "paperweight-userdev")