Skip to content

Fix kotlinx-coroutines-debug having the wrong module-info #3948

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 1 addition & 34 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ configure(subprojects.findAll { !sourceless.contains(it.name) && it.name != core

apply plugin: "bom-conventions"
apply plugin: "java-modularity-conventions"
apply plugin: "version-file-conventions"

if (build_snapshot_train) {
println "Hacking test tasks, removing stress and flaky tests"
Expand Down Expand Up @@ -252,40 +253,6 @@ configure(subprojects.findAll { !unpublished.contains(it.name) }) {
}
}
}

def thisProject = it
if (thisProject.name in sourceless) {
return
}

def versionFileTask = thisProject.tasks.register("versionFileTask") {
def name = thisProject.name.replace("-", "_")
def versionFile = thisProject.layout.buildDirectory.file("${name}.version")
it.outputs.file(versionFile)

it.doLast {
versionFile.get().asFile.text = version.toString()
}
}

List<String> jarTasks
if (isMultiplatform(it)) {
jarTasks = ["jvmJar"]
} else if (it.name == "kotlinx-coroutines-debug") {
// We shadow debug module instead of just packaging it
jarTasks = ["shadowJar"]
} else {
jarTasks = ["jar"]
}

for (name in jarTasks) {
thisProject.tasks.named(name, Jar) {
it.dependsOn versionFileTask
it.from(versionFileTask) {
into("META-INF")
}
}
}
}

// Report Kotlin compiler version when building project
Expand Down
29 changes: 29 additions & 0 deletions buildSrc/src/main/kotlin/VersionFile.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright 2016-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

import org.gradle.api.*
import org.gradle.api.tasks.*

/**
* Adds 'module_name.version' file to the project's JAR META-INF
* for the better toolability. See #2941
*/
object VersionFile {
fun registerVersionFileTask(project: Project): TaskProvider<Task> {
val versionFile = project.layout.buildDirectory.file("${project.name.replace('-', '_')}.version")
val version = project.version.toString()
return project.tasks.register("versionFileTask") {
outputs.file(versionFile)
doLast {
versionFile.get().asFile.writeText(version)
}
}
}

fun fromVersionFile(target: AbstractCopyTask, versionFileTask: TaskProvider<Task>) {
target.from(versionFileTask) {
into("META-INF")
}
}
}
17 changes: 17 additions & 0 deletions buildSrc/src/main/kotlin/version-file-conventions.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import org.gradle.api.tasks.bundling.*

configure(subprojects.filter { !unpublished.contains(it.name) && it.name !in sourceless }) {
val project = this
val jarTaskName = when {
project.name == "kotlinx-coroutines-debug" -> {
project.apply(plugin = "com.github.johnrengelman.shadow")
"shadowJar"
}
isMultiplatform -> "jvmJar"
else -> "jar"
}
val versionFileTask = VersionFile.registerVersionFileTask(project)
tasks.withType(Jar::class.java).named(jarTaskName) {
VersionFile.fromVersionFile(this, versionFileTask)
}
}
6 changes: 0 additions & 6 deletions gradle/publish.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

import org.gradle.util.VersionNumber

// Configures publishing of Maven artifacts to Maven Central

apply plugin: 'maven-publish'
Expand All @@ -15,10 +13,6 @@ def isMultiplatform = project.name == "kotlinx-coroutines-core" || project.name
def isBom = project.name == "kotlinx-coroutines-bom"

