Add api compatible way to get if project isolation is enabled

Gradle 8.0 internal API has changed returned type. To fix incorrect KGP
behaviour has to add additional Gradle 8.0 plugin variant and provide
project isolation start parameter accessor implementation for older
Gradle versions.

^KT-55624 In Progress
This commit is contained in:
Yahor Berdnikau
2023-03-17 10:59:01 +01:00
committed by Space Team
parent 19b0ffd85c
commit cc1aaf4ba8
20 changed files with 362 additions and 19 deletions
+7 -4
View File
@@ -39,7 +39,7 @@ import java.net.URL
import java.util.*
/**
* Gradle plugins common variants.
* Gradle's plugins common variants.
*
* [minimalSupportedGradleVersion] - minimal Gradle version that is supported in this variant
* [gradleApiVersion] - Gradle API dependency version. Usually should be the same as [minimalSupportedGradleVersion].
@@ -55,7 +55,8 @@ enum class GradlePluginVariant(
GRADLE_71("gradle71", "7.1", "7.1", "https://docs.gradle.org/7.1.1/javadoc/"),
GRADLE_74("gradle74", "7.4", "7.4", "https://docs.gradle.org/7.4.2/javadoc/"),
GRADLE_75("gradle75", "7.5", "7.5", "https://docs.gradle.org/7.5.1/javadoc/"),
GRADLE_76("gradle76", "7.6", "7.6", "https://docs.gradle.org/7.6/javadoc/"),
GRADLE_76("gradle76", "7.6", "7.6", "https://docs.gradle.org/7.6.1/javadoc/"),
GRADLE_80("gradle80", "8.0", "8.0", "https://docs.gradle.org/8.0.2/javadoc/"),
}
val commonSourceSetName = "common"
@@ -438,7 +439,7 @@ fun Project.createGradlePluginVariant(
}
configurations.configureEach {
if (isCanBeConsumed && this@configureEach.name.startsWith(variantSourceSet.name)) {
if (this@configureEach.name.startsWith(variantSourceSet.name)) {
attributes {
attribute(
GradlePluginApiVersion.GRADLE_PLUGIN_API_VERSION_ATTRIBUTE,
@@ -694,7 +695,9 @@ fun Project.configureDokkaPublication(
// Workaround for https://github.com/Kotlin/dokka/issues/2097
// Gradle 7.6 javadoc does not have published 'package-list' file
private fun GradleExternalDocumentationLinkBuilder.addWorkaroundForElementList(pluginVariant: GradlePluginVariant) {
if (pluginVariant == GradlePluginVariant.GRADLE_76) {
if (pluginVariant == GradlePluginVariant.GRADLE_76 ||
pluginVariant == GradlePluginVariant.GRADLE_80
) {
packageListUrl.set(URL("${pluginVariant.gradleApiJavadocUrl}element-list"))
}
}
@@ -94,4 +94,11 @@ if (!kotlinBuildProperties.isInJpsBuildIdeaSync) {
commonSourceSet = commonSourceSet
)
publishShadowedJar(gradle76SourceSet, commonSourceSet)
// Used for Gradle 8.0+ versions
val gradle80SourceSet = createGradlePluginVariant(
GradlePluginVariant.GRADLE_80,
commonSourceSet = commonSourceSet
)
publishShadowedJar(gradle80SourceSet, commonSourceSet)
}
@@ -55,6 +55,13 @@ createGradlePluginVariant(
isGradlePlugin = false
)
// Used for Gradle 8.0+ versions
createGradlePluginVariant(
GradlePluginVariant.GRADLE_80,
commonSourceSet = commonSourceSet,
isGradlePlugin = false
)
publishing {
publications {
register<MavenPublication>(DEFAULT_MAIN_PUBLICATION_NAME) {
@@ -93,7 +93,7 @@ abstract class DefaultKotlinBasePlugin : KotlinBasePlugin {
}
val kotlinGradleBuildServices = KotlinGradleBuildServices.registerIfAbsent(project.gradle).get()
if (!isProjectIsolationEnabled(project.gradle)) {
if (!project.isProjectIsolationEnabled) {
kotlinGradleBuildServices.detectKotlinPluginLoadedInMultipleProjects(project, kotlinPluginVersion)
}
@@ -167,6 +167,11 @@ abstract class DefaultKotlinBasePlugin : KotlinBasePlugin {
ArtifactTypeAttributeAccessor.ArtifactTypeAttributeAccessorVariantFactory::class,
DefaultArtifactTypeAttributeAccessorVariantFactory()
)
factories.putIfAbsent(
ProjectIsolationStartParameterAccessor.Factory::class,
DefaultProjectIsolationStartParameterAccessorVariantFactory()
)
}
protected fun setupAttributeMatchingStrategy(
@@ -0,0 +1,43 @@
/*
* 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.
*/
package org.jetbrains.kotlin.gradle.plugin.internal
import org.gradle.api.Project
import org.gradle.api.internal.StartParameterInternal
import org.gradle.api.invocation.Gradle
import org.jetbrains.kotlin.gradle.plugin.VariantImplementationFactories
import org.jetbrains.kotlin.gradle.plugin.variantImplementationFactory
/**
* Gradle 8.0 has changed internal method return type to `Option.Value<Boolean>` from previous `BuildOption.Value<Boolean>`.
*/
interface ProjectIsolationStartParameterAccessor {
val isProjectIsolationEnabled: Boolean
interface Factory : VariantImplementationFactories.VariantImplementationFactory {
fun getInstance(gradle: Gradle): ProjectIsolationStartParameterAccessor
}
}
internal class DefaultProjectIsolationStartParameterAccessorVariantFactory :
ProjectIsolationStartParameterAccessor.Factory {
override fun getInstance(gradle: Gradle): ProjectIsolationStartParameterAccessor {
return DefaultProjectIsolationStartParameterAccessor(gradle)
}
}
internal class DefaultProjectIsolationStartParameterAccessor(
private val gradle: Gradle
) : ProjectIsolationStartParameterAccessor {
override val isProjectIsolationEnabled: Boolean by lazy {
(gradle.startParameter as StartParameterInternal).isolatedProjects.get()
}
}
internal val Project.isProjectIsolationEnabled
get() = variantImplementationFactory<ProjectIsolationStartParameterAccessor.Factory>()
.getInstance(gradle)
.isProjectIsolationEnabled
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.build.report.metrics.BuildTime
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_BUILD_REPORT_SINGLE_FILE
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_BUILD_REPORT_HTTP_URL
import org.jetbrains.kotlin.gradle.utils.isProjectIsolationEnabled
import org.jetbrains.kotlin.gradle.plugin.internal.isProjectIsolationEnabled
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toUpperCaseAsciiOnly
@@ -29,7 +29,7 @@ internal fun reportingSettings(project: Project): ReportingSettings {
else -> BuildReportMode.VERBOSE
}
val fileReportSettings = if (buildReportOutputTypes.contains(BuildReportType.FILE)) {
val buildReportDir = properties.buildReportFileOutputDir ?: (if (isProjectIsolationEnabled(project.gradle)) {
val buildReportDir = properties.buildReportFileOutputDir ?: (if (project.isProjectIsolationEnabled) {
// TODO: it's a workaround for KT-52963, should be reworked KT-55763
project.rootDir.resolve("build")
} else {
@@ -13,13 +13,6 @@ import org.gradle.api.provider.Provider
import org.jetbrains.kotlin.gradle.plugin.internal.configurationTimePropertiesAccessor
import org.jetbrains.kotlin.gradle.plugin.internal.usedAtConfigurationTime
internal fun isProjectIsolationEnabled(gradle: Gradle) =
try {
(gradle.startParameter as? StartParameterInternal)?.isolatedProjects?.get()
} catch (_: IncompatibleClassChangeError) {
null
} ?: false
internal fun isConfigurationCacheAvailable(gradle: Gradle) =
try {
val startParameters = gradle.startParameter
@@ -32,9 +25,6 @@ internal fun Project.readSystemPropertyAtConfigurationTime(key: String): Provide
return providers.systemProperty(key).usedAtConfigurationTime(configurationTimePropertiesAccessor)
}
internal fun unavailableValueError(propertyName: String): Nothing =
error("'$propertyName' should be available at configuration time but unavailable on configuration cache reuse")
fun Task.notCompatibleWithConfigurationCacheCompat(reason: String) {
val reportConfigurationCacheWarnings = try {
val startParameters = project.gradle.startParameter as? StartParameterInternal
@@ -151,4 +151,6 @@ private fun Project.registerVariantImplementations() {
KotlinTestReportCompatibilityHelperG70.KotlinTestReportCompatibilityHelperVariantFactoryG70()
factories[ArtifactTypeAttributeAccessor.ArtifactTypeAttributeAccessorVariantFactory::class] =
ArtifactTypeAttributeAccessorG70.ArtifactTypeAttributeAccessorVariantFactoryG70()
factories[ProjectIsolationStartParameterAccessor.Factory::class] =
ProjectIsolationStartParameterAccessorG70.Factory()
}
@@ -0,0 +1,19 @@
/*
* 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.
*/
package org.jetbrains.kotlin.gradle.plugin.internal
import org.gradle.api.invocation.Gradle
internal class ProjectIsolationStartParameterAccessorG70() : ProjectIsolationStartParameterAccessor {
override val isProjectIsolationEnabled: Boolean
get() = false
internal class Factory : ProjectIsolationStartParameterAccessor.Factory {
override fun getInstance(gradle: Gradle): ProjectIsolationStartParameterAccessor {
return ProjectIsolationStartParameterAccessorG70()
}
}
}
@@ -152,4 +152,6 @@ private fun Project.registerVariantImplementations() {
KotlinTestReportCompatibilityHelperG71.KotlinTestReportCompatibilityHelperVariantFactoryG71()
factories[ArtifactTypeAttributeAccessor.ArtifactTypeAttributeAccessorVariantFactory::class] =
ArtifactTypeAttributeAccessorG71.ArtifactTypeAttributeAccessorVariantFactoryG71()
factories[ProjectIsolationStartParameterAccessor.Factory::class] =
ProjectIsolationStartParameterAccessorG71.Factory()
}
@@ -0,0 +1,23 @@
/*
* 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.
*/
package org.jetbrains.kotlin.gradle.plugin.internal
import org.gradle.api.internal.StartParameterInternal
import org.gradle.api.invocation.Gradle
internal class ProjectIsolationStartParameterAccessorG71(
private val gradle: Gradle
) : ProjectIsolationStartParameterAccessor {
override val isProjectIsolationEnabled: Boolean by lazy {
(gradle.startParameter as StartParameterInternal).isolatedProjects.get()
}
internal class Factory : ProjectIsolationStartParameterAccessor.Factory {
override fun getInstance(gradle: Gradle): ProjectIsolationStartParameterAccessor {
return ProjectIsolationStartParameterAccessorG71(gradle)
}
}
}
@@ -142,4 +142,6 @@ private fun Project.registerVariantImplementations() {
val factories = VariantImplementationFactoriesConfigurator.get(gradle)
factories[MppTestReportHelper.MppTestReportHelperVariantFactory::class] =
MppTestReportHelperG74.MppTestReportHelperVariantFactoryG74()
factories[ProjectIsolationStartParameterAccessor.Factory::class] =
ProjectIsolationStartParameterAccessorG74.Factory()
}
@@ -0,0 +1,23 @@
/*
* 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.
*/
package org.jetbrains.kotlin.gradle.plugin.internal
import org.gradle.api.internal.StartParameterInternal
import org.gradle.api.invocation.Gradle
internal class ProjectIsolationStartParameterAccessorG74(
private val gradle: Gradle
) : ProjectIsolationStartParameterAccessor {
override val isProjectIsolationEnabled: Boolean by lazy {
(gradle.startParameter as StartParameterInternal).isolatedProjects.get()
}
internal class Factory : ProjectIsolationStartParameterAccessor.Factory {
override fun getInstance(gradle: Gradle): ProjectIsolationStartParameterAccessor {
return ProjectIsolationStartParameterAccessorG74(gradle)
}
}
}
@@ -14,6 +14,8 @@ import org.gradle.api.model.ObjectFactory
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.kotlin.gradle.plugin.internal.MppTestReportHelper
import org.jetbrains.kotlin.gradle.plugin.internal.MppTestReportHelperG75
import org.jetbrains.kotlin.gradle.plugin.internal.ProjectIsolationStartParameterAccessor
import org.jetbrains.kotlin.gradle.plugin.internal.ProjectIsolationStartParameterAccessorG75
import javax.inject.Inject
private const val PLUGIN_VARIANT_NAME = "gradle75"
@@ -143,4 +145,6 @@ private fun Project.registerVariantImplementations() {
val factories = VariantImplementationFactoriesConfigurator.get(gradle)
factories[MppTestReportHelper.MppTestReportHelperVariantFactory::class] =
MppTestReportHelperG75.MppTestReportHelperVariantFactoryG75()
factories[ProjectIsolationStartParameterAccessor.Factory::class] =
ProjectIsolationStartParameterAccessorG75.Factory()
}
@@ -0,0 +1,23 @@
/*
* 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.
*/
package org.jetbrains.kotlin.gradle.plugin.internal
import org.gradle.api.internal.StartParameterInternal
import org.gradle.api.invocation.Gradle
internal class ProjectIsolationStartParameterAccessorG75(
private val gradle: Gradle
) : ProjectIsolationStartParameterAccessor {
override val isProjectIsolationEnabled: Boolean by lazy {
(gradle.startParameter as StartParameterInternal).isolatedProjects.get()
}
internal class Factory : ProjectIsolationStartParameterAccessor.Factory {
override fun getInstance(gradle: Gradle): ProjectIsolationStartParameterAccessor {
return ProjectIsolationStartParameterAccessorG75(gradle)
}
}
}
@@ -12,6 +12,8 @@ import org.gradle.api.Project
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.model.ObjectFactory
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.kotlin.gradle.plugin.internal.ProjectIsolationStartParameterAccessor
import org.jetbrains.kotlin.gradle.plugin.internal.ProjectIsolationStartParameterAccessorG76
import javax.inject.Inject
private const val PLUGIN_VARIANT_NAME = "gradle76"
@@ -137,7 +139,8 @@ open class KotlinPlatformCommonPlugin : KotlinPlatformPluginBase("common") {
}
}
@Suppress("UnusedReceiverParameter")
private fun Project.registerVariantImplementations() {
val factories = VariantImplementationFactoriesConfigurator.get(gradle)
factories[ProjectIsolationStartParameterAccessor.Factory::class] =
ProjectIsolationStartParameterAccessorG76.Factory()
}
@@ -0,0 +1,23 @@
/*
* 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.
*/
package org.jetbrains.kotlin.gradle.plugin.internal
import org.gradle.api.internal.StartParameterInternal
import org.gradle.api.invocation.Gradle
internal class ProjectIsolationStartParameterAccessorG76(
private val gradle: Gradle
) : ProjectIsolationStartParameterAccessor {
override val isProjectIsolationEnabled: Boolean by lazy {
(gradle.startParameter as StartParameterInternal).isolatedProjects.get()
}
internal class Factory : ProjectIsolationStartParameterAccessor.Factory {
override fun getInstance(gradle: Gradle): ProjectIsolationStartParameterAccessor {
return ProjectIsolationStartParameterAccessorG76(gradle)
}
}
}
@@ -0,0 +1,143 @@
/*
* Copyright 2010-2022 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.
*/
package org.jetbrains.kotlin.gradle.plugin
import com.android.build.gradle.BaseExtension
import org.gradle.api.Named
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.model.ObjectFactory
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import javax.inject.Inject
private const val PLUGIN_VARIANT_NAME = "gradle80"
open class KotlinPluginWrapper @Inject constructor(
registry: ToolingModelBuilderRegistry
) : AbstractKotlinPluginWrapper(registry) {
override val pluginVariant: String = PLUGIN_VARIANT_NAME
override fun apply(project: Project) {
project.registerVariantImplementations()
super.apply(project)
}
}
open class KotlinCommonPluginWrapper @Inject constructor(
registry: ToolingModelBuilderRegistry
) : AbstractKotlinCommonPluginWrapper(registry) {
override val pluginVariant: String = PLUGIN_VARIANT_NAME
override fun apply(project: Project) {
project.registerVariantImplementations()
super.apply(project)
}
}
open class KotlinAndroidPluginWrapper @Inject constructor(
registry: ToolingModelBuilderRegistry
) : AbstractKotlinAndroidPluginWrapper(registry) {
override val pluginVariant: String = PLUGIN_VARIANT_NAME
override fun apply(project: Project) {
project.registerVariantImplementations()
super.apply(project)
}
}
@Suppress("DEPRECATION_ERROR")
open class Kotlin2JsPluginWrapper @Inject constructor(
registry: ToolingModelBuilderRegistry
) : AbstractKotlin2JsPluginWrapper(registry) {
override val pluginVariant: String = PLUGIN_VARIANT_NAME
override fun apply(project: Project) {
project.registerVariantImplementations()
super.apply(project)
}
}
open class KotlinMultiplatformPluginWrapper : AbstractKotlinMultiplatformPluginWrapper() {
override val pluginVariant: String = PLUGIN_VARIANT_NAME
override fun apply(project: Project) {
project.registerVariantImplementations()
super.apply(project)
}
}
open class KotlinJsPluginWrapper : AbstractKotlinJsPluginWrapper() {
override val pluginVariant: String = PLUGIN_VARIANT_NAME
override fun apply(project: Project) {
project.registerVariantImplementations()
super.apply(project)
}
}
open class KotlinPm20PluginWrapper @Inject constructor(
objectFactory: ObjectFactory
) : AbstractKotlinPm20PluginWrapper(objectFactory) {
override val pluginVariant: String = PLUGIN_VARIANT_NAME
override fun apply(project: Project) {
project.registerVariantImplementations()
super.apply(project)
}
}
open class KotlinPlatformJvmPlugin : KotlinPlatformImplementationPluginBase("jvm") {
override fun apply(project: Project) {
project.applyPlugin<KotlinPluginWrapper>()
super.apply(project)
}
}
open class KotlinPlatformJsPlugin : KotlinPlatformImplementationPluginBase("js") {
override fun apply(project: Project) {
@Suppress("DEPRECATION_ERROR")
project.applyPlugin<Kotlin2JsPluginWrapper>()
super.apply(project)
}
}
open class KotlinPlatformAndroidPlugin : KotlinPlatformImplementationPluginBase("android") {
override fun apply(project: Project) {
project.applyPlugin<KotlinAndroidPluginWrapper>()
super.apply(project)
}
override fun namedSourceSetsContainer(project: Project): NamedDomainObjectContainer<*> =
(project.extensions.getByName("android") as BaseExtension).sourceSets
override fun addCommonSourceSetToPlatformSourceSet(commonSourceSet: Named, platformProject: Project) {
val androidExtension = platformProject.extensions.getByName("android") as BaseExtension
val androidSourceSet = androidExtension.sourceSets.findByName(commonSourceSet.name) ?: return
val kotlinSourceSet = androidSourceSet.getExtension<SourceDirectorySet>(KOTLIN_DSL_NAME)
?: return
kotlinSourceSet.source(getKotlinSourceDirectorySetSafe(commonSourceSet)!!)
}
}
open class KotlinPlatformCommonPlugin : KotlinPlatformPluginBase("common") {
override fun apply(project: Project) {
warnAboutKotlin12xMppDeprecation(project)
project.applyPlugin<KotlinCommonPluginWrapper>()
}
}
@Suppress("UnusedReceiverParameter")
private fun Project.registerVariantImplementations() {
}
@@ -157,4 +157,6 @@ private fun Project.registerVariantImplementations() {
KotlinTestReportCompatibilityHelperG6.KotlinTestReportCompatibilityHelperVariantFactoryG6()
factories[ArtifactTypeAttributeAccessor.ArtifactTypeAttributeAccessorVariantFactory::class] =
ArtifactTypeAttributeAccessorG6.ArtifactTypeAttributeAccessorVariantFactoryG6()
factories[ProjectIsolationStartParameterAccessor.Factory::class] =
ProjectIsolationStartParameterAccessorG6.Factory()
}
@@ -0,0 +1,19 @@
/*
* 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.
*/
package org.jetbrains.kotlin.gradle.plugin.internal
import org.gradle.api.invocation.Gradle
internal class ProjectIsolationStartParameterAccessorG6() : ProjectIsolationStartParameterAccessor {
override val isProjectIsolationEnabled: Boolean
get() = false
internal class Factory : ProjectIsolationStartParameterAccessor.Factory {
override fun getInstance(gradle: Gradle): ProjectIsolationStartParameterAccessor {
return ProjectIsolationStartParameterAccessorG6()
}
}
}