Skip to content

Commit 562902b

Browse files
authored
Fix debug module publication with shadow plugin (#3357)
Fixes #3345 Fixes #3334
1 parent 8b6473d commit 562902b

File tree

4 files changed

+79
-18
lines changed

4 files changed

+79
-18
lines changed

gradle/publish.gradle

+1-5
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,7 @@ publishing {
4545
// Configure java publications for regular non-MPP modules
4646
publications {
4747
maven(MavenPublication) {
48-
if (project.name == "kotlinx-coroutines-debug") {
49-
project.shadow.component(it)
50-
} else {
51-
from components.java
52-
}
48+
from components.java
5349
artifact sourcesJar
5450
}
5551
}

integration-testing/build.gradle

+24-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ dependencies {
2323
}
2424

2525
sourceSets {
26+
// Test that relies on Guava to reflectively check all Throwable subclasses in coroutines
2627
withGuavaTest {
2728
kotlin
2829
compileClasspath += sourceSets.test.runtimeClasspath
@@ -33,6 +34,7 @@ sourceSets {
3334
implementation 'com.google.guava:guava:31.1-jre'
3435
}
3536
}
37+
// Checks correctness of Maven publication (JAR resources) and absence of atomicfu symbols
3638
mavenTest {
3739
kotlin
3840
compileClasspath += sourceSets.test.runtimeClasspath
@@ -43,6 +45,7 @@ sourceSets {
4345
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
4446
}
4547
}
48+
// Checks that kotlinx-coroutines-debug can be used as -javaagent parameter
4649
debugAgentTest {
4750
kotlin
4851
compileClasspath += sourceSets.test.runtimeClasspath
@@ -53,6 +56,20 @@ sourceSets {
5356
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-debug:$coroutines_version"
5457
}
5558
}
59+
60+
// Checks that kotlinx-coroutines-debug agent can self-attach dynamically to JVM as standalone dependency
61+
debugDynamicAgentTest {
62+
kotlin
63+
compileClasspath += sourceSets.test.runtimeClasspath
64+
runtimeClasspath += sourceSets.test.runtimeClasspath
65+
66+
dependencies {
67+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
68+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-debug:$coroutines_version"
69+
}
70+
}
71+
72+
// Checks that kotlinx-coroutines-core can be used as -javaagent parameter
5673
coreAgentTest {
5774
kotlin
5875
compileClasspath += sourceSets.test.runtimeClasspath
@@ -93,6 +110,12 @@ task debugAgentTest(type: Test) {
93110
systemProperties project.properties.subMap(["overwrite.probes"])
94111
}
95112

113+
task debugDynamicAgentTest(type: Test) {
114+
def sourceSet = sourceSets.debugDynamicAgentTest
115+
testClassesDirs = sourceSet.output.classesDirs
116+
classpath = sourceSet.runtimeClasspath
117+
}
118+
96119
task coreAgentTest(type: Test) {
97120
def sourceSet = sourceSets.coreAgentTest
98121
def coroutinesCoreJar = sourceSet.runtimeClasspath.filter {it.name == "kotlinx-coroutines-core-jvm-${coroutines_version}.jar" }.singleFile
@@ -106,5 +129,5 @@ compileTestKotlin {
106129
}
107130

108131
check {
109-
dependsOn([withGuavaTest, mavenTest, debugAgentTest, coreAgentTest, 'smokeTest:build'])
132+
dependsOn([withGuavaTest, debugDynamicAgentTest, mavenTest, debugAgentTest, coreAgentTest, 'smokeTest:build'])
110133
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright 2016-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
import org.junit.*
5+
import kotlinx.coroutines.*
6+
import kotlinx.coroutines.debug.*
7+
import org.junit.Test
8+
import java.io.*
9+
import java.lang.IllegalStateException
10+
11+
class DynamicAttachDebugTest {
12+
13+
@Test
14+
fun testAgentDumpsCoroutines() =
15+
DebugProbes.withDebugProbes {
16+
runBlocking {
17+
val baos = ByteArrayOutputStream()
18+
DebugProbes.dumpCoroutines(PrintStream(baos))
19+
// if the agent works, then dumps should contain something,
20+
// at least the fact that this test is running.
21+
Assert.assertTrue(baos.toString().contains("testAgentDumpsCoroutines"))
22+
}
23+
}
24+
25+
@Test(expected = IllegalStateException::class)
26+
fun testAgentIsNotInstalled() {
27+
DebugProbes.dumpCoroutines(PrintStream(ByteArrayOutputStream()))
28+
}
29+
}

kotlinx-coroutines-debug/build.gradle

+25-12
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,6 @@ configurations {
88
shadowDeps // shaded dependencies, not included into the resulting .pom file
99
compileOnly.extendsFrom(shadowDeps)
1010
runtimeOnly.extendsFrom(shadowDeps)
11-
12-
/*
13-
* It is possible to extend a particular configuration with shadow,
14-
* but in that case it changes dependency type to "runtime" and resolves it
15-
* (so it cannot be further modified). Otherwise, shadow just ignores all dependencies.
16-
*/
17-
shadow.extendsFrom(api) // shadow - resulting configuration with shaded jar file
18-
configureKotlinJvmPlatform(shadow)
1911
}
2012

2113
dependencies {
@@ -39,17 +31,38 @@ java {
3931
}
4032

4133
jar {
42-
manifest {
43-
attributes "Premain-Class": "kotlinx.coroutines.debug.AgentPremain"
44-
attributes "Can-Redefine-Classes": "true"
34+
setEnabled(false)
35+
}
36+
37+
// This is a rough estimation of what shadow plugin has been doing with our default configuration prior to
38+
// 1.6.2: https://github.com/johnrengelman/shadow/blob/1ff12fc816629ae5bc331fa3889c8ecfcaee7b27/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/ShadowJavaPlugin.groovy#L72-L82
39+
// We just emulate it here for backwards compatibility
40+
shadowJar.configure {
41+
def classpath = project.objects.fileCollection().from { ->
42+
project.configurations.findByName('runtimeClasspath')
43+
}
44+
doFirst {
45+
manifest.attributes 'Class-Path': classpath.collect { "${it.name}" }.findAll { it }.join(' ')
4546
}
4647
}
4748

48-
shadowJar {
49+
def shadowJarTask = shadowJar {
4950
classifier null
5051
// Shadow only byte buddy, do not package kotlin stdlib
5152
configurations = [project.configurations.shadowDeps]
5253
relocate('net.bytebuddy', 'kotlinx.coroutines.repackaged.net.bytebuddy')
54+
55+
manifest {
56+
attributes "Premain-Class": "kotlinx.coroutines.debug.AgentPremain"
57+
attributes "Can-Redefine-Classes": "true"
58+
}
59+
}
60+
61+
configurations {
62+
artifacts {
63+
add("apiElements", shadowJarTask)
64+
add("runtimeElements", shadowJarTask)
65+
}
5366
}
5467

5568
def commonKoverExcludes =

0 commit comments

Comments
 (0)