KT-49159 Transform KotlinGradleBuildService to BuildService
This commit is contained in:
+5
@@ -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
|
||||
|
||||
+1
-1
@@ -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)
|
||||
|
||||
|
||||
+7
-4
@@ -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)
|
||||
|
||||
+1
-1
@@ -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")
|
||||
|
||||
+7
-2
@@ -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<KotlinSourceSet>.sorted() = this.sortedBy { it.name }
|
||||
|
||||
+1
-1
@@ -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")
|
||||
|
||||
+3
-1
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -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
|
||||
|
||||
|
||||
+1
@@ -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
|
||||
|
||||
+1
@@ -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")
|
||||
|
||||
|
||||
+45
@@ -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<Any> = state.get(projectScopeServices) as AtomicReference<Any>
|
||||
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<out OperationCompletionListener>?) {
|
||||
}
|
||||
|
||||
}
|
||||
+3
@@ -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 }
|
||||
|
||||
|
||||
+1
-6
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+66
-119
@@ -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<out OperationCompletionListener>
|
||||
) : BuildAdapter() {
|
||||
abstract class KotlinGradleBuildServices : BuildService<KotlinGradleBuildServices.Parameters>, 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<KotlinGradleBuildListener> = project.provider {
|
||||
KotlinGradleBuildListener(KotlinGradleFinishBuildHandler())
|
||||
}
|
||||
fun registerIfAbsent(project: Project): Provider<KotlinGradleBuildServices> = 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<ReportStatistics>(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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
-9
@@ -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) {
|
||||
|
||||
+10
-11
@@ -88,9 +88,9 @@ abstract class KotlinBasePluginWrapper: Plugin<Project> {
|
||||
}
|
||||
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> {
|
||||
|
||||
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<Project> {
|
||||
|
||||
internal abstract fun getPlugin(
|
||||
project: Project,
|
||||
kotlinGradleBuildServices: KotlinGradleBuildServices
|
||||
): Plugin<Project>
|
||||
}
|
||||
|
||||
open class KotlinPluginWrapper @Inject constructor(
|
||||
protected val registry: ToolingModelBuilderRegistry
|
||||
) : KotlinBasePluginWrapper() {
|
||||
override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin<Project> =
|
||||
override fun getPlugin(project: Project): Plugin<Project> =
|
||||
KotlinPlugin(registry)
|
||||
|
||||
override val projectExtensionClass: KClass<out KotlinJvmProjectExtension>
|
||||
@@ -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<Project> =
|
||||
override fun getPlugin(project: Project): Plugin<Project> =
|
||||
KotlinCommonPlugin(registry)
|
||||
|
||||
override val projectExtensionClass: KClass<out KotlinCommonProjectExtension>
|
||||
@@ -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<Project> =
|
||||
override fun getPlugin(project: Project): Plugin<Project> =
|
||||
KotlinAndroidPlugin(registry)
|
||||
|
||||
override val projectExtensionClass: KClass<out KotlinAndroidProjectExtension>
|
||||
@@ -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<Project> =
|
||||
override fun getPlugin(project: Project): Plugin<Project> =
|
||||
Kotlin2JsPlugin(registry)
|
||||
|
||||
override val projectExtensionClass: KClass<out Kotlin2JsProjectExtension>
|
||||
@@ -196,7 +195,7 @@ open class Kotlin2JsPluginWrapper @Inject constructor(
|
||||
}
|
||||
|
||||
open class KotlinJsPluginWrapper : KotlinBasePluginWrapper() {
|
||||
override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin<Project> =
|
||||
override fun getPlugin(project: Project): Plugin<Project> =
|
||||
KotlinJsPlugin(project.getKotlinPluginVersion())
|
||||
|
||||
override val projectExtensionClass: KClass<out KotlinJsProjectExtension>
|
||||
@@ -227,7 +226,7 @@ open class KotlinJsPluginWrapper : KotlinBasePluginWrapper() {
|
||||
}
|
||||
|
||||
open class KotlinMultiplatformPluginWrapper : KotlinBasePluginWrapper() {
|
||||
override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin<Project> =
|
||||
override fun getPlugin(project: Project): Plugin<Project> =
|
||||
KotlinMultiplatformPlugin()
|
||||
|
||||
override val projectExtensionClass: KClass<out KotlinMultiplatformExtension>
|
||||
@@ -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<Project> =
|
||||
override fun getPlugin(project: Project): Plugin<Project> =
|
||||
objectFactory.newInstance(KotlinPm20GradlePlugin::class.java)
|
||||
|
||||
override val projectExtensionClass: KClass<out KotlinPm20ProjectExtension>
|
||||
|
||||
+1
-1
@@ -108,7 +108,7 @@ class KotlinMultiplatformPlugin : Plugin<Project> {
|
||||
|
||||
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",
|
||||
|
||||
+7
-5
@@ -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<BuildExecutionDataProcessor>()
|
||||
|
||||
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,
|
||||
|
||||
-1
@@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user