Fix eager Kotlin/JVM task configuration on Gradle 7.3+
^KT-54836 Fixed
This commit is contained in:
committed by
Space Team
parent
f8e6c59600
commit
2e5981eb94
+24
@@ -25,6 +25,30 @@ class ConfigurationAvoidanceIT : KGPBaseTest() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmGradlePluginTests
|
||||||
|
@GradleTestVersions(
|
||||||
|
maxVersion = TestVersions.Gradle.G_7_5,
|
||||||
|
additionalVersions = [TestVersions.Gradle.G_7_3, TestVersions.Gradle.G_7_4]
|
||||||
|
)
|
||||||
|
@DisplayName("KGP/Jvm does not eagerly configure any tasks")
|
||||||
|
@GradleTest
|
||||||
|
fun testJvmConfigurationAvoidance(gradleVersion: GradleVersion) {
|
||||||
|
project("simpleProject", gradleVersion) {
|
||||||
|
buildGradle.appendText(
|
||||||
|
"""
|
||||||
|
|
|
||||||
|
|tasks.configureEach {
|
||||||
|
| if (name != "help" && name != "clean") {
|
||||||
|
| throw new GradleException("Configuration avoidance failure for ${'$'}name!")
|
||||||
|
| }
|
||||||
|
|}
|
||||||
|
""".trimMargin()
|
||||||
|
)
|
||||||
|
|
||||||
|
build("--dry-run")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@AndroidGradlePluginTests
|
@AndroidGradlePluginTests
|
||||||
@DisplayName("Android unrelated tasks are not configured")
|
@DisplayName("Android unrelated tasks are not configured")
|
||||||
@AndroidTestVersions(minVersion = TestVersions.AGP.AGP_42)
|
@AndroidTestVersions(minVersion = TestVersions.AGP.AGP_42)
|
||||||
|
|||||||
+47
-1
@@ -9,6 +9,7 @@ import org.junit.jupiter.api.DisplayName
|
|||||||
import kotlin.io.path.appendText
|
import kotlin.io.path.appendText
|
||||||
import kotlin.io.path.createDirectories
|
import kotlin.io.path.createDirectories
|
||||||
import kotlin.io.path.createFile
|
import kotlin.io.path.createFile
|
||||||
|
import java.util.zip.ZipFile
|
||||||
|
|
||||||
@JvmGradlePluginTests
|
@JvmGradlePluginTests
|
||||||
@DisplayName("KGP simple tests")
|
@DisplayName("KGP simple tests")
|
||||||
@@ -202,7 +203,7 @@ class SimpleKotlinGradleIT : KGPBaseTest() {
|
|||||||
|
|
||||||
@GradleTest
|
@GradleTest
|
||||||
@DisplayName("Should be compatible with project isolation")
|
@DisplayName("Should be compatible with project isolation")
|
||||||
@GradleTestVersions(minVersion = TestVersions.Gradle.G_7_1, maxVersion = TestVersions.Gradle.G_7_1)
|
@GradleTestVersions(minVersion = TestVersions.Gradle.G_7_1)
|
||||||
fun testProjectIsolation(gradleVersion: GradleVersion) {
|
fun testProjectIsolation(gradleVersion: GradleVersion) {
|
||||||
project(
|
project(
|
||||||
projectName = "instantExecution",
|
projectName = "instantExecution",
|
||||||
@@ -273,4 +274,49 @@ class SimpleKotlinGradleIT : KGPBaseTest() {
|
|||||||
build("assemble")
|
build("assemble")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DisplayName("Changing compile task destination directory does not break test compilation")
|
||||||
|
@GradleTest
|
||||||
|
internal fun customDestinationDir(gradleVersion: GradleVersion) {
|
||||||
|
project("simpleProject", gradleVersion) {
|
||||||
|
//language=Groovy
|
||||||
|
buildGradle.appendText(
|
||||||
|
"""
|
||||||
|
|
|
||||||
|
|tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile.class).configureEach {
|
||||||
|
| if (it.name == "compileKotlin") {
|
||||||
|
| it.destinationDirectory.set(project.layout.buildDirectory.dir("banana"))
|
||||||
|
| }
|
||||||
|
|}
|
||||||
|
""".trimMargin()
|
||||||
|
)
|
||||||
|
|
||||||
|
build("build") {
|
||||||
|
assertFileInProjectExists("build/banana/demo/KotlinGreetingJoiner.class")
|
||||||
|
assertFileInProjectExists("build/libs/simpleProject.jar")
|
||||||
|
ZipFile(projectPath.resolve("build/libs/simpleProject.jar").toFile()).use { jar ->
|
||||||
|
assert(jar.entries().asSequence().count { it.name == "demo/KotlinGreetingJoiner.class" } == 1) {
|
||||||
|
"The jar should contain one entry `demo/KotlinGreetingJoiner.class` with no duplicates\n" +
|
||||||
|
jar.entries().asSequence().map { it.name }.joinToString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@DisplayName("Default jar content should not contain duplicates")
|
||||||
|
@GradleTest
|
||||||
|
internal fun defaultJarContent(gradleVersion: GradleVersion) {
|
||||||
|
project("simpleProject", gradleVersion) {
|
||||||
|
build("build") {
|
||||||
|
assertFileInProjectExists("build/libs/simpleProject.jar")
|
||||||
|
ZipFile(projectPath.resolve("build/libs/simpleProject.jar").toFile()).use { jar ->
|
||||||
|
assert(jar.entries().asSequence().count { it.name == "demo/KotlinGreetingJoiner.class" } == 1) {
|
||||||
|
"The jar should contain one entry `demo/KotlinGreetingJoiner.class` with no duplicates\n" +
|
||||||
|
jar.entries().asSequence().map { it.name }.joinToString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -43,6 +43,7 @@ dependencies {
|
|||||||
|
|
||||||
task integrationTestJar(type: Jar) {
|
task integrationTestJar(type: Jar) {
|
||||||
from sourceSets.integrationTest.output
|
from sourceSets.integrationTest.output
|
||||||
|
from sourceSets.integrationTest.kotlin.classesDirectory
|
||||||
classifier = 'inttests'
|
classifier = 'inttests'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -18,6 +18,6 @@ dependencies {
|
|||||||
testImplementation 'org.testng:testng:6.8'
|
testImplementation 'org.testng:testng:6.8'
|
||||||
}
|
}
|
||||||
|
|
||||||
test {
|
tasks.named("test").configure {
|
||||||
useTestNG()
|
useTestNG()
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-5
@@ -6,15 +6,17 @@ import java.util.ArrayList
|
|||||||
|
|
||||||
class KotlinGreetingJoiner(val greeter : Greeter) {
|
class KotlinGreetingJoiner(val greeter : Greeter) {
|
||||||
|
|
||||||
val names = ArrayList<String?>()
|
private val names = ArrayList<String?>()
|
||||||
|
|
||||||
fun addName(name : String?): Unit{
|
fun addName(name : String?): Unit{
|
||||||
names.add(name)
|
names.add(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getJoinedGreeting() : String? {
|
fun getJoinedGreeting() : String? {
|
||||||
val joiner = Joiner.on(" and ").skipNulls();
|
val joiner = Joiner.on(" and ").skipNulls();
|
||||||
return "${greeter.getGreeting()} ${joiner.join(names)}"
|
return "${greeter.getGreeting()} ${joiner.join(names)}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun getNames(): List<String?> = names.toList()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-4
@@ -1,10 +1,6 @@
|
|||||||
package demo
|
package demo
|
||||||
|
|
||||||
import com.google.common.primitives.Ints
|
|
||||||
import com.google.common.base.Joiner
|
|
||||||
import org.testng.Assert.*
|
import org.testng.Assert.*
|
||||||
import org.testng.annotations.AfterMethod
|
|
||||||
import org.testng.annotations.BeforeMethod
|
|
||||||
import org.testng.annotations.Test as test
|
import org.testng.annotations.Test as test
|
||||||
|
|
||||||
class TestSource() {
|
class TestSource() {
|
||||||
@@ -16,6 +12,7 @@ class TestSource() {
|
|||||||
example.addName("Hermione")
|
example.addName("Hermione")
|
||||||
|
|
||||||
assertEquals(example.getJoinedGreeting(), "Hi Harry and Ron and Hermione")
|
assertEquals(example.getJoinedGreeting(), "Hi Harry and Ron and Hermione")
|
||||||
|
assertEquals(example.getNames().size, 4)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
@@ -164,6 +164,9 @@ internal val KotlinCompilationInfo.tcsOrNull: KotlinCompilationInfo.TCS?
|
|||||||
is KotlinCompilationInfo.TCS -> this
|
is KotlinCompilationInfo.TCS -> this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal val KotlinCompilationInfo.tcs: KotlinCompilationInfo.TCS
|
||||||
|
get() = this as KotlinCompilationInfo.TCS
|
||||||
|
|
||||||
internal val KotlinCompilationInfo.kpmOrNull: KotlinCompilationInfo.KPM?
|
internal val KotlinCompilationInfo.kpmOrNull: KotlinCompilationInfo.KPM?
|
||||||
get() = when (this) {
|
get() = when (this) {
|
||||||
is KotlinCompilationInfo.KPM -> this
|
is KotlinCompilationInfo.KPM -> this
|
||||||
|
|||||||
+44
-1
@@ -7,11 +7,14 @@ package org.jetbrains.kotlin.gradle.plugin
|
|||||||
|
|
||||||
import org.gradle.api.DefaultTask
|
import org.gradle.api.DefaultTask
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.file.Directory
|
||||||
import org.gradle.api.file.FileCollection
|
import org.gradle.api.file.FileCollection
|
||||||
import org.gradle.api.file.SourceDirectorySet
|
import org.gradle.api.file.SourceDirectorySet
|
||||||
import org.gradle.api.logging.Logging
|
import org.gradle.api.logging.Logging
|
||||||
|
import org.gradle.api.provider.Property
|
||||||
import org.gradle.api.tasks.SourceSet
|
import org.gradle.api.tasks.SourceSet
|
||||||
import org.gradle.api.tasks.TaskProvider
|
import org.gradle.api.tasks.TaskProvider
|
||||||
|
import org.gradle.api.tasks.bundling.Jar
|
||||||
import org.jetbrains.kotlin.gradle.plugin.internal.JavaSourceSetsAccessor
|
import org.jetbrains.kotlin.gradle.plugin.internal.JavaSourceSetsAccessor
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinWithJavaCompilation
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinWithJavaCompilation
|
||||||
@@ -50,7 +53,47 @@ internal abstract class KotlinSourceSetProcessor<T : AbstractKotlinCompile<*>>(
|
|||||||
|
|
||||||
private fun prepareKotlinCompileTask(): TaskProvider<out T> =
|
private fun prepareKotlinCompileTask(): TaskProvider<out T> =
|
||||||
doRegisterTask(project, compilationInfo.compileKotlinTaskName).also { task ->
|
doRegisterTask(project, compilationInfo.compileKotlinTaskName).also { task ->
|
||||||
compilationInfo.classesDirs.from(task.flatMap { it.destinationDirectory })
|
// Workaround for case when 'compilationInfo.classesDirs' is actually Java 'SourceSet.output.classesDir'
|
||||||
|
// Gradle from 7.3 started to realize 'FileCollection's registered for 'BuildOutputCleanupRegistry'
|
||||||
|
// at the end of the configuration phase. One of this 'FileCollection' is 'SourceSetOutput'
|
||||||
|
// which causes 'KotlinCompile' tasks to be eagerly realized.
|
||||||
|
// Related commit into Gradle: https://github.com/gradle/gradle/commit/758adc5b0c5a5d27e2797a9fa8fd2690530c5de9
|
||||||
|
// Proper workaround is peeked from here:
|
||||||
|
// https://github.com/gradle/gradle/blob/16cbc3a678771b08418d086eb67e9934c9282dfb/subprojects/plugins/src/main/java/org/gradle/api/plugins/internal/JvmPluginsHelper.java#L142-L148
|
||||||
|
if (compilationInfo.tcsOrNull?.compilation is KotlinWithJavaCompilation<*, *>) {
|
||||||
|
val kotlinSourceDirectorySet = compilationInfo.tcs.compilation.defaultSourceSet.kotlin
|
||||||
|
kotlinSourceDirectorySet.destinationDirectory.value(defaultKotlinDestinationDir)
|
||||||
|
task.configure {
|
||||||
|
if (it is Kotlin2JsCompile) {
|
||||||
|
it.defaultDestinationDirectory.convention(kotlinSourceDirectorySet.destinationDirectory)
|
||||||
|
} else {
|
||||||
|
it.destinationDirectory.convention(kotlinSourceDirectorySet.destinationDirectory)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compilationInfo.classesDirs.from(kotlinSourceDirectorySet.destinationDirectory).builtBy(task)
|
||||||
|
if (compilationInfo.tcs.compilation.platformType == KotlinPlatformType.js) {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
kotlinSourceDirectorySet.compiledBy(
|
||||||
|
task as TaskProvider<Kotlin2JsCompile>,
|
||||||
|
Kotlin2JsCompile::defaultDestinationDirectory
|
||||||
|
)
|
||||||
|
(kotlinSourceDirectorySet.classesDirectory as Property<Directory>).set(task.flatMap { it.destinationDirectory })
|
||||||
|
} else {
|
||||||
|
kotlinSourceDirectorySet.compiledBy(task, AbstractKotlinCompile<*>::destinationDirectory)
|
||||||
|
}
|
||||||
|
if (compilationInfo.isMain) {
|
||||||
|
project.tasks.named(
|
||||||
|
compilationInfo.tcs.compilation.target.artifactsTaskName,
|
||||||
|
Jar::class.java
|
||||||
|
) {
|
||||||
|
it.from(kotlinSourceDirectorySet.classesDirectory)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
compilationInfo.classesDirs.from(
|
||||||
|
task.flatMap { it.destinationDirectory }
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun run() {
|
override fun run() {
|
||||||
|
|||||||
+10
@@ -34,6 +34,16 @@ internal object DefaultKotlinCompilationAssociator : KotlinCompilationAssociator
|
|||||||
*/
|
*/
|
||||||
project.dependencies.add(auxiliary.compileOnlyConfigurationName, project.files({ main.output.classesDirs }))
|
project.dependencies.add(auxiliary.compileOnlyConfigurationName, project.files({ main.output.classesDirs }))
|
||||||
project.dependencies.add(auxiliary.runtimeOnlyConfigurationName, project.files({ main.output.allOutputs }))
|
project.dependencies.add(auxiliary.runtimeOnlyConfigurationName, project.files({ main.output.allOutputs }))
|
||||||
|
// Adding classes that could be produced into non-default destination for JVM target
|
||||||
|
// Check KotlinSourceSetProcessor for details
|
||||||
|
project.dependencies.add(
|
||||||
|
auxiliary.implementationConfigurationName,
|
||||||
|
project.objects.fileCollection().from(
|
||||||
|
{
|
||||||
|
main.defaultSourceSet.kotlin.classesDirectory.orNull?.asFile
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
auxiliary.compileDependencyConfigurationName.addAllDependenciesFromOtherConfigurations(
|
auxiliary.compileDependencyConfigurationName.addAllDependenciesFromOtherConfigurations(
|
||||||
project,
|
project,
|
||||||
|
|||||||
+13
-1
@@ -10,6 +10,8 @@ import org.gradle.api.tasks.TaskProvider
|
|||||||
import org.gradle.api.tasks.bundling.AbstractArchiveTask
|
import org.gradle.api.tasks.bundling.AbstractArchiveTask
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.getVisibleSourceSetsFromAssociateCompilations
|
import org.jetbrains.kotlin.gradle.plugin.sources.getVisibleSourceSetsFromAssociateCompilations
|
||||||
|
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
|
||||||
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompileTool
|
||||||
import org.jetbrains.kotlin.gradle.utils.filesProvider
|
import org.jetbrains.kotlin.gradle.utils.filesProvider
|
||||||
|
|
||||||
internal interface KotlinCompilationFriendPathsResolver {
|
internal interface KotlinCompilationFriendPathsResolver {
|
||||||
@@ -23,7 +25,17 @@ internal class DefaultKotlinCompilationFriendPathsResolver(
|
|||||||
|
|
||||||
override fun resolveFriendPaths(compilation: InternalKotlinCompilation<*>): Iterable<FileCollection> {
|
override fun resolveFriendPaths(compilation: InternalKotlinCompilation<*>): Iterable<FileCollection> {
|
||||||
return mutableListOf<FileCollection>().apply {
|
return mutableListOf<FileCollection>().apply {
|
||||||
compilation.associateWithClosure.forEach { add(it.output.classesDirs) }
|
compilation.associateWithClosure.forEach {
|
||||||
|
add(it.output.classesDirs)
|
||||||
|
// Adding classes that could be produced to non-default destination for JVM target
|
||||||
|
// Check KotlinSourceSetProcessor for details
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
add(
|
||||||
|
compilation.project.files(
|
||||||
|
(it.compileTaskProvider as TaskProvider<KotlinCompileTool>).flatMap { task -> task.destinationDirectory }
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
add(friendArtifactResolver.resolveFriendArtifacts(compilation))
|
add(friendArtifactResolver.resolveFriendArtifacts(compilation))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -42,7 +42,7 @@ open class GradleKpmCompilationTaskConfigurator(
|
|||||||
val result = project.tasks.named(compilationData.compileKotlinTaskName, KotlinCompile::class.java) {
|
val result = project.tasks.named(compilationData.compileKotlinTaskName, KotlinCompile::class.java) {
|
||||||
it.kotlinPluginData = project.compilerPluginProviderForPlatformCompilation(variant, compilationData)
|
it.kotlinPluginData = project.compilerPluginProviderForPlatformCompilation(variant, compilationData)
|
||||||
}
|
}
|
||||||
compilationData.output.classesDirs.from(result.map { it.destinationDirectory })
|
compilationData.output.classesDirs.from(result.flatMap { it.destinationDirectory })
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user