From eec4ac644cee33c543da741be1cc9e5f75a56bb1 Mon Sep 17 00:00:00 2001 From: "nataliya.valtman" Date: Thu, 14 Oct 2021 13:49:23 +0300 Subject: [PATCH] KT-49159 Transform KotlinGradleBuildService to BuildService --- .../kotlin/gradle/KotlinGradlePluginIT.kt | 5 + .../gradle/BuildKotlinToolingMetadataTest.kt | 2 +- .../IdeImportPropertiesConsistencyTest.kt | 11 +- .../JvmAndAndroidIntermediateSourceSetTest.kt | 2 +- .../gradle/KotlinAndroidDependsOnEdgesTest.kt | 9 +- .../kotlin/gradle/MppPublicationTest.kt | 2 +- .../gradle/MultiplatformExtensionTest.kt | 4 +- .../gradle/ResolveKotlinSourceSetsTest.kt | 1 + .../gradle/SourceSetCommonizerTargetTest.kt | 1 + .../SyncKotlinAndAndroidSourceSetsTest.kt | 1 + .../gradle/buildEventListenerRegistry.kt | 45 +++++ .../org/jetbrains/kotlin/gradle/mpp/Util.kt | 3 + .../BuildEventsListenerRegistryHolder.kt | 7 +- .../plugin/KotlinGradleBuildServices.kt | 185 +++++++----------- .../plugin/KotlinGradleFinishBuildHandler.kt | 25 ++- .../gradle/plugin/KotlinPluginWrapper.kt | 21 +- .../plugin/mpp/KotlinMultiplatformPlugin.kt | 2 +- .../kotlin/gradle/report/configureReporing.kt | 12 +- .../js/MultiplePluginDeclarationDetector.kt | 1 - 19 files changed, 177 insertions(+), 162 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/buildEventListenerRegistry.kt diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinGradlePluginIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinGradlePluginIT.kt index 25288c02885..ab00999880e 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinGradlePluginIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinGradlePluginIT.kt @@ -913,6 +913,11 @@ class KotlinGradleIT : BaseGradleIT() { assertSuccessful() assertContains("Kotlin build report is written to") } + + build("clean", "assemble", "-Pkotlin.build.report.enable=true") { + assertSuccessful() + assertContains("Kotlin build report is written to") + } } @Test diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/BuildKotlinToolingMetadataTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/BuildKotlinToolingMetadataTest.kt index f9b7521754a..fe033e83cd9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/BuildKotlinToolingMetadataTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/BuildKotlinToolingMetadataTest.kt @@ -38,7 +38,7 @@ import kotlin.test.assertTrue class BuildKotlinToolingMetadataTest { - private val project = ProjectBuilder.builder().build() as ProjectInternal + private val project = ProjectBuilder.builder().build().also{ addBuildEventsListenerRegistryMock(it) } as ProjectInternal private val multiplatformExtension get() = project.extensions.getByType(KotlinMultiplatformExtension::class.java) private val jsExtension get() = project.extensions.getByType(KotlinJsProjectExtension::class.java) diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/IdeImportPropertiesConsistencyTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/IdeImportPropertiesConsistencyTest.kt index 6018bbb19eb..57d64d4aa54 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/IdeImportPropertiesConsistencyTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/IdeImportPropertiesConsistencyTest.kt @@ -52,14 +52,14 @@ class IdeImportPropertiesConsistencyTest { @Test fun `test simple project`() { - val project = ProjectBuilder.builder().build() + val project = createProject() project.applyMultiplatformPlugin() project.assertPropertiesMatch() } @Test fun `test simple project with new hmpp flag`() { - val project = ProjectBuilder.builder().build() + val project = createProject() project.enableHierarchicalStructureByDefault() project.applyMultiplatformPlugin() project.assertPropertiesMatch() @@ -67,13 +67,16 @@ class IdeImportPropertiesConsistencyTest { @Test fun `test sub project with new hmpp flag`() { - val rootProject = ProjectBuilder.builder().build() - val project = ProjectBuilder.builder().withParent(rootProject).build() + val rootProject = createProject() + val project = ProjectBuilder.builder().withParent(rootProject).build().also { addBuildEventsListenerRegistryMock(it) } rootProject.enableHierarchicalStructureByDefault() project.applyMultiplatformPlugin() project.assertPropertiesMatch() } + private fun createProject() = ProjectBuilder.builder().build() + .also { addBuildEventsListenerRegistryMock(it) } + private fun Project.assertPropertiesMatch() { val isHmppValueUsedInCli = project.isKotlinGranularMetadataEnabled val isHmppValueUsedInIde = project.getProperty(GradleImportProperties.IS_HMPP_ENABLED) diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/JvmAndAndroidIntermediateSourceSetTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/JvmAndAndroidIntermediateSourceSetTest.kt index 8d2f5ec2039..a5958122533 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/JvmAndAndroidIntermediateSourceSetTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/JvmAndAndroidIntermediateSourceSetTest.kt @@ -9,7 +9,6 @@ package org.jetbrains.kotlin.gradle import com.android.build.gradle.LibraryExtension -import org.gradle.api.Project import org.gradle.api.internal.project.ProjectInternal import org.gradle.api.plugins.ExtraPropertiesExtension import org.gradle.testfixtures.ProjectBuilder @@ -30,6 +29,7 @@ class JvmAndAndroidIntermediateSourceSetTest { @BeforeTest fun setup() { project = ProjectBuilder.builder().build() as ProjectInternal + addBuildEventsListenerRegistryMock(project) project.extensions.getByType(ExtraPropertiesExtension::class.java).set("kotlin.mpp.enableGranularSourceSetsMetadata", "true") project.plugins.apply("kotlin-multiplatform") diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/KotlinAndroidDependsOnEdgesTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/KotlinAndroidDependsOnEdgesTest.kt index ed3c60e7f6a..3d6fd1e5386 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/KotlinAndroidDependsOnEdgesTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/KotlinAndroidDependsOnEdgesTest.kt @@ -19,7 +19,8 @@ import kotlin.test.assertEquals class KotlinAndroidDependsOnEdgesTest { @Test fun `default android source set declares dependsOn commonMain`() { - val project = ProjectBuilder.builder().build() + val project = createProject() + project.plugins.apply("kotlin-multiplatform") project.plugins.apply("android-library") @@ -59,7 +60,7 @@ class KotlinAndroidDependsOnEdgesTest { @Test fun `custom dependsOn edges`() { - val project = ProjectBuilder.builder().build() + val project = createProject() project.plugins.apply("kotlin-multiplatform") project.plugins.apply("android-library") @@ -105,6 +106,10 @@ class KotlinAndroidDependsOnEdgesTest { "Expected androidAndroidTest to only depend on commonTest" ) } + + private fun createProject() = ProjectBuilder.builder().build() + .also { addBuildEventsListenerRegistryMock(it) } + } private fun Iterable.sorted() = this.sortedBy { it.name } diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/MppPublicationTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/MppPublicationTest.kt index 60ba7cf5a9a..22cc0718ea1 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/MppPublicationTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/MppPublicationTest.kt @@ -18,7 +18,7 @@ import kotlin.test.fail class MppPublicationTest { - private val project = ProjectBuilder.builder().build() as ProjectInternal + private val project = ProjectBuilder.builder().build().also { addBuildEventsListenerRegistryMock(it) } as ProjectInternal init { project.plugins.apply("kotlin-multiplatform") diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/MultiplatformExtensionTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/MultiplatformExtensionTest.kt index ce8e4869d30..c38ed51e019 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/MultiplatformExtensionTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/MultiplatformExtensionTest.kt @@ -24,12 +24,14 @@ import org.jetbrains.kotlin.gradle.targets.native.internal.from import kotlin.test.BeforeTest import kotlin.test.assertNotNull + abstract class MultiplatformExtensionTest { protected val project: ProjectInternal = ProjectBuilder.builder().build() as ProjectInternal protected lateinit var kotlin: KotlinMultiplatformExtension @BeforeTest open fun setup() { + addBuildEventsListenerRegistryMock(project) kotlin = project.applyMultiplatformPlugin() } @@ -97,4 +99,4 @@ fun Project.enableCInteropCommonization() { fun Project.enableHierarchicalStructureByDefault() { propertiesExtension.set(KOTLIN_MPP_HIERARCHICAL_STRUCTURE_BY_DEFAULT, "true") -} \ No newline at end of file +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/ResolveKotlinSourceSetsTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/ResolveKotlinSourceSetsTest.kt index 7873d479b7c..f0e7bb5c525 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/ResolveKotlinSourceSetsTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/ResolveKotlinSourceSetsTest.kt @@ -24,6 +24,7 @@ class ResolveKotlinSourceSetsTest { @BeforeTest fun setup() { project = ProjectBuilder.builder().build() + addBuildEventsListenerRegistryMock(project) project.plugins.apply("kotlin-multiplatform") kotlin = project.extensions.getByName("kotlin") as KotlinMultiplatformExtension diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/SourceSetCommonizerTargetTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/SourceSetCommonizerTargetTest.kt index 0e3087049c8..36a26bd8b52 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/SourceSetCommonizerTargetTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/SourceSetCommonizerTargetTest.kt @@ -29,6 +29,7 @@ class SourceSetCommonizerTargetTest { @BeforeTest fun setup() { project = ProjectBuilder.builder().build() + addBuildEventsListenerRegistryMock(project) project.extensions.getByType(ExtraPropertiesExtension::class.java).set("kotlin.mpp.enableCompatibilityMetadataVariant", "false") project.plugins.apply("kotlin-multiplatform") kotlin = project.extensions.getByName("kotlin") as KotlinMultiplatformExtension diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/SyncKotlinAndAndroidSourceSetsTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/SyncKotlinAndAndroidSourceSetsTest.kt index 991fb11c40c..3427d40dd34 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/SyncKotlinAndAndroidSourceSetsTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/SyncKotlinAndAndroidSourceSetsTest.kt @@ -26,6 +26,7 @@ class SyncKotlinAndAndroidSourceSetsTest { @BeforeTest fun setup() { project = ProjectBuilder.builder().build() as ProjectInternal + addBuildEventsListenerRegistryMock(project) project.plugins.apply("kotlin-multiplatform") project.plugins.apply("android-library") diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/buildEventListenerRegistry.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/buildEventListenerRegistry.kt new file mode 100644 index 00000000000..865b4b170d6 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/buildEventListenerRegistry.kt @@ -0,0 +1,45 @@ +/* + * Copyright 2010-2021 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 + +import org.gradle.api.Project +import org.gradle.api.internal.project.DefaultProject +import org.gradle.api.provider.Provider +import org.gradle.build.event.BuildEventsListenerRegistry +import org.gradle.internal.service.DefaultServiceRegistry +import org.gradle.internal.service.scopes.ProjectScopeServices +import org.gradle.tooling.events.OperationCompletionListener +import java.lang.reflect.Field +import java.util.concurrent.atomic.AtomicReference + +/** + * In Gradle 6.7-rc-1 BuildEventsListenerRegistry service is not created in we need it in order + * to instantiate AGP. This creates a fake one and injects it - http://b/168630734. + */ +internal fun addBuildEventsListenerRegistryMock(project: Project) { + try { + val projectScopeServices = (project as DefaultProject).services as ProjectScopeServices + val state: Field = ProjectScopeServices::class.java.superclass.getDeclaredField("state") + state.isAccessible = true + @Suppress("UNCHECKED_CAST") + val stateValue: AtomicReference = state.get(projectScopeServices) as AtomicReference + val enumClass = Class.forName(DefaultServiceRegistry::class.java.name + "\$State") + stateValue.set(enumClass.enumConstants[0]) + + // add service and set state so that future mutations are not allowed + projectScopeServices.add(BuildEventsListenerRegistry::class.java, BuildEventsListenerRegistryMock) + stateValue.set(enumClass.enumConstants[1]) + } catch (e: Throwable) { + throw RuntimeException(e) + } +} + +object BuildEventsListenerRegistryMock : BuildEventsListenerRegistry { + + override fun onTaskCompletion(listener: Provider?) { + } + +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/mpp/Util.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/mpp/Util.kt index 9022a954d93..932a7bcf47d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/mpp/Util.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/mpp/Util.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle.mpp import org.gradle.api.Project import org.gradle.api.internal.project.ProjectInternal import org.gradle.testfixtures.ProjectBuilder +import org.jetbrains.kotlin.gradle.addBuildEventsListenerRegistryMock import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinPm20ProjectExtension @@ -19,6 +20,8 @@ fun buildProject( .builder() .apply(configBuilder) .build() + //temporary solution for BuildEventsListenerRegistry + .also { addBuildEventsListenerRegistryMock(it) } .apply(configProject) .let { it as ProjectInternal } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/BuildEventsListenerRegistryHolder.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/BuildEventsListenerRegistryHolder.kt index ab2cf2c716c..ee799408a2d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/BuildEventsListenerRegistryHolder.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/BuildEventsListenerRegistryHolder.kt @@ -7,17 +7,12 @@ package org.jetbrains.kotlin.gradle.plugin import org.gradle.api.Project import org.gradle.build.event.BuildEventsListenerRegistry -import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable import javax.inject.Inject -open class BuildEventsListenerRegistryHolder @Inject constructor(val listenerRegistry: BuildEventsListenerRegistry?) { +open class BuildEventsListenerRegistryHolder @Inject constructor(val listenerRegistry: BuildEventsListenerRegistry) { companion object { fun getInstance(project: Project) = run { - if (isConfigurationCacheAvailable(project.gradle)) { project.objects.newInstance(BuildEventsListenerRegistryHolder::class.java) - } else { - BuildEventsListenerRegistryHolder(null) } } } -} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleBuildServices.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleBuildServices.kt index 03d12f00726..6520c31f298 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleBuildServices.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleBuildServices.kt @@ -5,14 +5,12 @@ package org.jetbrains.kotlin.gradle.plugin -import org.gradle.BuildAdapter -import org.gradle.BuildResult -import org.gradle.api.Project -import org.gradle.api.invocation.Gradle -import org.gradle.api.logging.Logging import com.gradle.scan.plugin.BuildScanExtension +import org.gradle.api.Project +import org.gradle.api.logging.Logging import org.gradle.api.provider.Provider -import org.gradle.tooling.events.OperationCompletionListener +import org.gradle.api.services.BuildService +import org.gradle.api.services.BuildServiceParameters import org.jetbrains.kotlin.gradle.logging.kotlinDebug import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskExecutionResults import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskLoggers @@ -21,58 +19,47 @@ import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildEsStatListener import org.jetbrains.kotlin.gradle.plugin.statistics.ReportStatisticsToBuildScan import org.jetbrains.kotlin.gradle.plugin.statistics.ReportStatisticsToElasticSearch import org.jetbrains.kotlin.gradle.report.configureReporting -import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable +import java.io.File -//Support Gradle 6 and less. Move to -internal class KotlinGradleBuildServices private constructor( - private val gradle: Gradle, - private vararg val gradleListenerProviders: Provider -) : BuildAdapter() { +abstract class KotlinGradleBuildServices : BuildService, AutoCloseable { + + interface Parameters : BuildServiceParameters { + var buildDir: File + var rootDir: File + } + + private val log = Logging.getLogger(this.javaClass) + private var buildHandler: KotlinGradleFinishBuildHandler = KotlinGradleFinishBuildHandler() + private val CLASS_NAME = KotlinGradleBuildServices::class.java.simpleName + val INIT_MESSAGE = "Initialized $CLASS_NAME" + val DISPOSE_MESSAGE = "Disposed $CLASS_NAME" + + init { + log.kotlinDebug(INIT_MESSAGE) + buildHandler.buildStart() + } + + override fun close() { + buildHandler.buildFinished(parameters.buildDir, parameters.rootDir) + log.kotlinDebug(DISPOSE_MESSAGE) + + TaskLoggers.clear() + TaskExecutionResults.clear() + } companion object { - private val CLASS_NAME = KotlinGradleBuildServices::class.java.simpleName - const val FORCE_SYSTEM_GC_MESSAGE = "Forcing System.gc()" - const val SHOULD_REPORT_MEMORY_USAGE_PROPERTY = "kotlin.gradle.test.report.memory.usage" - val INIT_MESSAGE = "Initialized $CLASS_NAME" - val DISPOSE_MESSAGE = "Disposed $CLASS_NAME" - val ALREADY_INITIALIZED_MESSAGE = "$CLASS_NAME is already initialized" - - @field:Volatile - internal var instance: KotlinGradleBuildServices? = null - -// @JvmStatic -// @Synchronized -// fun getInstance(gradle: Gradle): KotlinGradleBuildServices { -// val log = Logging.getLogger(KotlinGradleBuildServices::class.java) -// -// if (instance != null) { -// log.kotlinDebug(ALREADY_INITIALIZED_MESSAGE) -// return instance!! -// } -// -// val services = KotlinGradleBuildServices(gradle) -// instance = services -// if (!isGradleVersionAtLeast(6,1)) { -// gradle.addBuildListener(services) -// log.kotlinDebug(INIT_MESSAGE) -// } else { -// BuildEventsListenerRegistry. -// } -// -// services.buildStarted() -// return services -// } - - - @JvmStatic - @Synchronized - fun getInstance(project: Project, listenerRegistryHolder: BuildEventsListenerRegistryHolder): KotlinGradleBuildServices { - val log = Logging.getLogger(KotlinGradleBuildServices::class.java) - val kotlinGradleListenerProvider: Provider = project.provider { - KotlinGradleBuildListener(KotlinGradleFinishBuildHandler()) - } + fun registerIfAbsent(project: Project): Provider = project.gradle.sharedServices.registerIfAbsent( + "kotlin-build-service-${KotlinGradleBuildServices::class.java.canonicalName}_${KotlinGradleBuildServices::class.java.classLoader.hashCode()}", + KotlinGradleBuildServices::class.java + ) { service -> + configureReporting(project.gradle) + service.parameters.rootDir = project.rootProject.rootDir + service.parameters.buildDir = project.rootProject.buildDir + addListeners(project) + } + fun addListeners(project: Project) { val kotlinGradleEsListenerProvider = project.provider { val listeners = project.rootProject.objects.listProperty(ReportStatistics::class.java) .value(listOf(ReportStatisticsToElasticSearch)) @@ -83,81 +70,41 @@ internal class KotlinGradleBuildServices private constructor( KotlinBuildEsStatListener(project.rootProject.name, listeners.get()) } + val listenerRegistryHolder = BuildEventsListenerRegistryHolder.getInstance(project) - if (instance != null) { - log.kotlinDebug(ALREADY_INITIALIZED_MESSAGE) - return instance!! - } - - val gradle = project.gradle - val services = KotlinGradleBuildServices(gradle, kotlinGradleListenerProvider, kotlinGradleEsListenerProvider) - if (isConfigurationCacheAvailable(gradle)) { - listenerRegistryHolder.listenerRegistry!!.onTaskCompletion(kotlinGradleListenerProvider) - listenerRegistryHolder.listenerRegistry.onTaskCompletion(kotlinGradleEsListenerProvider) - } else { - gradle.addBuildListener(services) - gradle.taskGraph.addTaskExecutionListener(kotlinGradleEsListenerProvider.get()) - log.kotlinDebug(INIT_MESSAGE) - } - instance = services - - services.buildStarted() - return services + listenerRegistryHolder.listenerRegistry.onTaskCompletion(kotlinGradleEsListenerProvider) } - } + private val multipleProjectsHolder = KotlinPluginInMultipleProjectsHolder( + trackPluginVersionsSeparately = true + ) - private val log = Logging.getLogger(this.javaClass) - private var buildHandler: KotlinGradleFinishBuildHandler? = null - - // There is function with the same name in BuildAdapter, - // but it is called before any plugin can attach build listener - fun buildStarted() { - buildHandler = KotlinGradleFinishBuildHandler() - buildHandler!!.buildStart() - - TaskLoggers.clear() - TaskExecutionResults.clear() - - configureReporting(gradle) - } - - override fun buildFinished(result: BuildResult) { - buildHandler!!.buildFinished(result.gradle!!) - instance = null - log.kotlinDebug(DISPOSE_MESSAGE) - } - - - private val multipleProjectsHolder = KotlinPluginInMultipleProjectsHolder( - trackPluginVersionsSeparately = true - ) - - @Synchronized - internal fun detectKotlinPluginLoadedInMultipleProjects(project: Project, kotlinPluginVersion: String) { - val onRegister = { - gradle.taskGraph.whenReady { - if (multipleProjectsHolder.isInMultipleProjects(project, kotlinPluginVersion)) { - val loadedInProjects = multipleProjectsHolder.getAffectedProjects(project, kotlinPluginVersion)!! - if (PropertiesProvider(project).ignorePluginLoadedInMultipleProjects != true) { - project.logger.warn("\n$MULTIPLE_KOTLIN_PLUGINS_LOADED_WARNING") - project.logger.warn( - MULTIPLE_KOTLIN_PLUGINS_SPECIFIC_PROJECTS_WARNING + loadedInProjects.joinToString(limit = 4) { "'$it'" } + @Synchronized + internal fun detectKotlinPluginLoadedInMultipleProjects(project: Project, kotlinPluginVersion: String) { + val onRegister = { + project.gradle.taskGraph.whenReady { + if (multipleProjectsHolder.isInMultipleProjects(project, kotlinPluginVersion)) { + val loadedInProjects = multipleProjectsHolder.getAffectedProjects(project, kotlinPluginVersion)!! + if (PropertiesProvider(project).ignorePluginLoadedInMultipleProjects != true) { + project.logger.warn("\n$MULTIPLE_KOTLIN_PLUGINS_LOADED_WARNING") + project.logger.warn( + MULTIPLE_KOTLIN_PLUGINS_SPECIFIC_PROJECTS_WARNING + loadedInProjects.joinToString(limit = 4) { "'$it'" } + ) + } + project.logger.info( + "$MULTIPLE_KOTLIN_PLUGINS_SPECIFIC_PROJECTS_INFO: " + + loadedInProjects.joinToString { "'$it'" } ) } - project.logger.info( - "$MULTIPLE_KOTLIN_PLUGINS_SPECIFIC_PROJECTS_INFO: " + - loadedInProjects.joinToString { "'$it'" } - ) } } - } - multipleProjectsHolder.addProject( - project, - kotlinPluginVersion, - onRegister - ) + multipleProjectsHolder.addProject( + project, + kotlinPluginVersion, + onRegister + ) + } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleFinishBuildHandler.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleFinishBuildHandler.kt index 58f0ea3b21e..03074b66c39 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleFinishBuildHandler.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleFinishBuildHandler.kt @@ -12,41 +12,45 @@ import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner import org.jetbrains.kotlin.gradle.logging.kotlinDebug import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskExecutionResults import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskLoggers -import org.jetbrains.kotlin.gradle.utils.relativeToRoot +import org.jetbrains.kotlin.gradle.utils.relativeOrCanonical import org.jetbrains.kotlin.utils.addToStdlib.sumByLong +import java.io.File import java.lang.management.ManagementFactory import kotlin.math.max -// move to KotlinGradleBuildListener when min supported version is 6.1 class KotlinGradleFinishBuildHandler { + companion object { + const val SHOULD_REPORT_MEMORY_USAGE_PROPERTY = "kotlin.gradle.test.report.memory.usage" + const val FORCE_SYSTEM_GC_MESSAGE = "Forcing System.gc()" + } + private val log = Logging.getLogger(this.javaClass) private var startMemory: Long? = null - private val shouldReportMemoryUsage = System.getProperty(KotlinGradleBuildServices.SHOULD_REPORT_MEMORY_USAGE_PROPERTY) != null + private val shouldReportMemoryUsage = System.getProperty(SHOULD_REPORT_MEMORY_USAGE_PROPERTY) != null fun buildStart() { startMemory = getUsedMemoryKb() } - fun buildFinished(gradle: Gradle) { + fun buildFinished(rootProjectBuildDir: File, rootProjectRootDir: File) { TaskLoggers.clear() TaskExecutionResults.clear() GradleCompilerRunner.clearBuildModulesInfo() - val rootProject = gradle.rootProject - val sessionsDir = GradleCompilerRunner.sessionsDir(rootProject.buildDir) + val sessionsDir = GradleCompilerRunner.sessionsDir(rootProjectBuildDir) if (sessionsDir.exists()) { val sessionFiles = sessionsDir.listFiles() // it is expected that only one session file per build exists // afaik is is not possible to run multiple gradle builds in one project since gradle locks some dirs if (sessionFiles.size > 1) { - log.warn("w: Detected multiple Kotlin daemon sessions at ${sessionsDir.relativeToRoot(rootProject)}") + log.warn("w: Detected multiple Kotlin daemon sessions at ${sessionsDir.relativeOrCanonical(rootProjectRootDir)}") } for (file in sessionFiles) { file.delete() - log.kotlinDebug { DELETED_SESSION_FILE_PREFIX + file.relativeToRoot(rootProject) } + log.kotlinDebug { DELETED_SESSION_FILE_PREFIX + file.relativeOrCanonical(rootProjectRootDir) } } } @@ -58,14 +62,17 @@ class KotlinGradleFinishBuildHandler { // but on subsequent runs in the daemon it should be rather small, then the classes are actually reused by the daemon (see above) log.lifecycle("[KOTLIN][PERF] Used memory after build: $endMem kb (difference since build start: ${"%+d".format(endMem - startMem)} kb)") } + } + fun buildFinished(gradle: Gradle) { + buildFinished(gradle.rootProject.buildDir, gradle.rootProject.rootDir) gradle.removeListener(this) } internal fun getUsedMemoryKb(): Long? { if (!shouldReportMemoryUsage) return null - log.lifecycle(KotlinGradleBuildServices.FORCE_SYSTEM_GC_MESSAGE) + log.lifecycle(FORCE_SYSTEM_GC_MESSAGE) val gcCountBefore = getGcCount() System.gc() while (getGcCount() == gcCountBefore) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt index a3d01eec927..701e0fa2c31 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt @@ -88,9 +88,9 @@ abstract class KotlinBasePluginWrapper: Plugin { } project.registerCommonizerClasspathConfigurationIfNecessary() - val kotlinGradleBuildServices = KotlinGradleBuildServices.getInstance(project, BuildEventsListenerRegistryHolder.getInstance(project)) + KotlinGradleBuildServices.registerIfAbsent(project).get() - kotlinGradleBuildServices.detectKotlinPluginLoadedInMultipleProjects(project, kotlinPluginVersion) + KotlinGradleBuildServices.detectKotlinPluginLoadedInMultipleProjects(project, kotlinPluginVersion) project.createKotlinExtension(projectExtensionClass).apply { coreLibrariesVersion = kotlinPluginVersion @@ -106,7 +106,7 @@ abstract class KotlinBasePluginWrapper: Plugin { project.extensions.add(KotlinTestsRegistry.PROJECT_EXTENSION_NAME, createTestRegistry(project)) - val plugin = getPlugin(project, kotlinGradleBuildServices) + val plugin = getPlugin(project) setupAttributeMatchingStrategy(project) @@ -151,14 +151,13 @@ abstract class KotlinBasePluginWrapper: Plugin { internal abstract fun getPlugin( project: Project, - kotlinGradleBuildServices: KotlinGradleBuildServices ): Plugin } open class KotlinPluginWrapper @Inject constructor( protected val registry: ToolingModelBuilderRegistry ) : KotlinBasePluginWrapper() { - override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin = + override fun getPlugin(project: Project): Plugin = KotlinPlugin(registry) override val projectExtensionClass: KClass @@ -168,7 +167,7 @@ open class KotlinPluginWrapper @Inject constructor( open class KotlinCommonPluginWrapper @Inject constructor( protected val registry: ToolingModelBuilderRegistry ) : KotlinBasePluginWrapper() { - override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin = + override fun getPlugin(project: Project): Plugin = KotlinCommonPlugin(registry) override val projectExtensionClass: KClass @@ -178,7 +177,7 @@ open class KotlinCommonPluginWrapper @Inject constructor( open class KotlinAndroidPluginWrapper @Inject constructor( protected val registry: ToolingModelBuilderRegistry ) : KotlinBasePluginWrapper() { - override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin = + override fun getPlugin(project: Project): Plugin = KotlinAndroidPlugin(registry) override val projectExtensionClass: KClass @@ -188,7 +187,7 @@ open class KotlinAndroidPluginWrapper @Inject constructor( open class Kotlin2JsPluginWrapper @Inject constructor( protected val registry: ToolingModelBuilderRegistry ) : KotlinBasePluginWrapper() { - override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin = + override fun getPlugin(project: Project): Plugin = Kotlin2JsPlugin(registry) override val projectExtensionClass: KClass @@ -196,7 +195,7 @@ open class Kotlin2JsPluginWrapper @Inject constructor( } open class KotlinJsPluginWrapper : KotlinBasePluginWrapper() { - override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin = + override fun getPlugin(project: Project): Plugin = KotlinJsPlugin(project.getKotlinPluginVersion()) override val projectExtensionClass: KClass @@ -227,7 +226,7 @@ open class KotlinJsPluginWrapper : KotlinBasePluginWrapper() { } open class KotlinMultiplatformPluginWrapper : KotlinBasePluginWrapper() { - override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin = + override fun getPlugin(project: Project): Plugin = KotlinMultiplatformPlugin() override val projectExtensionClass: KClass @@ -252,7 +251,7 @@ open class KotlinMultiplatformPluginWrapper : KotlinBasePluginWrapper() { open class KotlinPm20PluginWrapper @Inject constructor( private val objectFactory: ObjectFactory ) : KotlinBasePluginWrapper() { - override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin = + override fun getPlugin(project: Project): Plugin = objectFactory.newInstance(KotlinPm20GradlePlugin::class.java) override val projectExtensionClass: KClass diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt index ada4db768fb..9eb7ea76a2a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt @@ -108,7 +108,7 @@ class KotlinMultiplatformPlugin : Plugin { SingleActionPerBuild.run(project.rootProject, "cleanup-processed-metadata") { if (isConfigurationCacheAvailable(project.gradle)) { - BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry!!.onTaskCompletion( + BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion( project.gradle.sharedServices .registerIfAbsent( "cleanup-stale-sourceset-metadata", diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/report/configureReporing.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/report/configureReporing.kt index 9d60d43c928..ab539e674f2 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/report/configureReporing.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/report/configureReporing.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.report import org.gradle.api.Project import org.gradle.api.invocation.Gradle +import org.gradle.api.logging.Logger import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider import org.jetbrains.kotlin.gradle.report.data.BuildExecutionDataProcessor import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile @@ -18,6 +19,7 @@ internal fun configureReporting(gradle: Gradle) { val buildDataProcessors = ArrayList() val rootProject = gradle.rootProject + val log = rootProject.logger val reportingSettings = reportingSettings(rootProject) gradle.taskGraph.whenReady { graph -> graph.allTasks.asSequence() @@ -26,13 +28,13 @@ internal fun configureReporting(gradle: Gradle) { } if (reportingSettings.buildReportMode != BuildReportMode.NONE && reportingSettings.buildReportDir != null) { - configurePlainTextReportWriter(gradle, reportingSettings)?.let { + configurePlainTextReportWriter(rootProject.name, log, reportingSettings)?.let { buildDataProcessors.add(it) } } if (reportingSettings.metricsOutputFile != null) { - buildDataProcessors.add(MetricsWriter(reportingSettings.metricsOutputFile.absoluteFile, rootProject.logger)) + buildDataProcessors.add(MetricsWriter(reportingSettings.metricsOutputFile.absoluteFile, log)) } if (buildDataProcessors.isNotEmpty() && !isConfigurationCacheAvailable(gradle)) { @@ -62,13 +64,13 @@ private fun reportingSettings(rootProject: Project): ReportingSettings { } private fun configurePlainTextReportWriter( - gradle: Gradle, + rootProjectName: String, + log: Logger, reportingSettings: ReportingSettings ): BuildExecutionDataProcessor? { - val log = gradle.rootProject.logger return reportingSettings.buildReportDir?.let { reportDir -> val ts = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(Calendar.getInstance().time) - val reportFile = reportDir.resolve("${gradle.rootProject.name}-build-$ts.txt") + val reportFile = reportDir.resolve("${rootProjectName}-build-$ts.txt") return PlainTextBuildReportWriter( outputFile = reportFile, diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/MultiplePluginDeclarationDetector.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/MultiplePluginDeclarationDetector.kt index d5239dc6555..6926c63310e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/MultiplePluginDeclarationDetector.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/MultiplePluginDeclarationDetector.kt @@ -10,7 +10,6 @@ import org.gradle.api.invocation.Gradle import org.jetbrains.kotlin.gradle.plugin.BuildFinishedListenerService import org.jetbrains.kotlin.gradle.plugin.KotlinPluginInMultipleProjectsHolder import org.jetbrains.kotlin.gradle.plugin.MULTIPLE_KOTLIN_PLUGINS_LOADED_WARNING -import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable internal class MultiplePluginDeclarationDetector private constructor() {