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