[Gradle] jvm().withJava(): Fix Zombie compilation instance returned from create()
^KT-60462 Verification Pending
This commit is contained in:
committed by
Space Team
parent
0945968751
commit
0feecebc07
+1
-1
@@ -286,4 +286,4 @@ internal abstract class AbstractKotlinPlugin(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -15,7 +15,6 @@ 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.gradle.api.tasks.bundling.Jar
|
||||||
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
|
||||||
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
|
||||||
@@ -41,7 +40,7 @@ internal abstract class KotlinSourceSetProcessor<T : AbstractKotlinCompile<*>>(
|
|||||||
protected val javaSourceSet: SourceSet?
|
protected val javaSourceSet: SourceSet?
|
||||||
get() = when (val compilation = compilationInfo.safeAs<KotlinCompilationInfo.TCS>()?.origin) {
|
get() = when (val compilation = compilationInfo.safeAs<KotlinCompilationInfo.TCS>()?.origin) {
|
||||||
is KotlinWithJavaCompilation<*, *> -> compilation.javaSourceSet
|
is KotlinWithJavaCompilation<*, *> -> compilation.javaSourceSet
|
||||||
is KotlinJvmCompilation -> compilation.javaSourceSet.getOrNull()
|
is KotlinJvmCompilation -> compilation.javaSourceSet
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+8
-9
@@ -19,9 +19,6 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationI
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.variantImplementationFactory
|
import org.jetbrains.kotlin.gradle.plugin.variantImplementationFactory
|
||||||
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
|
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
|
||||||
import org.jetbrains.kotlin.gradle.utils.LenientFuture
|
|
||||||
import org.jetbrains.kotlin.gradle.utils.future
|
|
||||||
import org.jetbrains.kotlin.gradle.utils.lenient
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
open class KotlinJvmCompilation @Inject internal constructor(
|
open class KotlinJvmCompilation @Inject internal constructor(
|
||||||
@@ -67,17 +64,19 @@ open class KotlinJvmCompilation @Inject internal constructor(
|
|||||||
* will be enabled after call to this method.
|
* will be enabled after call to this method.
|
||||||
*/
|
*/
|
||||||
internal val compileJavaTaskProviderSafe: Provider<JavaCompile> = target.project.providers
|
internal val compileJavaTaskProviderSafe: Provider<JavaCompile> = target.project.providers
|
||||||
.provider { javaSourceSet.getOrNull() }
|
.provider { javaSourceSet }
|
||||||
.flatMap { javaSourceSet ->
|
.flatMap { javaSourceSet ->
|
||||||
@Suppress("RedundantRequireNotNullCall") // IDE and CLI disagree here
|
|
||||||
checkNotNull(javaSourceSet)
|
checkNotNull(javaSourceSet)
|
||||||
project.tasks.named(javaSourceSet.compileJavaTaskName, JavaCompile::class.java)
|
project.tasks.named(javaSourceSet.compileJavaTaskName, JavaCompile::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val javaSourceSet: LenientFuture<SourceSet> = target.project.future {
|
internal val javaSourceSet
|
||||||
target.withJavaEnabledFuture.await()
|
get() = if (target.withJavaEnabled) maybeCreateJavaSourceSet() else null
|
||||||
target.project.javaSourceSets.maybeCreate(compilationName)
|
|
||||||
}.lenient
|
internal fun maybeCreateJavaSourceSet(): SourceSet {
|
||||||
|
check(target.withJavaEnabled)
|
||||||
|
return target.project.javaSourceSets.maybeCreate(compilationName)
|
||||||
|
}
|
||||||
|
|
||||||
override val processResourcesTaskName: String
|
override val processResourcesTaskName: String
|
||||||
get() = compilation.processResourcesTaskName ?: error("Missing 'processResourcesTaskName'")
|
get() = compilation.processResourcesTaskName ?: error("Missing 'processResourcesTaskName'")
|
||||||
|
|||||||
+1
-3
@@ -6,12 +6,10 @@
|
|||||||
@file:Suppress("PackageDirectoryMismatch") // Old package for compatibility
|
@file:Suppress("PackageDirectoryMismatch") // Old package for compatibility
|
||||||
package org.jetbrains.kotlin.gradle.plugin.mpp
|
package org.jetbrains.kotlin.gradle.plugin.mpp
|
||||||
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.*
|
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinJvmCompilationAssociator
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.*
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinCompilationImplFactory
|
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinCompilationImplFactory
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinJvmCompilerOptionsFactory
|
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinJvmCompilerOptionsFactory
|
||||||
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
|
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
|
||||||
import org.jetbrains.kotlin.gradle.utils.*
|
|
||||||
|
|
||||||
open class KotlinJvmCompilationFactory internal constructor(
|
open class KotlinJvmCompilationFactory internal constructor(
|
||||||
override val target: KotlinJvmTarget
|
override val target: KotlinJvmTarget
|
||||||
|
|||||||
+4
-10
@@ -34,9 +34,8 @@ import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmRunDsl
|
|||||||
import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmRunDslImpl
|
import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmRunDslImpl
|
||||||
import org.jetbrains.kotlin.gradle.targets.jvm.tasks.registerMainRunTask
|
import org.jetbrains.kotlin.gradle.targets.jvm.tasks.registerMainRunTask
|
||||||
import org.jetbrains.kotlin.gradle.tasks.withType
|
import org.jetbrains.kotlin.gradle.tasks.withType
|
||||||
import org.jetbrains.kotlin.gradle.utils.*
|
|
||||||
import org.jetbrains.kotlin.gradle.utils.CompletableFuture
|
|
||||||
import org.jetbrains.kotlin.gradle.utils.Future
|
import org.jetbrains.kotlin.gradle.utils.Future
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
|
||||||
import org.jetbrains.kotlin.gradle.utils.findAppliedAndroidPluginIdOrNull
|
import org.jetbrains.kotlin.gradle.utils.findAppliedAndroidPluginIdOrNull
|
||||||
import org.jetbrains.kotlin.gradle.utils.future
|
import org.jetbrains.kotlin.gradle.utils.future
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||||
@@ -95,13 +94,6 @@ abstract class KotlinJvmTarget @Inject constructor(
|
|||||||
mainRun.await()?.configure()
|
mainRun.await()?.configure()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Future that will complete once [withJava] is called and java support for this target
|
|
||||||
* was established.
|
|
||||||
*/
|
|
||||||
internal val withJavaEnabledFuture: Future<Unit> get() = withJavaEnabledFutureImpl
|
|
||||||
private val withJavaEnabledFutureImpl = CompletableFuture<Unit>()
|
|
||||||
|
|
||||||
var withJavaEnabled = false
|
var withJavaEnabled = false
|
||||||
private set
|
private set
|
||||||
|
|
||||||
@@ -184,7 +176,9 @@ abstract class KotlinJvmTarget @Inject constructor(
|
|||||||
disableJavaPluginTasks(javaSourceSets)
|
disableJavaPluginTasks(javaSourceSets)
|
||||||
}
|
}
|
||||||
|
|
||||||
withJavaEnabledFutureImpl.complete(Unit)
|
compilations.all { compilation ->
|
||||||
|
compilation.maybeCreateJavaSourceSet()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun disableJavaPluginTasks(javaSourceSet: SourceSetContainer) {
|
private fun disableJavaPluginTasks(javaSourceSet: SourceSetContainer) {
|
||||||
|
|||||||
+78
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("FunctionName")
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.gradle.regressionTests
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation
|
||||||
|
import org.jetbrains.kotlin.gradle.util.buildProjectWithMPP
|
||||||
|
import org.jetbrains.kotlin.gradle.util.runLifecycleAwareTest
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertNull
|
||||||
|
import kotlin.test.assertSame
|
||||||
|
|
||||||
|
class KT60462WithJavaZombieCompilationTest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regression was introduced by:
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* [Gradle] Ensure java source sets being created eagerly for 'withJava' Sebastian Sellmair* 07.07.23, 20:49
|
||||||
|
* 817e3de8f546e34974b89fef0f4f93b425e7e607
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* The commit was ensuring that jvm compilations will create their associated java source sets
|
||||||
|
* as eager as possible. The solution chosen in the commit was that already the construction of the compilation
|
||||||
|
* will spawn a coroutine that waits for the `withJavaEnabled` callback to create the java source set.
|
||||||
|
*
|
||||||
|
* However, a buildscript like
|
||||||
|
*
|
||||||
|
* ```kotlin
|
||||||
|
* kotlin {
|
||||||
|
* jvm().withJava()
|
||||||
|
* val customCompilation = jvm().compilations.create("custom")
|
||||||
|
* // ^
|
||||||
|
* // Zombie
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* would therefore try to create the java source set right in the constructor call of the 'custom' compilation.
|
||||||
|
* This would have triggered a listener on `javaSourceSets.all {}` which would ensure that all
|
||||||
|
* java source sets have a corresponding kotlin compilation created.
|
||||||
|
*
|
||||||
|
* Since the current stack is currently inside the constructor of the first compilation, the
|
||||||
|
* used `compilations.maybeCreate` would trigger the creation of another custom compilation.
|
||||||
|
*
|
||||||
|
* The initial buildscript call creating the initial custom compilation will therefore return a Zombie instance
|
||||||
|
* ```kotlin
|
||||||
|
* kotlin {
|
||||||
|
* val customCompilation = jvm().compilations.create("custom")
|
||||||
|
* customCompilation != jvm().compilations.getByName("custom")
|
||||||
|
* // ^ ^
|
||||||
|
* // Zombie Real instance created by the javaSourceSets.all listener
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun `test - custom compilation`() = buildProjectWithMPP().runLifecycleAwareTest {
|
||||||
|
multiplatformExtension.jvm().apply {
|
||||||
|
withJava()
|
||||||
|
|
||||||
|
var instanceUsedForConfigureBlock: KotlinJvmCompilation? = null
|
||||||
|
|
||||||
|
val instanceReturnedFromCreate = compilations.create("custom") { instance ->
|
||||||
|
assertNull(instanceUsedForConfigureBlock)
|
||||||
|
instanceUsedForConfigureBlock = instance
|
||||||
|
}
|
||||||
|
|
||||||
|
val instanceReturnedFromGet = compilations.getByName("custom")
|
||||||
|
|
||||||
|
assertSame(instanceReturnedFromCreate, instanceUsedForConfigureBlock)
|
||||||
|
assertSame(instanceReturnedFromGet, instanceUsedForConfigureBlock)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user