if (!isBom) {
if (project.name == "kotlinx-coroutines-debug") {
apply plugin: "com.github.johnrengelman.shadow"
}

// empty xxx-javadoc.jar
task javadocJar(type: Jar) {
archiveClassifier = 'javadoc'
Expand Down
73 changes: 0 additions & 73 deletions kotlinx-coroutines-debug/build.gradle

This file was deleted.

113 changes: 113 additions & 0 deletions kotlinx-coroutines-debug/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* Copyright 2016-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/

import com.github.jengelman.gradle.plugins.shadow.tasks.*
import java.net.*
import java.nio.file.*

plugins {
id("com.github.johnrengelman.shadow")
id("org.jetbrains.kotlinx.kover") // apply plugin to use autocomplete for Kover DSL
}

configurations {
val shadowDeps by creating
compileOnly.configure {
extendsFrom(shadowDeps)
}
runtimeOnly.configure {
extendsFrom(shadowDeps)
}
}

val junit_version by properties
val junit5_version by properties
val byte_buddy_version by properties
val blockhound_version by properties
val jna_version by properties

dependencies {
compileOnly("junit:junit:$junit_version")
compileOnly("org.junit.jupiter:junit-jupiter-api:$junit5_version")
testImplementation("org.junit.jupiter:junit-jupiter-engine:$junit5_version")
testImplementation("org.junit.platform:junit-platform-testkit:1.7.0")
add("shadowDeps", "net.bytebuddy:byte-buddy:$byte_buddy_version")
add("shadowDeps", "net.bytebuddy:byte-buddy-agent:$byte_buddy_version")
compileOnly("io.projectreactor.tools:blockhound:$blockhound_version")
testImplementation("io.projectreactor.tools:blockhound:$blockhound_version")
testImplementation("com.google.code.gson:gson:2.8.6")
api("net.java.dev.jna:jna:$jna_version")
api("net.java.dev.jna:jna-platform:$jna_version")
}

java {
/* This is needed to be able to run JUnit5 tests. Otherwise, Gradle complains that it can't find the
JVM1.6-compatible version of the `junit-jupiter-api` artifact. */
disableAutoTargetJvm()
}

// This is required for BlockHound tests to work, see https://github.com/Kotlin/kotlinx.coroutines/issues/3701
tasks.withType<Test>().configureEach {
if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_13)) {
jvmArgs("-XX:+AllowRedefinitionToAddDeleteMethods")
}
}

val jar by tasks.existing(Jar::class) {
enabled = false
}

val shadowJar by tasks.existing(ShadowJar::class) {
// Shadow only byte buddy, do not package kotlin stdlib
configurations = listOf(project.configurations["shadowDeps"])
relocate("net.bytebuddy", "kotlinx.coroutines.repackaged.net.bytebuddy")
/* These classifiers are both set to `null` to trick Gradle into thinking that this jar file is both the
artifact from the `jar` task and the one from `shadowJar`. Without this, Gradle complains that the artifact
from the `jar` task is not present when the compilaton finishes, even if the file with this name exists. */
archiveClassifier.convention(null as String?)
archiveClassifier.set(null as String?)
archiveBaseName.set(jar.flatMap { it.archiveBaseName })
archiveVersion.set(jar.flatMap { it.archiveVersion })
manifest {
attributes(
mapOf(
"Premain-Class" to "kotlinx.coroutines.debug.AgentPremain",
"Can-Redefine-Classes" to "true",
"Multi-Release" to "true"
)
)
}
// add module-info.class to the META-INF/versions/9/ directory.
dependsOn(tasks.compileModuleInfoJava)
doLast {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thumbs up for the new approach, it's much more straightforward now

// We can't do that directly with the shadowJar task because it doesn't support replacing existing files.
val zipPath = [email protected]()
val zipUri = URI.create("jar:${zipPath.toUri()}")
val moduleInfoFilePath = tasks.compileModuleInfoJava.get().outputs.files.asFileTree.matching {
include("module-info.class")
}.singleFile.toPath()
FileSystems.newFileSystem(zipUri, emptyMap<String, String>()).use { fs ->
val moduleInfoFile = fs.getPath("META-INF/versions/9/module-info.class")
Files.copy(moduleInfoFilePath, moduleInfoFile, StandardCopyOption.REPLACE_EXISTING)
}
}
}

configurations {
// shadowJar is already part of the `shadowRuntimeElements` and `shadowApiElements`, but the other subprojects
// that depend on `kotlinx-coroutines-debug` look at `runtimeElements` and `apiElements`.
artifacts {
add("apiElements", shadowJar)
add("runtimeElements", shadowJar)
}
}

koverReport {
filters {
excludes {
// Never used, safety mechanism
classes("kotlinx.coroutines.debug.internal.NoOpProbesKt")
}
}
}