1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-01-05 15:00:29 +00:00

Various improvements to packaging

This fixes several issues I had with consuming multi-loader CC:T in
various upstream mods.

 - Include /all/ sources in the Forge/Fabric jar. Before it was just the
   common classes, and not the core or API.

 - Use some Gradle magic to remove superfluous dependencies from the POM
   file. Also make sure Cobalt and Netty are present as dependencies.

 - Start using minimize() in our shadow jar config again.
This commit is contained in:
Jonathan Coates 2022-11-17 09:26:57 +00:00
parent 8152f19b6e
commit 8d2e150f05
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
17 changed files with 227 additions and 86 deletions

View File

@ -2,10 +2,38 @@ import org.jetbrains.gradle.ext.compiler
import org.jetbrains.gradle.ext.settings
plugins {
publishing
alias(libs.plugins.taskTree)
alias(libs.plugins.githubRelease)
id("org.jetbrains.gradle.plugin.idea-ext")
id("cc-tweaked")
}
val isUnstable = project.properties["isUnstable"] == "true"
val modVersion: String by extra
val mcVersion: String by extra
githubRelease {
token(findProperty("githubApiKey") as String? ?: "")
owner.set("cc-tweaked")
repo.set("CC-Tweaked")
targetCommitish.set(cct.gitBranch)
tagName.set("v$mcVersion-$modVersion")
releaseName.set("[$mcVersion] $modVersion")
body.set(
provider {
"## " + project(":core").file("src/main/resources/data/computercraft/lua/rom/help/whatsnew.md")
.readLines()
.takeWhile { it != "Type \"help changelog\" to see the full version history." }
.joinToString("\n").trim()
},
)
prerelease.set(isUnstable)
}
tasks.publish { dependsOn(tasks.githubRelease) }
idea.project.settings.compiler.javac {
// We want ErrorProne to be present when compiling via IntelliJ, as it offers some helpful warnings
// and errors. Loop through our source sets and find the appropriate flags.

View File

@ -3,11 +3,6 @@ plugins {
`kotlin-dsl`
}
repositories {
mavenCentral()
gradlePluginPortal()
}
// Duplicated in settings.gradle.kts
repositories {
mavenCentral()

View File

@ -1,3 +1,4 @@
import cc.tweaked.gradle.CCTweakedExtension
import cc.tweaked.gradle.CCTweakedPlugin
import cc.tweaked.gradle.LicenseHeader
import com.diffplug.gradle.spotless.FormatExtension
@ -21,10 +22,7 @@ val mcVersion: String by extra
group = "cc.tweaked"
version = modVersion
base.archivesName.convention(
// TODO: Remove this (and the one below) once we've no longer got a root project!
if (project.path == rootProject.path) "cc-tweaked-$mcVersion" else "cc-tweaked-$mcVersion-${project.name}",
)
base.archivesName.convention("cc-tweaked-$mcVersion-${project.name}")
java {
toolchain {
@ -104,6 +102,8 @@ tasks.withType(JavaCompile::class.java).configureEach {
tasks.withType(AbstractArchiveTask::class.java).configureEach {
isPreserveFileTimestamps = false
isReproducibleFileOrder = true
dirMode = Integer.valueOf("755", 8)
fileMode = Integer.valueOf("664", 8)
}
tasks.jar {
@ -112,7 +112,7 @@ tasks.jar {
"Specification-Title" to "computercraft",
"Specification-Vendor" to "SquidDev",
"Specification-Version" to "1",
"Implementation-Title" to (if (project.path == rootProject.path) "cctweaked" else "cctweaked-${project.name}"),
"Implementation-Title" to "cctweaked-${project.name}",
"Implementation-Version" to modVersion,
"Implementation-Vendor" to "SquidDev",
)
@ -141,6 +141,14 @@ tasks.withType(JacocoReport::class.java).configureEach {
reports.html.required.set(true)
}
project.plugins.withType(CCTweakedPlugin::class.java) {
// Set up jacoco to read from /all/ our source directories.
val cct = project.extensions.getByType<CCTweakedExtension>()
project.tasks.named("jacocoTestReport", JacocoReport::class.java) {
for (ref in cct.sourceSets.get()) sourceDirectories.from(ref.allSource.sourceDirectories)
}
}
spotless {
encoding = StandardCharsets.UTF_8
lineEndings = LineEnding.UNIX

View File

@ -87,16 +87,17 @@ abstract class CCTweakedExtension(
init {
sourceDirectories.finalizeValueOnRead()
project.afterEvaluate { sourceDirectories.disallowChanges() }
}
/**
* Mark this project as consuming another project. Its [sourceDirectories] are added, ensuring tasks are set up
* correctly.
* Mark this project as consuming another project. Its [sourceDirectories] are added, allowing easier configuration
* of run configurations and other tasks which consume sources/classes.
*/
fun externalSources(project: Project) {
val otherCct = project.extensions.getByType(CCTweakedExtension::class.java)
for (sourceSet in otherCct.sourceSets.get()) {
sourceDirectories.add(SourceSetReference.external(sourceSet))
for (sourceSet in otherCct.sourceDirectories.get()) {
sourceDirectories.add(SourceSetReference(sourceSet.sourceSet, classes = sourceSet.classes, external = true))
}
}

View File

@ -2,27 +2,20 @@ package cc.tweaked.gradle
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.testing.jacoco.tasks.JacocoReport
/**
* Configures projects to match a shared configuration.
*/
class CCTweakedPlugin : Plugin<Project> {
override fun apply(project: Project) {
val sourceSets = project.extensions.getByType(SourceSetContainer::class.java)
val cct = project.extensions.create("cct", CCTweakedExtension::class.java)
cct.sourceDirectories.add(SourceSetReference.internal(sourceSets.getByName("main")))
project.afterEvaluate {
cct.sourceDirectories.disallowChanges()
}
// Set up jacoco to read from /all/ our source directories.
project.tasks.named("jacocoTestReport", JacocoReport::class.java) {
for (ref in cct.sourceSets.get()) sourceDirectories.from(ref.allSource.sourceDirectories)
project.plugins.withType(JavaPlugin::class.java) {
val sourceSets = project.extensions.getByType(JavaPluginExtension::class.java).sourceSets
cct.sourceDirectories.add(SourceSetReference.internal(sourceSets.getByName("main")))
}
}

View File

@ -1,8 +1,15 @@
package cc.tweaked.gradle
import org.gradle.api.artifacts.ResolvedDependency
import org.gradle.api.artifacts.dsl.DependencyHandler
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.specs.Spec
import org.gradle.api.tasks.JavaExec
import org.gradle.process.JavaExecSpec
/**
* Add an annotation processor to all source sets.
*/
fun DependencyHandler.annotationProcessorEverywhere(dep: Any) {
add("compileOnly", dep)
add("annotationProcessor", dep)
@ -14,6 +21,9 @@ fun DependencyHandler.annotationProcessorEverywhere(dep: Any) {
add("testAnnotationProcessor", dep)
}
/**
* A version of [JavaExecSpec.copyTo] which copies *all* properties.
*/
fun JavaExec.copyToFull(spec: JavaExec) {
copyTo(spec)
spec.classpath = classpath

View File

@ -0,0 +1,62 @@
package cc.tweaked.gradle
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.MinimalExternalModuleDependency
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.specs.Spec
/**
* A dependency in a POM file.
*/
data class MavenDependency(val groupId: String?, val artifactId: String?, val version: String?, val scope: String?)
/**
* A spec specifying which dependencies to include/exclude.
*/
class MavenDependencySpec {
private val excludeSpecs = mutableListOf<Spec<MavenDependency>>()
fun exclude(spec: Spec<MavenDependency>) {
excludeSpecs.add(spec)
}
fun exclude(dep: Dependency) {
exclude {
(dep.group.isNullOrEmpty() || dep.group == it.groupId) &&
(dep.name.isNullOrEmpty() || dep.name == it.artifactId) &&
(dep.version.isNullOrEmpty() || dep.version == it.version)
}
}
fun exclude(dep: MinimalExternalModuleDependency) {
exclude {
dep.module.group == it.groupId && dep.module.name == it.artifactId
}
}
fun isIncluded(dep: MavenDependency) = !excludeSpecs.any { it.isSatisfiedBy(dep) }
}
/**
* Configure dependencies present in this publication's POM file.
*
* While this approach is very ugly, it's the easiest way to handle it!
*/
fun MavenPublication.mavenDependencies(action: MavenDependencySpec.() -> Unit) {
val spec = MavenDependencySpec()
action(spec)
pom.withXml {
val dependencies = XmlUtil.findChild(asNode(), "dependencies") ?: return@withXml
dependencies.children().map { it as groovy.util.Node }.forEach {
val dep = MavenDependency(
groupId = XmlUtil.findChild(it, "groupId")?.text(),
artifactId = XmlUtil.findChild(it, "artifactId")?.text(),
version = XmlUtil.findChild(it, "version")?.text(),
scope = XmlUtil.findChild(it, "scope")?.text(),
)
if (!spec.isIncluded(dep)) it.parent().remove(it)
}
}
}

View File

@ -0,0 +1,12 @@
package cc.tweaked.gradle
import groovy.util.Node
import groovy.util.NodeList
object XmlUtil {
fun findChild(node: Node, name: String): Node? = when (val child = node.get(name)) {
is Node -> child
is NodeList -> child.singleOrNull() as Node?
else -> null
}
}

View File

@ -5,7 +5,8 @@ kotlin.stdlib.default.dependency=false
kotlin.jvm.target.validation.mode=error
# Mod properties
modVersion=1.101.1
isUnstable=true
modVersion=1.102.0-SNAPSHOT
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
mcVersion=1.19.2

View File

@ -59,7 +59,7 @@ mentioning:
- `web`: This contains the additional tooling for building [the documentation website][tweaked.cc], such as support for
rendering recipes
- `build-logic` (in the base directory, not in `projects/`): This contains any build logic shared between modules. For
- `buildSrc` (in the base directory, not in `projects/`): This contains any build logic shared between modules. For
instance, `cc-tweaked.java-convention.gradle.kts` sets up the defaults for Java that we use across the whole project.
> **Note**

View File

@ -5,6 +5,7 @@
*/
package dan200.computercraft.client.sound;
import dan200.computercraft.annotations.FabricOverride;
import dan200.computercraft.annotations.ForgeOverride;
import dan200.computercraft.shared.peripheral.speaker.SpeakerPosition;
import net.minecraft.client.resources.sounds.AbstractSoundInstance;
@ -64,7 +65,12 @@ public class SpeakerSound extends AbstractSoundInstance implements TickableSound
@ForgeOverride
public CompletableFuture<AudioStream> getStream(SoundBufferLibrary soundBuffers, Sound sound, boolean looping) {
return stream != null ? CompletableFuture.completedFuture(stream) : soundBuffers.getStream(sound.getPath(), looping);
return getAudioStream(soundBuffers, sound.getPath(), looping);
}
@FabricOverride
public CompletableFuture<AudioStream> getAudioStream(SoundBufferLibrary soundBuffers, ResourceLocation sound, boolean looping) {
return stream != null ? CompletableFuture.completedFuture(stream) : soundBuffers.getStream(sound, looping);
}
public @Nullable AudioStream getStream() {

View File

@ -0,0 +1,17 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.annotations;
import java.lang.annotation.*;
/**
* Equivalent to {@link Override}, but for Fabric-specific methods.
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface FabricOverride {
}

View File

@ -1,3 +1,7 @@
# New features in CC: Tweaked 1.102.0-SNAPSHOT
No user-facing changes.
# New features in CC: Tweaked 1.101.1
Several bug fixes:

View File

@ -1,7 +1,5 @@
New features in CC: Tweaked 1.101.1
New features in CC: Tweaked 1.102.0-SNAPSHOT
Several bug fixes:
* Improve validation of rednet messages (Ale32bit)
* Fix `turtle.refuel()` always failing.
No user-facing changes.
Type "help changelog" to see the full version history.

View File

@ -1,6 +1,6 @@
plugins {
id("cc-tweaked.publishing")
id("cc-tweaked.fabric")
id("cc-tweaked.publishing")
}
val mcVersion: String by extra

View File

@ -1,11 +1,13 @@
import cc.tweaked.gradle.annotationProcessorEverywhere
import cc.tweaked.gradle.clientClasses
import cc.tweaked.gradle.commonClasses
import cc.tweaked.gradle.mavenDependencies
import net.fabricmc.loom.configuration.ide.RunConfigSettings
plugins {
id("cc-tweaked.fabric")
id("cc-tweaked.gametest")
id("cc-tweaked.publishing")
}
val modVersion: String by extra
@ -35,10 +37,15 @@ dependencies {
include(libs.nightConfig.toml)
// Pull in our other projects. See comments in MinecraftConfigurations on this nastiness.
api(commonClasses(project(":fabric-api")))
clientApi(clientClasses(project(":fabric-api")))
implementation(project(":core"))
// These are transitive deps of :core, so we don't need these deps. However, we want them to appear as runtime deps
// in our POM, and this is the easiest way.
runtimeOnly(libs.cobalt)
runtimeOnly(libs.netty.http)
compileOnly(project(":forge-stubs"))
implementation(commonClasses(project(":fabric-api")))
clientImplementation(clientClasses(project(":fabric-api")))
annotationProcessorEverywhere(libs.autoService)
@ -137,7 +144,13 @@ tasks.processResources {
}
tasks.jar {
from(allProjects.map { zipTree(it.tasks.jar.get().archiveFile) })
for (source in cct.sourceDirectories.get()) {
if (source.classes && source.external) from(source.sourceSet.output)
}
}
tasks.sourcesJar {
for (source in cct.sourceDirectories.get()) from(source.sourceSet.allSource)
}
val validateMixinNames by tasks.registering(net.fabricmc.loom.task.ValidateMixinNameTask::class) {
@ -153,3 +166,15 @@ val runGametest = tasks.named<JavaExec>("runGametest")
cct.jacoco(runGametest)
tasks.check { dependsOn(validateMixinNames, runGametest) }
tasks.withType(GenerateModuleMetadata::class).configureEach { isEnabled = false }
publishing {
publications {
named("maven", MavenPublication::class) {
mavenDependencies {
exclude(dependencies.create("cc.tweaked:"))
exclude(libs.jei.fabric.get())
}
}
}
}

View File

@ -1,6 +1,4 @@
import cc.tweaked.gradle.*
import groovy.util.Node
import groovy.util.NodeList
import net.darkhax.curseforgegradle.TaskPublishCurseForge
import net.minecraftforge.gradle.common.util.RunConfig
@ -12,7 +10,6 @@ plugins {
alias(libs.plugins.shadow)
// Publishing
alias(libs.plugins.curseForgeGradle)
alias(libs.plugins.githubRelease)
alias(libs.plugins.minotaur)
id("cc-tweaked.illuaminate")
@ -20,7 +17,7 @@ plugins {
id("cc-tweaked")
}
val isStable = true
val isUnstable = project.properties["isUnstable"] == "true"
val modVersion: String by extra
val mcVersion: String by extra
@ -41,10 +38,6 @@ minecraft {
// configureEach would be better, but we need to eagerly configure configs or otherwise the run task doesn't
// get set up properly.
all {
lazyToken("minecraft_classpath") {
configurations["shade"].copyRecursive().resolve().joinToString(File.pathSeparator) { it.absolutePath }
}
property("forge.logging.markers", "REGISTRIES")
property("forge.logging.console.level", "debug")
@ -78,7 +71,7 @@ minecraft {
}
fun RunConfig.configureForGameTest() {
val old = lazyTokens.get("minecraft_classpath")
val old = lazyTokens["minecraft_classpath"]
lazyToken("minecraft_classpath") {
// We do some terrible hacks here to basically find all things not already on the runtime classpath
// and add them. /Except/ for our source sets, as those need to load inside the Minecraft classpath.
@ -89,7 +82,9 @@ minecraft {
.filter { it.isFile && !it.name.endsWith("-test-fixtures.jar") }
.map { it.absolutePath }
.joinToString(File.pathSeparator)
if (old == null) new else old.get() + File.pathSeparator + new
val oldVal = old?.get()
if (oldVal.isNullOrEmpty()) new else oldVal + File.pathSeparator + new
}
property("cctest.sources", project(":common").file("src/testMod/resources/data/cctest").absolutePath)
@ -131,8 +126,6 @@ reobf {
}
configurations {
val shade by registering { isTransitive = false }
implementation { extendsFrom(shade.get()) }
register("cctJavadoc")
}
@ -145,11 +138,14 @@ dependencies {
libs.bundles.externalMods.forge.compile.get().map { compileOnly(fg.deobf(it)) }
libs.bundles.externalMods.forge.runtime.get().map { runtimeOnly(fg.deobf(it)) }
// Depend on our other projects. By using the api configuration, shadow jar will correctly
// preserve all files from forge-api/core-api.
api(commonClasses(project(":forge-api")))
api(clientClasses(project(":forge-api")))
implementation(project(":core"))
implementation(commonClasses(project(":forge-api")))
implementation(clientClasses(project(":forge-api")))
"shade"(libs.cobalt)
"shade"(libs.netty.http)
minecraftLibrary(libs.cobalt)
minecraftLibrary(libs.netty.http) { isTransitive = false }
testFixturesApi(libs.bundles.test)
testFixturesApi(libs.bundles.kotlin)
@ -206,19 +202,27 @@ tasks.jar {
finalizedBy("reobfJar")
archiveClassifier.set("slim")
from(allProjects.map { zipTree(it.tasks.jar.get().archiveFile) })
for (source in cct.sourceDirectories.get()) {
if (source.classes && source.external) from(source.sourceSet.output)
}
}
tasks.sourcesJar {
for (source in cct.sourceDirectories.get()) from(source.sourceSet.allSource)
}
tasks.shadowJar {
finalizedBy("reobfShadowJar")
archiveClassifier.set("")
from(allProjects.map { zipTree(it.tasks.jar.get().archiveFile) })
configurations = listOf(project.configurations["shade"])
dependencies {
include(dependency("cc.tweaked:"))
include(dependency(libs.cobalt.get()))
include(dependency(libs.netty.http.get()))
}
relocate("org.squiddev.cobalt", "cc.tweaked.internal.cobalt")
relocate("io.netty.handler", "cc.tweaked.internal.netty")
// TODO: minimize(): Would be good to support once our build scripts are stabilised.
minimize()
}
tasks.assemble { dependsOn("shadowJar") }
@ -276,7 +280,7 @@ val publishCurseForge by tasks.registering(TaskPublishCurseForge::class) {
mainFile.changelog =
"Release notes can be found on the [GitHub repository](https://github.com/cc-tweaked/CC-Tweaked/releases/tag/v$mcVersion-$modVersion)."
mainFile.changelogType = "markdown"
mainFile.releaseType = if (isStable) "release" else "alpha"
mainFile.releaseType = if (isUnstable) "alpha" else "release"
mainFile.gameVersions.add(mcVersion)
}
@ -287,7 +291,7 @@ modrinth {
projectId.set("gu7yAYhd")
versionNumber.set("$mcVersion-$modVersion")
versionName.set(modVersion)
versionType.set(if (isStable) "release" else "alpha")
versionType.set(if (isUnstable) "alpha" else "release")
uploadFile.set(tasks.shadowJar as Any)
gameVersions.add(mcVersion)
changelog.set("Release notes can be found on the [GitHub repository](https://github.com/cc-tweaked/CC-Tweaked/releases/tag/v$mcVersion-$modVersion).")
@ -297,27 +301,6 @@ modrinth {
tasks.publish { dependsOn(tasks.modrinth) }
githubRelease {
token(findProperty("githubApiKey") as String? ?: "")
owner.set("cc-tweaked")
repo.set("CC-Tweaked")
targetCommitish.set(cct.gitBranch)
tagName.set("v$mcVersion-$modVersion")
releaseName.set("[$mcVersion] $modVersion")
body.set(
provider {
"## " + file("src/main/resources/data/computercraft/lua/rom/help/whatsnew.md")
.readLines()
.takeWhile { it != "Type \"help changelog\" to see the full version history." }
.joinToString("\n").trim()
},
)
prerelease.set(!isStable)
}
tasks.publish { dependsOn(tasks.githubRelease) }
// Don't publish the slim jar
for (cfg in listOf(configurations.apiElements, configurations.runtimeElements)) {
cfg.configure { artifacts.removeIf { it.classifier == "slim" } }
@ -327,11 +310,9 @@ publishing {
publications {
named("maven", MavenPublication::class) {
fg.component(this)
// Remove all dependencies: they're shaded anyway! This is very ugly, but not found a better way :(.
pom.withXml {
for (node in asNode().get("dependencies") as NodeList) {
asNode().remove(node as Node)
}
mavenDependencies {
exclude(dependencies.create("cc.tweaked:"))
exclude(libs.jei.forge.get())
}
}
}