Create FUS plugin fus-statistics-gradle-plugin can be used by other Gradle plugins to collect additional metrics for FUS. KT-59627
diff --git a/libraries/tools/gradle/fus-statistics-gradle-plugin/ReadMe.md b/libraries/tools/gradle/fus-statistics-gradle-plugin/ReadMe.md new file mode 100644 index 0000000..5537fd1 --- /dev/null +++ b/libraries/tools/gradle/fus-statistics-gradle-plugin/ReadMe.md
@@ -0,0 +1,4 @@ +## Description + +Contains a plugin for FUS statistics. fus-statistics-gradle-plugin can be used by other Gradle plugins to +collect additional metrics for FUS.
diff --git a/libraries/tools/gradle/fus-statistics-gradle-plugin/build.gradle.kts b/libraries/tools/gradle/fus-statistics-gradle-plugin/build.gradle.kts new file mode 100644 index 0000000..1f93955 --- /dev/null +++ b/libraries/tools/gradle/fus-statistics-gradle-plugin/build.gradle.kts
@@ -0,0 +1,22 @@ +plugins { + id("gradle-plugin-common-configuration") +} + + +dependencies { + commonApi(project(":kotlin-gradle-plugin-api")) + commonApi(project(":kotlin-gradle-plugin")) + commonCompileOnly(gradleKotlinDsl()) +} + + +gradlePlugin { + plugins { + create("fus-statistics-gradle-plugin") { + id = "org.jetbrains.kotlin.fus-statistics-gradle-plugin" + displayName = "FusStatisticsPlugin" + description = displayName + implementationClass = "org.jetbrains.kotlin.gradle.fus.FusStatisticsPlugin" + } + } +} \ No newline at end of file
diff --git a/libraries/tools/gradle/fus-statistics-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/fus/FusStatisticsPlugin.kt b/libraries/tools/gradle/fus-statistics-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/fus/FusStatisticsPlugin.kt new file mode 100644 index 0000000..de90880 --- /dev/null +++ b/libraries/tools/gradle/fus-statistics-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/fus/FusStatisticsPlugin.kt
@@ -0,0 +1,19 @@ +package org.jetbrains.kotlin.gradle.fus + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.provider.ProviderFactory +import javax.inject.Inject + +/* + * 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. + */ + +class FusStatisticsPlugin @Inject constructor( + private val providerFactory: ProviderFactory +) : Plugin<Project> { + override fun apply(project: Project) { + GradleBuildFusStatisticsService.registerIfAbsent(project).get() + } +} \ No newline at end of file
diff --git a/libraries/tools/gradle/fus-statistics-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/fus/GradleBuildFusStatistics.kt b/libraries/tools/gradle/fus-statistics-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/fus/GradleBuildFusStatistics.kt new file mode 100644 index 0000000..b52353b --- /dev/null +++ b/libraries/tools/gradle/fus-statistics-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/fus/GradleBuildFusStatistics.kt
@@ -0,0 +1,12 @@ +/* + * 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.fus +interface GradleBuildFusStatistics { + fun reportBoolean(name: String, value: Boolean, subprojectName: String?, weight: Long?): Boolean + + fun reportNumber(name: String, value: Long, subprojectName: String?, weight: Long?): Boolean + + fun reportString(name: String, value: String, subprojectName: String?, weight: Long?): Boolean +} \ No newline at end of file
diff --git a/libraries/tools/gradle/fus-statistics-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/fus/GradleBuildFusStatisticsService.kt b/libraries/tools/gradle/fus-statistics-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/fus/GradleBuildFusStatisticsService.kt new file mode 100644 index 0000000..b6fb2d9 --- /dev/null +++ b/libraries/tools/gradle/fus-statistics-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/fus/GradleBuildFusStatisticsService.kt
@@ -0,0 +1,88 @@ +package org.jetbrains.kotlin.gradle.fus + + +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.gradle.api.services.BuildService +import org.gradle.api.services.BuildServiceParameters +import org.gradle.api.tasks.Internal +import org.gradle.kotlin.dsl.withType + + +internal interface UsesGradleBuildFusStatisticsService : Task { + @get:Internal + val fusStatisticsBuildService: Property<GradleBuildFusStatisticsService?> +} + +internal abstract class GradleBuildFusStatisticsService : GradleBuildFusStatistics, + BuildService<GradleBuildFusStatisticsService.Parameters>, AutoCloseable { + + interface Parameters : BuildServiceParameters { + val path: Property<String> + val statisticsIsEnabled: Property<Boolean> + } + + override fun close() { + } + + companion object { + private const val CUSTOM_LOGGER_ROOT_PATH = "kotlin.session.logger.root.path" + private const val STATISTICS_FOLDER_NAME = "kotlin-fus" + private const val STATISTICS_FILE_NAME_PATTERN = "\\d{4}-\\d{2}-\\d{2}-\\d{2}-\\d{2}-\\d{2}-\\d{3}(.\\d+)?.profile" + + private const val BUILD_SESSION_SEPARATOR = "BUILD FINISHED" + + + private var statisticsIsEnabled: Boolean = true //KT-59629 Wait for user confirmation before start to collect metrics + private val serviceClass = GradleBuildFusStatisticsService::class.java + private val serviceName = "${serviceClass.name}_${serviceClass.classLoader.hashCode()}" + + fun registerIfAbsent(project: Project): Provider<GradleBuildFusStatisticsService> { + project.gradle.sharedServices.registrations.findByName(serviceName)?.let { + @Suppress("UNCHECKED_CAST") + return it.service as Provider<GradleBuildFusStatisticsService> + } + + return if (statisticsIsEnabled) { + project.gradle.sharedServices.registerIfAbsent(serviceName, serviceClass) { + val customPath: String = if (project.rootProject.hasProperty(CUSTOM_LOGGER_ROOT_PATH)) { + project.rootProject.property(CUSTOM_LOGGER_ROOT_PATH) as String + } else { + project.gradle.gradleUserHomeDir.path //fix + } + it.parameters.path.set(customPath) + } + } else { + project.gradle.sharedServices.registerIfAbsent(serviceName, DummyGradleBuildFusStatisticsService::class.java) {} + .map { it as GradleBuildFusStatisticsService } + }.also { configureTasks(project, it) } + } + + private fun configureTasks(project: Project, serviceProvider: Provider<GradleBuildFusStatisticsService>) { + project.tasks.withType<UsesGradleBuildFusStatisticsService>().configureEach { task -> + task.fusStatisticsBuildService.value(serviceProvider).disallowChanges() + task.usesService(serviceProvider) + } + } + } +} + +internal abstract class DummyGradleBuildFusStatisticsService : GradleBuildFusStatisticsService() { + override fun reportBoolean(name: String, value: Boolean, subprojectName: String?, weight: Long?): Boolean { + //do nothing + return true + } + + override fun reportNumber(name: String, value: Long, subprojectName: String?, weight: Long?): Boolean { + //do nothing + return true + } + + override fun reportString(name: String, value: String, subprojectName: String?, weight: Long?): Boolean { + //do nothing + return true + } + +} \ No newline at end of file
diff --git a/settings.gradle b/settings.gradle index 8f596fe..a24e9a5 100644 --- a/settings.gradle +++ b/settings.gradle
@@ -216,6 +216,7 @@ ":gradle:kotlin-compiler-args-properties", ":gradle:regression-benchmark-templates", ":gradle:regression-benchmarks", + ":gradle:fus-statistics-gradle-plugin", ":kotlin-tooling-metadata", ":kotlin-tooling-core", ":kotlin-allopen", @@ -758,6 +759,7 @@ project(':gradle:gradle-warnings-detector').projectDir = "$rootDir/libraries/tools/gradle/gradle-warnings-detector" as File project(':gradle:kotlin-compiler-args-properties').projectDir = "$rootDir/libraries/tools/gradle/kotlin-compiler-args-properties" as File project(":gradle:regression-benchmark-templates").projectDir = "$rootDir/libraries/tools/gradle/regression-benchmark-templates" as File +project(":gradle:kotlin-compiler-args-properties").projectDir = "$rootDir/libraries/tools/gradle/fus-statistics-gradle-plugin" as File project(":gradle:regression-benchmarks").projectDir = "$rootDir/libraries/tools/gradle/regression-benchmarks" as File project(':kotlin-tooling-metadata').projectDir = "$rootDir/libraries/tools/kotlin-tooling-metadata" as File project(':kotlin-tooling-core').projectDir = "$rootDir/libraries/tools/kotlin-tooling-core" as File