From 6b83c639916bc8657fcd08e7acf9e242b7797f50 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Mon, 29 Jan 2024 20:59:16 +0000 Subject: [PATCH] Switch to our own Gradle plugin for vanilla Minecraft I didn't make a new years resolution to stop writing build tooling, but maybe I should have. This replaces our use of VanillaGradle with a new project, VanillaExtract. This offers a couple of useful features for multi-loader dev, including Parchment and Unpick support, both of which we now use in CC:T. --- buildSrc/build.gradle.kts | 16 +-- .../main/kotlin/cc-tweaked.vanilla.gradle.kts | 16 ++- .../tweaked/gradle/MinecraftConfigurations.kt | 118 +++--------------- gradle/libs.versions.toml | 6 +- projects/common/build.gradle.kts | 8 ++ settings.gradle.kts | 8 +- 6 files changed, 56 insertions(+), 116 deletions(-) diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 8dde9f70b..fc045e0db 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -29,19 +29,19 @@ repositories { } } - maven("https://repo.spongepowered.org/repository/maven-public/") { - name = "Sponge" - content { - includeGroup("org.spongepowered") - } - } - maven("https://maven.fabricmc.net/") { name = "Fabric" content { includeGroup("net.fabricmc") } } + + maven("https://squiddev.cc/maven") { + name = "SquidDev" + content { + includeGroup("cc.tweaked.vanilla-extract") + } + } } dependencies { @@ -55,7 +55,7 @@ dependencies { implementation(libs.ideaExt) implementation(libs.librarian) implementation(libs.minotaur) - implementation(libs.vanillaGradle) + implementation(libs.vanillaExtract) } gradlePlugin { diff --git a/buildSrc/src/main/kotlin/cc-tweaked.vanilla.gradle.kts b/buildSrc/src/main/kotlin/cc-tweaked.vanilla.gradle.kts index 0a669b51c..efcc7dbf5 100644 --- a/buildSrc/src/main/kotlin/cc-tweaked.vanilla.gradle.kts +++ b/buildSrc/src/main/kotlin/cc-tweaked.vanilla.gradle.kts @@ -10,25 +10,31 @@ import cc.tweaked.gradle.MinecraftConfigurations plugins { id("cc-tweaked.java-convention") - id("org.spongepowered.gradle.vanilla") + id("cc.tweaked.vanilla-extract") } plugins.apply(CCTweakedPlugin::class.java) val mcVersion: String by extra +val libs = project.extensions.getByType().named("libs") + minecraft { version(mcVersion) + + mappings { + parchment(libs.findVersion("parchmentMc").get().toString(), libs.findVersion("parchment").get().toString()) + } + + unpick(libs.findLibrary("yarn").get()) } dependencies { - val libs = project.extensions.getByType().named("libs") - // Depend on error prone annotations to silence a lot of compile warnings. - compileOnlyApi(libs.findLibrary("errorProne.annotations").get()) + compileOnly(libs.findLibrary("errorProne.annotations").get()) } -MinecraftConfigurations.setup(project) +MinecraftConfigurations.setupBasic(project) extensions.configure(CCTweakedExtension::class.java) { linters(minecraft = true, loader = null) diff --git a/buildSrc/src/main/kotlin/cc/tweaked/gradle/MinecraftConfigurations.kt b/buildSrc/src/main/kotlin/cc/tweaked/gradle/MinecraftConfigurations.kt index 0bdb94c62..dce07bf96 100644 --- a/buildSrc/src/main/kotlin/cc/tweaked/gradle/MinecraftConfigurations.kt +++ b/buildSrc/src/main/kotlin/cc/tweaked/gradle/MinecraftConfigurations.kt @@ -4,23 +4,17 @@ package cc.tweaked.gradle +import cc.tweaked.vanillaextract.configurations.Capabilities +import cc.tweaked.vanillaextract.configurations.MinecraftSetup import org.gradle.api.Project -import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.ModuleDependency import org.gradle.api.artifacts.dsl.DependencyHandler -import org.gradle.api.attributes.Bundling -import org.gradle.api.attributes.Category -import org.gradle.api.attributes.LibraryElements -import org.gradle.api.attributes.Usage -import org.gradle.api.attributes.java.TargetJvmVersion -import org.gradle.api.capabilities.Capability import org.gradle.api.plugins.BasePlugin import org.gradle.api.plugins.JavaPluginExtension import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.bundling.Jar import org.gradle.api.tasks.javadoc.Javadoc import org.gradle.kotlin.dsl.get -import org.gradle.kotlin.dsl.named /** * This sets up a separate client-only source set, and extends that and the main/common source set with additional @@ -59,31 +53,13 @@ private fun setup() { } configurations.named(client.implementationConfigurationName) { extendsFrom(clientApi) } - /* - Now add outgoing variants for the main and common source sets that we can consume downstream. This is possibly - the worst way to do things, but unfortunately the alternatives don't actually work very well: - - - Just using source set outputs: This means dependencies don't propagate, which means when :fabric depends - on :fabric-api, we don't inherit the fake :common-api in IDEA. - - - Having separate common/main jars: Nice in principle, but unfortunately Forge needs a separate deobf jar - task (as the original jar is obfuscated), and IDEA is not able to map its output back to a source set. - - This works for now, but is incredibly brittle. It's part of the reason we can't use testFixtures inside our - MC projects, as that adds a project(self) -> test dependency, which would pull in the jar instead. - - Note we register a fake client jar here. It's not actually needed, but is there to make sure IDEA has - a way to tell that client classes are needed at runtime. - - I'm so sorry, deeply aware how cursed this is. - */ - setupOutgoing(main, "CommonOnly") project.tasks.register(client.jarTaskName, Jar::class.java) { description = "An empty jar standing in for the client classes." group = BasePlugin.BUILD_GROUP archiveClassifier.set("client") } - setupOutgoing(client) + + MinecraftSetup(project).setupOutgoingConfigurations() // Reset the client classpath (Loom configures it slightly differently to this) and add a main -> client // dependency. Here we /can/ use source set outputs as we add transitive deps by patching the classpath. Nasty, @@ -106,6 +82,12 @@ MC projects, as that adds a project(self) -> test dependency, which would pull i project.tasks.named("jar", Jar::class.java) { from(client.output) } project.tasks.named("sourcesJar", Jar::class.java) { from(client.allSource) } + setupBasic() + } + + private fun setupBasic() { + val client = sourceSets["client"] + project.extensions.configure(CCTweakedExtension::class.java) { sourceDirectories.add(SourceSetReference.internal(client)) } @@ -120,83 +102,19 @@ MC projects, as that adds a project(self) -> test dependency, which would pull i project.tasks.named("check") { dependsOn(checkDependencyConsistency) } } - private fun setupOutgoing(sourceSet: SourceSet, suffix: String = "") { - setupOutgoing("${sourceSet.apiElementsConfigurationName}$suffix", sourceSet, objects.named(Usage.JAVA_API)) { - description = "API elements for ${sourceSet.name}" - extendsFrom(configurations[sourceSet.apiConfigurationName]) - } - - setupOutgoing("${sourceSet.runtimeElementsConfigurationName}$suffix", sourceSet, objects.named(Usage.JAVA_RUNTIME)) { - description = "Runtime elements for ${sourceSet.name}" - extendsFrom(configurations[sourceSet.implementationConfigurationName], configurations[sourceSet.runtimeOnlyConfigurationName]) - } - } - - /** - * Set up an outgoing configuration for a specific source set. We set an additional "main" or "client" capability - * (depending on the source set name) which allows downstream projects to consume them separately (see - * [DependencyHandler.commonClasses] and [DependencyHandler.clientClasses]). - */ - private fun setupOutgoing(name: String, sourceSet: SourceSet, usage: Usage, configure: Configuration.() -> Unit) { - configurations.register(name) { - isVisible = false - isCanBeConsumed = true - isCanBeResolved = false - - configure(this) - - attributes { - attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY)) - attribute(Usage.USAGE_ATTRIBUTE, usage) - attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL)) - attributeProvider( - TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, - java.toolchain.languageVersion.map { it.asInt() }, - ) - attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.JAR)) - } - - outgoing { - capability(BasicOutgoingCapability(project, sourceSet.name)) - - // We have two outgoing variants here: the original jar and the classes. - artifact(project.tasks.named(sourceSet.jarTaskName)) - - variants.create("classes") { - attributes.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.CLASSES)) - sourceSet.output.classesDirs.forEach { artifact(it) { builtBy(sourceSet.output) } } - } - } - } - } - companion object { + fun setupBasic(project: Project) { + MinecraftConfigurations(project).setupBasic() + } + fun setup(project: Project) { MinecraftConfigurations(project).setup() } } } -private class BasicIncomingCapability(private val module: ModuleDependency, private val name: String) : Capability { - override fun getGroup(): String = module.group!! - override fun getName(): String = "${module.name}-$name" - override fun getVersion(): String? = null -} +fun DependencyHandler.clientClasses(notation: Any): ModuleDependency = + Capabilities.clientClasses(create(notation) as ModuleDependency) -private class BasicOutgoingCapability(private val project: Project, private val name: String) : Capability { - override fun getGroup(): String = project.group.toString() - override fun getName(): String = "${project.name}-$name" - override fun getVersion(): String = project.version.toString() -} - -fun DependencyHandler.clientClasses(notation: Any): ModuleDependency { - val dep = create(notation) as ModuleDependency - dep.capabilities { requireCapability(BasicIncomingCapability(dep, "client")) } - return dep -} - -fun DependencyHandler.commonClasses(notation: Any): ModuleDependency { - val dep = create(notation) as ModuleDependency - dep.capabilities { requireCapability(BasicIncomingCapability(dep, "main")) } - return dep -} +fun DependencyHandler.commonClasses(notation: Any): ModuleDependency = + Capabilities.commonClasses(create(notation) as ModuleDependency) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e1b53a41e..5d8b938a0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -14,6 +14,7 @@ forgeSpi = "7.0.1" mixin = "0.8.5" parchment = "2023.08.20" parchmentMc = "1.20.1" +yarn = "1.20.1+build.10" # Core dependencies (these versions are tied to the version Minecraft uses) fastutil = "8.5.9" @@ -71,7 +72,7 @@ nullAway = "0.9.9" spotless = "6.23.3" taskTree = "2.1.1" teavm = "0.10.0-SQUID.2" -vanillaGradle = "0.2.1-SNAPSHOT" +vanillaExtract = "0.1.1" versionCatalogUpdate = "0.8.1" [libraries] @@ -158,7 +159,8 @@ teavm-metaprogramming-api = { module = "org.teavm:teavm-metaprogramming-api", ve teavm-metaprogramming-impl = { module = "org.teavm:teavm-metaprogramming-impl", version.ref = "teavm" } teavm-platform = { module = "org.teavm:teavm-platform", version.ref = "teavm" } teavm-tooling = { module = "org.teavm:teavm-tooling", version.ref = "teavm" } -vanillaGradle = { module = "org.spongepowered:vanillagradle", version.ref = "vanillaGradle" } +vanillaExtract = { module = "cc.tweaked.vanilla-extract:plugin", version.ref = "vanillaExtract" } +yarn = { module = "net.fabricmc:yarn", version.ref = "yarn" } [plugins] forgeGradle = { id = "net.minecraftforge.gradle", version.ref = "forgeGradle" } diff --git a/projects/common/build.gradle.kts b/projects/common/build.gradle.kts index cdd84846e..730937dcf 100644 --- a/projects/common/build.gradle.kts +++ b/projects/common/build.gradle.kts @@ -22,6 +22,14 @@ configurations { register("cctJavadoc") } +repositories { + maven("https://maven.minecraftforge.net/") { + content { + includeModule("org.spongepowered", "mixin") + } + } +} + dependencies { // Pull in our other projects. See comments in MinecraftConfigurations on this nastiness. implementation(project(":core")) diff --git a/settings.gradle.kts b/settings.gradle.kts index ab87dd417..2b5807cc8 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -27,7 +27,6 @@ pluginManagement { name = "Sponge" content { includeGroup("org.spongepowered") - includeGroup("org.spongepowered.gradle.vanilla") } } @@ -38,6 +37,13 @@ pluginManagement { includeGroup("net.fabricmc") } } + + maven("https://squiddev.cc/maven") { + name = "SquidDev" + content { + includeGroup("cc.tweaked.vanilla-extract") + } + } } resolutionStrategy {