KT-33908 Make Kotlin Gradle plugin compatible with configuration cache
#KT-33908 Fixed
This commit is contained in:
committed by
nataliya.valtman
parent
ea57b4cccb
commit
a766369e72
+1
-1
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-20200603220033+0000-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
+1
-1
@@ -726,7 +726,7 @@ fun getSomething() = 10
|
||||
|
||||
project.build("assemble", options = options) {
|
||||
assertFailed()
|
||||
assertContains("Class 'User' is not abstract and does not implement abstract member public abstract fun writeToParcel")
|
||||
assertContainsRegex("Class 'User' is not abstract and does not implement abstract member public abstract fun (writeToParcel|describeContents)".toRegex())
|
||||
}
|
||||
|
||||
File(project.projectDir, "app/build.gradle").modify { it.replace("[\"views\"]", "[\"parcelize\", \"views\"]") }
|
||||
|
||||
+14
-4
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.gradle.model.ModelContainer
|
||||
import org.jetbrains.kotlin.gradle.model.ModelFetcherBuildAction
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinJsCompilerType
|
||||
import org.jetbrains.kotlin.gradle.util.*
|
||||
import org.jetbrains.kotlin.test.util.trimTrailingWhitespaces
|
||||
import org.junit.After
|
||||
import org.junit.AfterClass
|
||||
import org.junit.Assert
|
||||
@@ -22,6 +21,8 @@ import java.io.File
|
||||
import java.util.regex.Pattern
|
||||
import kotlin.test.*
|
||||
|
||||
import org.jetbrains.kotlin.test.util.trimTrailingWhitespaces
|
||||
|
||||
val SYSTEM_LINE_SEPARATOR: String = System.getProperty("line.separator")
|
||||
|
||||
abstract class BaseGradleIT {
|
||||
@@ -205,9 +206,15 @@ abstract class BaseGradleIT {
|
||||
val withBuildCache: Boolean = false,
|
||||
val kaptOptions: KaptOptions? = null,
|
||||
val parallelTasksInProject: Boolean? = null,
|
||||
val jsCompilerType: KotlinJsCompilerType? = null
|
||||
val jsCompilerType: KotlinJsCompilerType? = null,
|
||||
val configurationCache: Boolean = false,
|
||||
val configurationCacheProblems: ConfigurationCacheProblems = ConfigurationCacheProblems.FAIL
|
||||
)
|
||||
|
||||
enum class ConfigurationCacheProblems {
|
||||
FAIL, WARN
|
||||
}
|
||||
|
||||
data class KaptOptions(
|
||||
val verbose: Boolean,
|
||||
val useWorkers: Boolean,
|
||||
@@ -707,9 +714,9 @@ Finished executing task ':$taskName'|
|
||||
val xmlString = buildString {
|
||||
appendln("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
|
||||
appendln("<results>")
|
||||
files.forEach {
|
||||
files.forEach { file ->
|
||||
appendln(
|
||||
it.readText()
|
||||
file.readText()
|
||||
.trimTrailingWhitespaces()
|
||||
.replace(projectDir.absolutePath, "/\$PROJECT_DIR$")
|
||||
.replace(projectDir.name, "\$PROJECT_NAME$")
|
||||
@@ -801,6 +808,9 @@ Finished executing task ':$taskName'|
|
||||
add("-Pkotlin.js.compiler=$it")
|
||||
}
|
||||
|
||||
add("-Dorg.gradle.unsafe.configuration-cache=${options.configurationCache}")
|
||||
add("-Dorg.gradle.unsafe.configuration-cache-problems=${options.configurationCacheProblems.name.toLowerCase()}")
|
||||
|
||||
// Workaround: override a console type set in the user machine gradle.properties (since Gradle 4.3):
|
||||
add("--console=plain")
|
||||
addAll(options.freeCommandLineArgs)
|
||||
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.jetbrains.kotlin.gradle.util.AGPVersion
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.junit.Test
|
||||
|
||||
class ConfigurationCacheForAndroidIT : AbstractConfigurationCacheIT() {
|
||||
private val androidGradlePluginVersion: AGPVersion
|
||||
get() = AGPVersion.v4_2_0
|
||||
|
||||
override fun defaultBuildOptions() =
|
||||
super.defaultBuildOptions().copy(
|
||||
androidHome = KotlinTestUtils.findAndroidSdk(),
|
||||
androidGradlePluginVersion = androidGradlePluginVersion,
|
||||
configurationCache = true,
|
||||
/* AGP causes a configuration cache problem:
|
||||
- plugin 'com.android.internal.application': registration of listener on 'TaskExecutionGraph.addTaskExecutionListener' is unsupported
|
||||
|
||||
which causes tests to fail when configuration-cache-problems=fail is used.
|
||||
However, everything works fine with WARN level reporting.
|
||||
TODO: switch to FAIL when AGP no longer causes the cache problem
|
||||
*/
|
||||
configurationCacheProblems = ConfigurationCacheProblems.WARN
|
||||
)
|
||||
|
||||
@Test
|
||||
fun testAndroidKaptProject() = with(Project("android-dagger", directoryPrefix = "kapt2")) {
|
||||
applyAndroid40Alpha4KotlinVersionWorkaround()
|
||||
projectDir.resolve("gradle.properties").appendText("\nkapt.incremental.apt=false")
|
||||
testConfigurationCacheOf(":app:compileDebugKotlin", ":app:kaptDebugKotlin", ":app:kaptGenerateStubsDebugKotlin")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testKotlinAndroidProject() = with(Project("AndroidProject")) {
|
||||
applyAndroid40Alpha4KotlinVersionWorkaround()
|
||||
testConfigurationCacheOf(":Lib:compileFlavor1DebugKotlin", ":Android:compileFlavor1DebugKotlin")
|
||||
}
|
||||
|
||||
/**
|
||||
* Android Gradle plugin 4.0-alpha4 depends on the EAP versions of some o.j.k modules.
|
||||
* Force the current Kotlin version, so the EAP versions are not queried from the
|
||||
* test project's repositories, where there's no 'kotlin-eap' repo.
|
||||
* TODO remove this workaround once an Android Gradle plugin version is used that depends on the stable Kotlin version
|
||||
*/
|
||||
private fun Project.applyAndroid40Alpha4KotlinVersionWorkaround() {
|
||||
setupWorkingDir()
|
||||
|
||||
val resolutionStrategyHack = """
|
||||
configurations.all {
|
||||
resolutionStrategy.dependencySubstitution.all { dependency ->
|
||||
def requested = dependency.requested
|
||||
if (requested instanceof ModuleComponentSelector && requested.group == 'org.jetbrains.kotlin') {
|
||||
dependency.useTarget requested.group + ':' + requested.module + ':' + '${defaultBuildOptions().kotlinVersion}'
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
gradleBuildScript().appendText(
|
||||
"\n" + """
|
||||
buildscript {
|
||||
$resolutionStrategyHack
|
||||
}
|
||||
$resolutionStrategyHack
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
+118
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.jetbrains.kotlin.gradle.util.findFileByName
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
import java.net.URI
|
||||
import java.util.Arrays.asList
|
||||
import kotlin.test.fail
|
||||
|
||||
class ConfigurationCacheIT : AbstractConfigurationCacheIT() {
|
||||
@Test
|
||||
fun testSimpleKotlinJvmProject() = with(Project("kotlinProject")) {
|
||||
testConfigurationCacheOf(":compileKotlin")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIncrementalKaptProject() = with(Project("kaptIncrementalCompilationProject")) {
|
||||
setupIncrementalAptProject("AGGREGATING")
|
||||
|
||||
testConfigurationCacheOf(
|
||||
":compileKotlin",
|
||||
":kaptKotlin",
|
||||
buildOptions = defaultBuildOptions().copy(
|
||||
incremental = true,
|
||||
kaptOptions = KaptOptions(
|
||||
verbose = true,
|
||||
useWorkers = true,
|
||||
incrementalKapt = true,
|
||||
includeCompileClasspath = false
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInstantExecution() = with(Project("instantExecution")) {
|
||||
testConfigurationCacheOf("assemble", executedTaskNames = asList(":lib-project:compileKotlin"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testInstantExecutionForJs() = with(Project("instantExecutionToJs")) {
|
||||
testConfigurationCacheOf("assemble", executedTaskNames = asList(":compileKotlin2Js"))
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractConfigurationCacheIT : BaseGradleIT() {
|
||||
override fun defaultBuildOptions() =
|
||||
super.defaultBuildOptions().copy(configurationCache = true)
|
||||
|
||||
override val defaultGradleVersion: GradleVersionRequired = GradleVersionRequired.AtLeast("6.6-rc-3")
|
||||
|
||||
protected fun Project.testConfigurationCacheOf(
|
||||
vararg taskNames: String,
|
||||
executedTaskNames: List<String>? = null,
|
||||
buildOptions: BuildOptions = defaultBuildOptions()
|
||||
) {
|
||||
// First, run a build that serializes the tasks state for instant execution in further builds
|
||||
|
||||
val executedTask: List<String> = executedTaskNames ?: taskNames.toList()
|
||||
|
||||
build(*taskNames, options = buildOptions) {
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(executedTask)
|
||||
assertContains("Calculating task graph as no configuration cache is available for tasks: ${taskNames.joinToString(separator = " ")}")
|
||||
checkInstantExecutionSucceeded()
|
||||
}
|
||||
|
||||
build("clean") {
|
||||
assertSuccessful()
|
||||
}
|
||||
|
||||
// Then run a build where tasks states are deserialized to check that they work correctly in this mode
|
||||
build(*taskNames, options = buildOptions) {
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(executedTask)
|
||||
assertContains("Reusing configuration cache.")
|
||||
}
|
||||
|
||||
build(*taskNames, options = buildOptions) {
|
||||
assertSuccessful()
|
||||
assertTasksUpToDate(executedTask)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Project.checkInstantExecutionSucceeded() {
|
||||
instantExecutionReportFile()?.let { htmlReportFile ->
|
||||
fail("Instant execution problems were found, check ${htmlReportFile.asClickableFileUrl()} for details.")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all files from the directory containing the given [htmlReportFile] to a
|
||||
* fresh temp dir and returns a reference to the copied [htmlReportFile] in the new
|
||||
* directory.
|
||||
*/
|
||||
private fun copyReportToTempDir(htmlReportFile: File): File =
|
||||
createTempDir().let { tempDir ->
|
||||
htmlReportFile.parentFile.copyRecursively(tempDir)
|
||||
tempDir.resolve(htmlReportFile.name)
|
||||
}
|
||||
|
||||
/**
|
||||
* The instant execution report file, if exists, indicates problems were
|
||||
* found while caching the task graph.
|
||||
*/
|
||||
private fun Project.instantExecutionReportFile() = projectDir
|
||||
.resolve("configuration-cache")
|
||||
.findFileByName("configuration-cache-report.html")
|
||||
?.let { copyReportToTempDir(it) }
|
||||
|
||||
private fun File.asClickableFileUrl(): String =
|
||||
URI("file", "", toURI().path, null, null).toString()
|
||||
}
|
||||
-149
@@ -1,149 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.jetbrains.kotlin.gradle.util.AGPVersion
|
||||
import org.jetbrains.kotlin.gradle.util.findFileByName
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
import java.net.URI
|
||||
import kotlin.test.fail
|
||||
|
||||
class InstantExecutionIT : BaseGradleIT() {
|
||||
private val androidGradlePluginVersion: AGPVersion
|
||||
get() = AGPVersion.v4_0_ALPHA_8
|
||||
|
||||
override fun defaultBuildOptions() =
|
||||
super.defaultBuildOptions().copy(
|
||||
androidHome = KotlinTestUtils.findAndroidSdk(),
|
||||
androidGradlePluginVersion = androidGradlePluginVersion
|
||||
)
|
||||
|
||||
private val minimumGradleVersion = GradleVersionRequired.AtLeast("6.1-rc-3")
|
||||
|
||||
@Test
|
||||
fun testSimpleKotlinJvmProject() = with(Project("kotlinProject", minimumGradleVersion)) {
|
||||
testInstantExecutionOf(":compileKotlin")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSimpleKotlinAndroidProject() = with(Project("android-dagger", minimumGradleVersion, "kapt2")) {
|
||||
applyAndroid40Alpha4KotlinVersionWorkaround()
|
||||
projectDir.resolve("gradle.properties").appendText("\nkapt.incremental.apt=false")
|
||||
testInstantExecutionOf(":app:compileDebugKotlin", ":app:kaptDebugKotlin", ":app:kaptGenerateStubsDebugKotlin")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIncrementalKaptProject() = with(getIncrementalKaptProject()) {
|
||||
testInstantExecutionOf(
|
||||
":compileKotlin",
|
||||
":kaptKotlin",
|
||||
buildOptions = defaultBuildOptions().copy(
|
||||
incremental = true,
|
||||
kaptOptions = KaptOptions(
|
||||
verbose = true,
|
||||
useWorkers = true,
|
||||
incrementalKapt = true,
|
||||
includeCompileClasspath = false
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun getIncrementalKaptProject() =
|
||||
Project("kaptIncrementalCompilationProject", minimumGradleVersion).apply {
|
||||
setupIncrementalAptProject("AGGREGATING")
|
||||
}
|
||||
|
||||
private fun Project.testInstantExecutionOf(vararg taskNames: String, buildOptions: BuildOptions = defaultBuildOptions()) {
|
||||
// First, run a build that serializes the tasks state for instant execution in further builds
|
||||
instantExecutionOf(*taskNames, buildOptions = buildOptions) {
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(*taskNames)
|
||||
checkInstantExecutionSucceeded()
|
||||
}
|
||||
|
||||
build("clean") {
|
||||
assertSuccessful()
|
||||
}
|
||||
|
||||
// Then run a build where tasks states are deserialized to check that they work correctly in this mode
|
||||
instantExecutionOf(*taskNames, buildOptions = buildOptions) {
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(*taskNames)
|
||||
}
|
||||
|
||||
instantExecutionOf(*taskNames, buildOptions = buildOptions) {
|
||||
assertSuccessful()
|
||||
assertTasksUpToDate(*taskNames)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Project.checkInstantExecutionSucceeded() {
|
||||
instantExecutionReportFile()?.let { htmlReportFile ->
|
||||
fail("Instant execution problems were found, check ${htmlReportFile.asClickableFileUrl()} for details.")
|
||||
}
|
||||
}
|
||||
|
||||
private fun Project.instantExecutionOf(
|
||||
vararg tasks: String,
|
||||
buildOptions: BuildOptions = defaultBuildOptions(),
|
||||
check: CompiledProject.() -> Unit
|
||||
) =
|
||||
build("-Dorg.gradle.unsafe.instant-execution=true", *tasks, options = buildOptions, check = check)
|
||||
|
||||
/**
|
||||
* Copies all files from the directory containing the given [htmlReportFile] to a
|
||||
* fresh temp dir and returns a reference to the copied [htmlReportFile] in the new
|
||||
* directory.
|
||||
*/
|
||||
private fun copyReportToTempDir(htmlReportFile: File): File =
|
||||
createTempDir().let { tempDir ->
|
||||
htmlReportFile.parentFile.copyRecursively(tempDir)
|
||||
tempDir.resolve(htmlReportFile.name)
|
||||
}
|
||||
|
||||
/**
|
||||
* The instant execution report file, if exists, indicates problems were
|
||||
* found while caching the task graph.
|
||||
*/
|
||||
private fun Project.instantExecutionReportFile() = projectDir
|
||||
.resolve(".instant-execution-state")
|
||||
.findFileByName("instant-execution-report.html")
|
||||
?.let { copyReportToTempDir(it) }
|
||||
|
||||
private fun File.asClickableFileUrl(): String =
|
||||
URI("file", "", toURI().path, null, null).toString()
|
||||
|
||||
/**
|
||||
* Android Gradle plugin 4.0-alpha4 depends on the EAP versions of some o.j.k modules.
|
||||
* Force the current Kotlin version, so the EAP versions are not queried from the
|
||||
* test project's repositories, where there's no 'kotlin-eap' repo.
|
||||
* TODO remove this workaround once an Android Gradle plugin version is used that depends on the stable Kotlin version
|
||||
*/
|
||||
private fun Project.applyAndroid40Alpha4KotlinVersionWorkaround() {
|
||||
setupWorkingDir()
|
||||
|
||||
val resolutionStrategyHack = """
|
||||
configurations.all {
|
||||
resolutionStrategy.dependencySubstitution.all { dependency ->
|
||||
def requested = dependency.requested
|
||||
if (requested instanceof ModuleComponentSelector && requested.group == 'org.jetbrains.kotlin') {
|
||||
dependency.useTarget requested.group + ':' + requested.module + ':' + '${defaultBuildOptions().kotlinVersion}'
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
gradleBuildScript().appendText("\n" + """
|
||||
buildscript {
|
||||
$resolutionStrategyHack
|
||||
}
|
||||
$resolutionStrategyHack
|
||||
""".trimIndent())
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -365,7 +365,7 @@ class KotlinGradleIT : BaseGradleIT() {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDowngradeTo106() {
|
||||
fun testDowngradePluginVersion() {
|
||||
val project = Project("kotlinProject")
|
||||
val options = defaultBuildOptions().copy(incremental = true, withDaemon = false)
|
||||
|
||||
@@ -373,7 +373,7 @@ class KotlinGradleIT : BaseGradleIT() {
|
||||
assertSuccessful()
|
||||
}
|
||||
|
||||
project.build("clean", "assemble", options = options.copy(kotlinVersion = "1.0.6")) {
|
||||
project.build("clean", "assemble", options = options.copy(kotlinVersion = "1.3.41")) {
|
||||
assertSuccessful()
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -78,7 +78,9 @@ class UpToDateIT : BaseGradleIT() {
|
||||
val originalPaths get() = originalCompilerCp.map { it.replace("\\", "/") }.joinToString(", ") { "'$it'" }
|
||||
|
||||
override fun initProject(project: Project) = with(project) {
|
||||
buildGradle.appendText("\nprintln 'compiler_cp=' + compileKotlin.getComputedCompilerClasspath\$kotlin_gradle_plugin()")
|
||||
buildGradle.appendText(
|
||||
"\nafterEvaluate { println 'compiler_cp=' + compileKotlin.getComputedCompilerClasspath\$kotlin_gradle_plugin() }"
|
||||
)
|
||||
build("clean") { originalCompilerCp = "compiler_cp=\\[(.*)]".toRegex().find(output)!!.groupValues[1].split(", ") }
|
||||
buildGradle.appendText("""${'\n'}
|
||||
// Add Kapt to the project to test its input checks as well:
|
||||
|
||||
+2
-1
@@ -24,6 +24,7 @@ class AGPVersion private constructor(private val versionNumber: VersionNumber) {
|
||||
val v3_3_2 = fromString("3.3.2")
|
||||
val v3_4_1 = fromString("3.4.1")
|
||||
val v3_6_0 = fromString("3.6.0")
|
||||
val v4_0_ALPHA_8 = fromString("4.0.0-alpha08")
|
||||
val v4_1_0 = fromString("4.1.0-beta02")
|
||||
val v4_2_0 = fromString("4.2.0-alpha07")
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
subprojects {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
apply plugin: 'kotlin'
|
||||
|
||||
dependencies {
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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 libproject
|
||||
|
||||
class Util {
|
||||
val projectName: String = "lib-project"
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
apply plugin: 'kotlin'
|
||||
|
||||
dependencies {
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
compile project(':lib-project')
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import libProject.Util
|
||||
|
||||
/*
|
||||
* Copyright 2010-2020 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.
|
||||
*/
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
println(Util.projectName)
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
include ':main-project', ':lib-project'
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'kotlin2js'
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib-js:$kotlin_version"
|
||||
testCompile "org.jetbrains.kotlin:kotlin-test-js:$kotlin_version"
|
||||
}
|
||||
|
||||
task jarSources(type: Jar) {
|
||||
from sourceSets.main.allSource
|
||||
classifier = 'source'
|
||||
}
|
||||
artifacts {
|
||||
compile jarSources
|
||||
}
|
||||
|
||||
compileKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlin2js/main/module.js"
|
||||
compileTestKotlin2Js.kotlinOptions.outputFile = "${buildDir}/kotlin2js/test/module-tests.js"
|
||||
|
||||
if (project.findProperty("kotlin.js.useIrBackend")?.toBoolean() == true) {
|
||||
compileKotlin2Js.kotlinOptions.freeCompilerArgs += ["-Xir-produce-klib-dir", "-Xir-only"]
|
||||
compileTestKotlin2Js.kotlinOptions.freeCompilerArgs += ["-Xir-produce-js"]
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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 project
|
||||
|
||||
class Main {
|
||||
fun value(): String = "instant"
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.
|
||||
*/
|
||||
import project.Main
|
||||
import kotlin.test.*
|
||||
|
||||
class MainTest {
|
||||
@Test
|
||||
fun mySimpleTest() {
|
||||
assertEquals("instant", Main().value())
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -2,12 +2,12 @@ apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion "29.0.2"
|
||||
compileSdkVersion 26
|
||||
buildToolsVersion "28.0.3"
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 29
|
||||
minSdkVersion 26
|
||||
targetSdkVersion 26
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -2,12 +2,12 @@ apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
buildToolsVersion "29.0.2"
|
||||
compileSdkVersion 26
|
||||
buildToolsVersion "28.0.3"
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 29
|
||||
minSdkVersion 26
|
||||
targetSdkVersion 26
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-4
@@ -5,17 +5,18 @@
|
||||
|
||||
package org.jetbrains.kotlin.compilerRunner
|
||||
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.workers.IsolationMode
|
||||
import org.gradle.workers.WorkerExecutor
|
||||
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
|
||||
import org.jetbrains.kotlin.gradle.tasks.GradleCompileTaskProvider
|
||||
|
||||
internal class GradleCompilerRunnerWithWorkers(
|
||||
task: Task,
|
||||
taskProvider: GradleCompileTaskProvider,
|
||||
private val workersExecutor: WorkerExecutor
|
||||
) : GradleCompilerRunner(task) {
|
||||
) : GradleCompilerRunner(taskProvider) {
|
||||
|
||||
override fun runCompilerAsync(workArgs: GradleKotlinCompilerWorkArguments) {
|
||||
task.logger.kotlinDebug { "Starting Kotlin compiler work from task '${task.path}'" }
|
||||
loggerProvider.kotlinDebug { "Starting Kotlin compiler work from task '${pathProvider}'" }
|
||||
// todo: write tests with Workers enabled;
|
||||
workersExecutor.submit(GradleKotlinCompilerWork::class.java) { config ->
|
||||
config.isolationMode = IsolationMode.NONE
|
||||
|
||||
+38
-21
@@ -6,8 +6,8 @@
|
||||
package org.jetbrains.kotlin.compilerRunner
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.invocation.Gradle
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.api.plugins.JavaPluginConvention
|
||||
import org.gradle.api.tasks.bundling.AbstractArchiveTask
|
||||
import org.gradle.jvm.tasks.Jar
|
||||
@@ -24,11 +24,12 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinWithJavaTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.isMain
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.ownModuleName
|
||||
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
|
||||
import org.jetbrains.kotlin.gradle.tasks.GradleCompileTaskProvider
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompileTaskData
|
||||
import org.jetbrains.kotlin.gradle.tasks.locateTask
|
||||
import org.jetbrains.kotlin.gradle.utils.archivePathCompatible
|
||||
import org.jetbrains.kotlin.gradle.utils.newTmpFile
|
||||
import org.jetbrains.kotlin.gradle.utils.relativeToRoot
|
||||
import org.jetbrains.kotlin.gradle.utils.relativeOrCanonical
|
||||
import org.jetbrains.kotlin.incremental.IncrementalModuleEntry
|
||||
import org.jetbrains.kotlin.incremental.IncrementalModuleInfo
|
||||
import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics
|
||||
@@ -50,9 +51,21 @@ const val COULD_NOT_CONNECT_TO_DAEMON_MESSAGE = "Could not connect to Kotlin com
|
||||
internal fun kotlinCompilerExecutionStrategy(): String =
|
||||
System.getProperty(KOTLIN_COMPILER_EXECUTION_STRATEGY_PROPERTY) ?: DAEMON_EXECUTION_STRATEGY
|
||||
|
||||
internal open class GradleCompilerRunner(protected val task: Task) {
|
||||
protected val project: Project
|
||||
get() = task.project
|
||||
/*
|
||||
Using real taskProvider cause "field 'taskProvider' from type 'org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner':
|
||||
value 'fixed(class org.jetbrains.kotlin.gradle.tasks.KotlinCompile_Decorated, task ':compileKotlin')'
|
||||
is not assignable to 'org.gradle.api.tasks.TaskProvider'" exception
|
||||
*/
|
||||
internal open class GradleCompilerRunner(protected val taskProvider: GradleCompileTaskProvider) {
|
||||
|
||||
internal val pathProvider = taskProvider.path
|
||||
internal val loggerProvider = taskProvider.logger
|
||||
internal val buildDirProvider = taskProvider.buildDir
|
||||
internal val projectDirProvider = taskProvider.projectDir
|
||||
internal val projectRootDirProvider = taskProvider.rootDir
|
||||
internal val sessionDirProvider = taskProvider.sessionsDir
|
||||
internal val projectNameProvider = taskProvider.projectName
|
||||
internal val incrementalModuleInfoProvider = taskProvider.buildModulesInfo
|
||||
|
||||
/**
|
||||
* Compiler might be executed asynchronously. Do not do anything requiring end of compilation after this function is called.
|
||||
@@ -107,7 +120,7 @@ internal open class GradleCompilerRunner(protected val task: Task) {
|
||||
environment: GradleCompilerEnvironment
|
||||
) {
|
||||
if (compilerArgs.version) {
|
||||
task.logger.lifecycle(
|
||||
loggerProvider.lifecycle(
|
||||
"Kotlin version " + loadCompilerVersion(environment.compilerClasspath) +
|
||||
" (JRE " + System.getProperty("java.runtime.version") + ")"
|
||||
)
|
||||
@@ -128,9 +141,16 @@ internal open class GradleCompilerRunner(protected val task: Task) {
|
||||
}
|
||||
|
||||
val incrementalCompilationEnvironment = environment.incrementalCompilationEnvironment
|
||||
val modulesInfo = incrementalCompilationEnvironment?.let { buildModulesInfo(project.gradle) }
|
||||
val modulesInfo = incrementalCompilationEnvironment?.let { incrementalModuleInfoProvider }
|
||||
val workArgs = GradleKotlinCompilerWorkArguments(
|
||||
projectFiles = ProjectFilesForCompilation(project),
|
||||
projectFiles = ProjectFilesForCompilation(
|
||||
loggerProvider,
|
||||
projectDirProvider,
|
||||
buildDirProvider,
|
||||
projectNameProvider,
|
||||
projectRootDirProvider,
|
||||
sessionDirProvider
|
||||
),
|
||||
compilerFullClasspath = environment.compilerFullClasspath,
|
||||
compilerClassName = compilerClassName,
|
||||
compilerArgs = argsArray,
|
||||
@@ -138,12 +158,12 @@ internal open class GradleCompilerRunner(protected val task: Task) {
|
||||
incrementalCompilationEnvironment = incrementalCompilationEnvironment,
|
||||
incrementalModuleInfo = modulesInfo,
|
||||
outputFiles = environment.outputFiles.toList(),
|
||||
taskPath = task.path,
|
||||
taskPath = pathProvider,
|
||||
buildReportMode = environment.buildReportMode,
|
||||
kotlinScriptExtensions = environment.kotlinScriptExtensions,
|
||||
allWarningsAsErrors = compilerArgs.allWarningsAsErrors
|
||||
)
|
||||
TaskLoggers.put(task.path, task.logger)
|
||||
TaskLoggers.put(pathProvider, loggerProvider)
|
||||
runCompilerAsync(workArgs)
|
||||
}
|
||||
|
||||
@@ -221,7 +241,7 @@ internal open class GradleCompilerRunner(protected val task: Task) {
|
||||
} else {
|
||||
if (target is KotlinWithJavaTarget<*>) {
|
||||
val jar = project.tasks.getByName(target.artifactsTaskName) as Jar
|
||||
jarToClassListFile[jar.archivePathCompatible.canonicalFile] = target.defaultArtifactClassesListFile
|
||||
jarToClassListFile[jar.archivePathCompatible.canonicalFile] = target.defaultArtifactClassesListFile.get()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -261,11 +281,9 @@ internal open class GradleCompilerRunner(protected val task: Task) {
|
||||
private var clientIsAliveFlagFile: File? = null
|
||||
|
||||
@Synchronized
|
||||
internal fun getOrCreateClientFlagFile(project: Project): File {
|
||||
val log = project.logger
|
||||
internal fun getOrCreateClientFlagFile(log: Logger, projectName: String): File {
|
||||
if (clientIsAliveFlagFile == null || !clientIsAliveFlagFile!!.exists()) {
|
||||
val projectName = project.rootProject.name.normalizeForFlagFile()
|
||||
clientIsAliveFlagFile = newTmpFile(prefix = "kotlin-compiler-in-$projectName-", suffix = ".alive")
|
||||
clientIsAliveFlagFile = newTmpFile(prefix = "kotlin-compiler-in-${projectName}-", suffix = ".alive")
|
||||
log.kotlinDebug { CREATED_CLIENT_FILE_PREFIX + clientIsAliveFlagFile!!.canonicalPath }
|
||||
} else {
|
||||
log.kotlinDebug { EXISTING_CLIENT_FILE_PREFIX + clientIsAliveFlagFile!!.canonicalPath }
|
||||
@@ -274,7 +292,7 @@ internal open class GradleCompilerRunner(protected val task: Task) {
|
||||
return clientIsAliveFlagFile!!
|
||||
}
|
||||
|
||||
private fun String.normalizeForFlagFile(): String {
|
||||
internal fun String.normalizeForFlagFile(): String {
|
||||
val validChars = ('a'..'z') + ('0'..'9') + "-_"
|
||||
return filter { it in validChars }
|
||||
}
|
||||
@@ -285,14 +303,13 @@ internal open class GradleCompilerRunner(protected val task: Task) {
|
||||
|
||||
// session files are deleted at org.jetbrains.kotlin.gradle.plugin.KotlinGradleBuildServices.buildFinished
|
||||
@Synchronized
|
||||
internal fun getOrCreateSessionFlagFile(project: Project): File {
|
||||
val log = project.logger
|
||||
internal fun getOrCreateSessionFlagFile(log: Logger, sessionsDir: File, projectRootDir: File): File {
|
||||
if (sessionFlagFile == null || !sessionFlagFile!!.exists()) {
|
||||
val sessionFilesDir = sessionsDir(project).apply { mkdirs() }
|
||||
val sessionFilesDir = sessionsDir.apply { mkdirs() }
|
||||
sessionFlagFile = newTmpFile(prefix = "kotlin-compiler-", suffix = ".salive", directory = sessionFilesDir)
|
||||
log.kotlinDebug { CREATED_SESSION_FILE_PREFIX + sessionFlagFile!!.relativeToRoot(project) }
|
||||
log.kotlinDebug { CREATED_SESSION_FILE_PREFIX + sessionFlagFile!!.relativeOrCanonical(projectRootDir) }
|
||||
} else {
|
||||
log.kotlinDebug { EXISTING_SESSION_FILE_PREFIX + sessionFlagFile!!.relativeToRoot(project) }
|
||||
log.kotlinDebug { EXISTING_SESSION_FILE_PREFIX + sessionFlagFile!!.relativeOrCanonical(projectRootDir) }
|
||||
}
|
||||
|
||||
return sessionFlagFile!!
|
||||
|
||||
+7
-5
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.compilerRunner
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.config.Services
|
||||
@@ -35,11 +36,12 @@ internal class ProjectFilesForCompilation(
|
||||
val sessionFlagFile: File,
|
||||
val buildDir: File
|
||||
) : Serializable {
|
||||
constructor(project: Project) : this(
|
||||
projectRootFile = project.rootProject.projectDir,
|
||||
clientIsAliveFlagFile = GradleCompilerRunner.getOrCreateClientFlagFile(project),
|
||||
sessionFlagFile = GradleCompilerRunner.getOrCreateSessionFlagFile(project),
|
||||
buildDir = project.buildDir
|
||||
//TODO
|
||||
constructor(logger: Logger, projectDir:File, buildDir: File, prjectName: String, projectRootDir: File, sessionDir: File) : this(
|
||||
projectRootFile = projectDir,
|
||||
clientIsAliveFlagFile = GradleCompilerRunner.getOrCreateClientFlagFile(logger, prjectName),
|
||||
sessionFlagFile = GradleCompilerRunner.getOrCreateSessionFlagFile(logger, sessionDir, projectRootDir),
|
||||
buildDir = buildDir
|
||||
)
|
||||
|
||||
companion object {
|
||||
|
||||
+22
-31
@@ -5,13 +5,15 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.internal
|
||||
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.jetbrains.kotlin.cli.common.arguments.*
|
||||
import org.jetbrains.kotlin.gradle.dsl.*
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||
import org.jetbrains.kotlin.gradle.dsl.Coroutines
|
||||
import org.jetbrains.kotlin.gradle.dsl.fillDefaultValues
|
||||
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
|
||||
import org.jetbrains.kotlin.gradle.tasks.*
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import org.jetbrains.kotlin.gradle.utils.getValue
|
||||
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompileArgumentsProvider
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompilerArgumentsProvider
|
||||
import org.jetbrains.kotlin.gradle.utils.toSortedPathsArray
|
||||
import org.jetbrains.kotlin.incremental.classpathAsList
|
||||
import org.jetbrains.kotlin.incremental.destinationAsFile
|
||||
@@ -38,22 +40,20 @@ internal fun compilerArgumentsConfigurationFlags(defaultsOnly: Boolean, ignoreCl
|
||||
* but outside the tasks, so that this state & logic can be reused without referencing the task directly. */
|
||||
internal open class AbstractKotlinCompileArgumentsContributor<T : CommonCompilerArguments>(
|
||||
// Don't save this reference into a property! That would be hostile to Gradle instant execution
|
||||
taskProvider: TaskProvider<out AbstractKotlinCompile<T>>
|
||||
taskProvider: KotlinCompileArgumentsProvider<out AbstractKotlinCompile<T>>
|
||||
) : CompilerArgumentsContributor<T> {
|
||||
private val coroutines by taskProvider.map { it.coroutines }
|
||||
|
||||
protected val logger by taskProvider.map { it.logger }
|
||||
|
||||
private val isMultiplatform by taskProvider.map { it.isMultiplatform }
|
||||
|
||||
private val pluginClasspath by taskProvider.map { it.pluginClasspath }
|
||||
private val pluginOptions by taskProvider.map { it.pluginOptions }
|
||||
private val coroutines = taskProvider.coroutines
|
||||
protected val logger = taskProvider.logger
|
||||
private val isMultiplatform = taskProvider.isMultiplatform
|
||||
private val pluginClasspath = taskProvider.pluginClasspath
|
||||
private val pluginOptions = taskProvider.pluginOptions
|
||||
|
||||
override fun contributeArguments(
|
||||
args: T,
|
||||
flags: Collection<CompilerArgumentsConfigurationFlag>
|
||||
) {
|
||||
args.coroutinesState = when (coroutines) {
|
||||
args.coroutinesState = when (coroutines.get()) {
|
||||
Coroutines.ENABLE -> CommonCompilerArguments.ENABLE
|
||||
Coroutines.WARN -> CommonCompilerArguments.WARN
|
||||
Coroutines.ERROR -> CommonCompilerArguments.ERROR
|
||||
@@ -79,23 +79,14 @@ internal open class AbstractKotlinCompileArgumentsContributor<T : CommonCompiler
|
||||
|
||||
internal open class KotlinJvmCompilerArgumentsContributor(
|
||||
// Don't save this reference into a property! That would be hostile to Gradle instant execution. Only map it to the task properties.
|
||||
taskProvider: TaskProvider<out KotlinCompile>
|
||||
taskProvider: KotlinJvmCompilerArgumentsProvider
|
||||
) : AbstractKotlinCompileArgumentsContributor<K2JVMCompilerArguments>(taskProvider) {
|
||||
|
||||
private val moduleName by taskProvider.map { it.moduleName }
|
||||
|
||||
private val friendPaths by taskProvider.map { it.friendPaths }
|
||||
|
||||
private val compileClasspath by taskProvider.map { it.compileClasspath }
|
||||
|
||||
private val destinationDir by taskProvider.map { it.destinationDir }
|
||||
|
||||
private val kotlinOptions by taskProvider.map {
|
||||
listOfNotNull(
|
||||
it.parentKotlinOptionsImpl as KotlinJvmOptionsImpl?,
|
||||
it.kotlinOptions as KotlinJvmOptionsImpl
|
||||
)
|
||||
}
|
||||
private val moduleName = taskProvider.moduleName
|
||||
private val friendPaths = taskProvider.friendPaths
|
||||
private val compileClasspath = taskProvider.compileClasspath
|
||||
private val destinationDir = taskProvider.destinationDir
|
||||
private val kotlinOptions = taskProvider.kotlinOptions
|
||||
|
||||
override fun contributeArguments(
|
||||
args: K2JVMCompilerArguments,
|
||||
@@ -121,6 +112,6 @@ internal open class KotlinJvmCompilerArgumentsContributor(
|
||||
}
|
||||
args.destinationAsFile = destinationDir
|
||||
|
||||
kotlinOptions.forEach { it.updateArguments(args) }
|
||||
kotlinOptions.forEach { it?.updateArguments(args) }
|
||||
}
|
||||
}
|
||||
+10
-2
@@ -10,6 +10,7 @@ import com.android.build.gradle.api.AndroidSourceSet
|
||||
import com.android.build.gradle.api.BaseVariant
|
||||
import com.android.build.gradle.api.SourceKind
|
||||
import com.intellij.openapi.util.SystemInfo
|
||||
import com.intellij.util.lang.JavaVersion
|
||||
import org.gradle.api.GradleException
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
@@ -22,7 +23,6 @@ import org.gradle.api.tasks.*
|
||||
import org.gradle.api.tasks.compile.AbstractCompile
|
||||
import org.gradle.api.tasks.compile.JavaCompile
|
||||
import org.gradle.process.CommandLineArgumentProvider
|
||||
import org.gradle.tooling.provider.model.ToolingModelBuilder
|
||||
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
|
||||
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.CLASS_STRUCTURE_ARTIFACT_TYPE
|
||||
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompileTaskData
|
||||
import org.jetbrains.kotlin.gradle.tasks.locateTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
||||
import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import java.io.ObjectOutputStream
|
||||
@@ -474,7 +475,14 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
|
||||
val dslJavacOptions: Provider<Map<String, String>> = project.provider {
|
||||
kaptExtension.getJavacOptions().toMutableMap().also { result ->
|
||||
if (javaCompile != null && "-source" !in result && "--source" !in result && "--release" !in result) {
|
||||
val sourceOptionKey = if (SystemInfo.isJavaVersionAtLeast(12, 0, 0)) {
|
||||
val atLeast12Java =
|
||||
if (isConfigurationCacheAvailable(project.gradle)) {
|
||||
val currentJavaVersion = JavaVersion.parse(project.providers.systemProperty("java.version").forUseAtConfigurationTime().get())
|
||||
currentJavaVersion.feature >= 12
|
||||
} else {
|
||||
SystemInfo.isJavaVersionAtLeast(12, 0, 0)
|
||||
}
|
||||
val sourceOptionKey = if (atLeast12Java) {
|
||||
"--source"
|
||||
} else {
|
||||
"-source"
|
||||
|
||||
+6
-3
@@ -20,7 +20,7 @@ import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.tasks.*
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||
import org.jetbrains.kotlin.gradle.dsl.*
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl
|
||||
import org.jetbrains.kotlin.gradle.tasks.FilteringSourceRootsContainer
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
@@ -50,7 +50,7 @@ open class KaptGenerateStubsTask : KotlinCompile() {
|
||||
@get:Classpath
|
||||
@get:InputFiles
|
||||
val kaptClasspath: FileCollection
|
||||
get() = project.files(kaptClasspathConfigurations)
|
||||
get() = objects.fileCollection().from(kaptClasspathConfigurations)
|
||||
|
||||
@get:Internal
|
||||
internal lateinit var kaptClasspathConfigurations: List<Configuration>
|
||||
@@ -69,6 +69,9 @@ open class KaptGenerateStubsTask : KotlinCompile() {
|
||||
error("KaptGenerateStubsTask.useModuleDetection setter should not be called!")
|
||||
}
|
||||
|
||||
@get:Input
|
||||
val verbose = (project.hasProperty("kapt.verbose") && project.property("kapt.verbose").toString().toBoolean() == true)
|
||||
|
||||
override fun source(vararg sources: Any): SourceTask {
|
||||
return super.source(sourceRootsContainer.add(sources))
|
||||
}
|
||||
@@ -95,7 +98,7 @@ open class KaptGenerateStubsTask : KotlinCompile() {
|
||||
val pluginOptionsWithKapt = pluginOptions.withWrappedKaptOptions(withApClasspath = kaptClasspath)
|
||||
args.pluginOptions = (pluginOptionsWithKapt.arguments + args.pluginOptions!!).toTypedArray()
|
||||
|
||||
args.verbose = project.hasProperty("kapt.verbose") && project.property("kapt.verbose").toString().toBoolean() == true
|
||||
args.verbose = verbose
|
||||
args.classpathAsList = this.compileClasspath.filter { it.exists() }.toList()
|
||||
args.destinationAsFile = this.destinationDir
|
||||
}
|
||||
|
||||
+35
-5
@@ -1,6 +1,5 @@
|
||||
package org.jetbrains.kotlin.gradle.internal
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.internal.ConventionTask
|
||||
@@ -28,7 +27,7 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState {
|
||||
outputs.cacheIf(reason) { useBuildCache }
|
||||
}
|
||||
|
||||
override fun localStateDirectories(): FileCollection = project.files()
|
||||
override fun localStateDirectories(): FileCollection = objects.fileCollection()
|
||||
|
||||
@get:Internal
|
||||
@field:Transient
|
||||
@@ -37,10 +36,13 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState {
|
||||
@get:Internal
|
||||
internal lateinit var stubsDir: File
|
||||
|
||||
@get:Internal
|
||||
internal val objects = project.objects
|
||||
|
||||
@get:Classpath
|
||||
@get:InputFiles
|
||||
val kaptClasspath: FileCollection
|
||||
get() = project.files(kaptClasspathConfigurations)
|
||||
get() = objects.fileCollection().from(kaptClasspathConfigurations)
|
||||
|
||||
@get:Classpath
|
||||
@get:InputFiles
|
||||
@@ -137,8 +139,36 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState {
|
||||
|
||||
private fun isRootAllowed(file: File): Boolean =
|
||||
file.exists() &&
|
||||
!FileUtil.isAncestor(destinationDir, file, /* strict = */ false) &&
|
||||
!FileUtil.isAncestor(classesDir, file, /* strict = */ false)
|
||||
!isAncestor(destinationDir, file) &&
|
||||
!isAncestor(classesDir, file)
|
||||
|
||||
//Have to avoid using FileUtil because it is required system property reading that is not allowed for configuration cache
|
||||
private fun isAncestor(dir: File, file: File): Boolean {
|
||||
val path = file.canonicalPath
|
||||
val prefix = dir.canonicalPath
|
||||
val pathLength = path.length
|
||||
val prefixLength = prefix.length
|
||||
//TODO
|
||||
val caseSensitive = true
|
||||
return if (prefixLength == 0) {
|
||||
true
|
||||
} else if (prefixLength > pathLength) {
|
||||
false
|
||||
} else if (!path.regionMatches(0, prefix, 0, prefixLength, ignoreCase = !caseSensitive)) {
|
||||
return false
|
||||
} else if (pathLength == prefixLength) {
|
||||
return true
|
||||
} else {
|
||||
val lastPrefixChar: Char = prefix.get(prefixLength - 1)
|
||||
var slashOrSeparatorIdx = prefixLength
|
||||
if (lastPrefixChar == '/' || lastPrefixChar == File.separatorChar) {
|
||||
slashOrSeparatorIdx = prefixLength - 1
|
||||
}
|
||||
val next1 = path[slashOrSeparatorIdx]
|
||||
return !(next1 != '/' && next1 != File.separatorChar)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun FileCollection?.orEmpty(): FileCollection =
|
||||
this ?: project.files()
|
||||
|
||||
+8
-3
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger
|
||||
import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector
|
||||
import org.jetbrains.kotlin.gradle.plugin.PLUGIN_CLASSPATH_CONFIGURATION_NAME
|
||||
import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions
|
||||
import org.jetbrains.kotlin.gradle.tasks.GradleCompileTaskProvider
|
||||
import org.jetbrains.kotlin.gradle.utils.getValue
|
||||
import org.jetbrains.kotlin.gradle.utils.optionalProvider
|
||||
import org.jetbrains.kotlin.gradle.utils.toSortedPathsArray
|
||||
@@ -43,6 +44,9 @@ open class KaptWithKotlincTask : KaptTask(), CompilerArgumentAwareWithInput<K2JV
|
||||
val pluginClasspath: FileCollection
|
||||
get() = project.configurations.getByName(PLUGIN_CLASSPATH_CONFIGURATION_NAME)
|
||||
|
||||
@get:Internal
|
||||
val taskProvider = GradleCompileTaskProvider(this)
|
||||
|
||||
override fun createCompilerArgs(): K2JVMCompilerArguments = K2JVMCompilerArguments()
|
||||
|
||||
private val compileKotlinArgumentsContributor by project.provider {
|
||||
@@ -50,8 +54,9 @@ open class KaptWithKotlincTask : KaptTask(), CompilerArgumentAwareWithInput<K2JV
|
||||
}
|
||||
|
||||
override fun setupCompilerArgs(args: K2JVMCompilerArguments, defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) {
|
||||
compileKotlinArgumentsContributor.contributeArguments(args, compilerArgumentsConfigurationFlags(
|
||||
defaultsOnly,
|
||||
compileKotlinArgumentsContributor.contributeArguments(
|
||||
args, compilerArgumentsConfigurationFlags(
|
||||
defaultsOnly,
|
||||
ignoreClasspathResolutionErrors
|
||||
))
|
||||
|
||||
@@ -106,7 +111,7 @@ open class KaptWithKotlincTask : KaptTask(), CompilerArgumentAwareWithInput<K2JV
|
||||
throw GradleException("Could not find tools.jar in system classpath, which is required for kapt to work")
|
||||
}
|
||||
|
||||
val compilerRunner = GradleCompilerRunner(this)
|
||||
val compilerRunner = GradleCompilerRunner(taskProvider)
|
||||
compilerRunner.runJvmCompilerAsync(
|
||||
sourcesToCompile = emptyList(),
|
||||
commonSources = emptyList(),
|
||||
|
||||
+29
-8
@@ -11,13 +11,12 @@ import org.gradle.workers.IsolationMode
|
||||
import org.gradle.workers.WorkerExecutor
|
||||
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME
|
||||
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptIncrementalChanges
|
||||
import org.jetbrains.kotlin.gradle.plugin.CompositeSubpluginOption
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinAndroidPluginWrapper
|
||||
import org.jetbrains.kotlin.gradle.plugin.SubpluginOption
|
||||
import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions
|
||||
import org.jetbrains.kotlin.gradle.tasks.findKotlinStdlibClasspath
|
||||
import org.jetbrains.kotlin.gradle.tasks.findToolsJar
|
||||
import org.jetbrains.kotlin.gradle.utils.getValue
|
||||
import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import java.io.File
|
||||
import java.io.Serializable
|
||||
@@ -29,7 +28,7 @@ open class KaptWithoutKotlincTask @Inject constructor(private val workerExecutor
|
||||
@get:InputFiles
|
||||
@get:Classpath
|
||||
@Suppress("unused")
|
||||
val kaptJars: Collection<File> by project.provider {
|
||||
val kaptJars: Collection<File> by lazy {
|
||||
project.configurations.getByName(KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME).resolve()
|
||||
}
|
||||
|
||||
@@ -48,6 +47,18 @@ open class KaptWithoutKotlincTask @Inject constructor(private val workerExecutor
|
||||
@get:Input
|
||||
lateinit var javacOptions: Map<String, String>
|
||||
|
||||
@get:Input
|
||||
internal val kotlinAndroidPluginWrapperPluginDoesNotExist = project.plugins.none { it is KotlinAndroidPluginWrapper }
|
||||
|
||||
@get:Input
|
||||
internal val kotlinStdlibClasspath = findKotlinStdlibClasspath(project)
|
||||
|
||||
@get:Internal
|
||||
internal val projectDir = project.projectDir
|
||||
|
||||
@get:Internal
|
||||
internal val providers = project.providers
|
||||
|
||||
private fun getAnnotationProcessorOptions(): Map<String, String> {
|
||||
val options = processorOptions.subpluginOptionsByPluginId[Kapt3GradleSubplugin.KAPT_SUBPLUGIN_ID] ?: return emptyMap()
|
||||
|
||||
@@ -70,7 +81,7 @@ open class KaptWithoutKotlincTask @Inject constructor(private val workerExecutor
|
||||
}
|
||||
|
||||
val compileClasspath = classpath.files.toMutableList()
|
||||
if (project.plugins.none { it is KotlinAndroidPluginWrapper }) {
|
||||
if (kotlinAndroidPluginWrapperPluginDoesNotExist) {
|
||||
compileClasspath.addAll(0, PathUtil.getJdkClassesRootsFromCurrentJre())
|
||||
}
|
||||
|
||||
@@ -82,7 +93,7 @@ open class KaptWithoutKotlincTask @Inject constructor(private val workerExecutor
|
||||
}
|
||||
|
||||
val optionsForWorker = KaptOptionsForWorker(
|
||||
project.projectDir,
|
||||
projectDir,
|
||||
compileClasspath,
|
||||
javaSourceRoots.toList(),
|
||||
|
||||
@@ -108,25 +119,35 @@ open class KaptWithoutKotlincTask @Inject constructor(private val workerExecutor
|
||||
if (annotationProcessorFqNames.isEmpty() && kaptClasspath.isEmpty())
|
||||
return
|
||||
|
||||
val kaptClasspath = kaptJars + findKotlinStdlibClasspath(project)
|
||||
val kaptClasspath = kaptJars + kotlinStdlibClasspath
|
||||
|
||||
workerExecutor.submit(KaptExecution::class.java) { config ->
|
||||
val isolationModeStr = project.findProperty("kapt.workers.isolation") as String? ?: "none"
|
||||
//TODO for gradle < 6.5
|
||||
val isolationModeStr = getValue("kapt.workers.isolation") ?: "none"
|
||||
config.isolationMode = when (isolationModeStr.toLowerCase()) {
|
||||
"process" -> IsolationMode.PROCESS
|
||||
"none" -> IsolationMode.NONE
|
||||
else -> IsolationMode.NONE
|
||||
}
|
||||
config.params(optionsForWorker, findToolsJar()?.toURI()?.toURL()?.toString().orEmpty(), kaptClasspath)
|
||||
if (project.findProperty("kapt.workers.log.classloading") == "true") {
|
||||
if (getValue("kapt.workers.log.classloading") == "true") {
|
||||
// for tests
|
||||
config.forkOptions.jvmArgs("-verbose:class")
|
||||
}
|
||||
logger.info("Kapt worker classpath: ${config.classpath}")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun getValue(propertyName: String): String? =
|
||||
if (isGradleVersionAtLeast(6, 5)) {
|
||||
providers.systemProperty(propertyName).forUseAtConfigurationTime().orNull
|
||||
} else {
|
||||
project.findProperty(propertyName) as String?
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private class KaptExecution @Inject constructor(
|
||||
val optionsForWorker: KaptOptionsForWorker,
|
||||
val toolsJarURLSpec: String,
|
||||
|
||||
+1
-1
@@ -144,7 +144,7 @@ class KotlinModelBuilder(private val kotlinPluginVersion: String, private val an
|
||||
}
|
||||
|
||||
private fun AbstractKotlinCompile<*>.createExperimentalFeatures(): ExperimentalFeatures {
|
||||
return ExperimentalFeaturesImpl(coroutinesStr)
|
||||
return ExperimentalFeaturesImpl(coroutinesStr.get())
|
||||
}
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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 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?) {
|
||||
companion object {
|
||||
fun getInstance(project: Project) = run {
|
||||
if (isConfigurationCacheAvailable(project.gradle)) {
|
||||
project.objects.newInstance(BuildEventsListenerRegistryHolder::class.java)
|
||||
} else {
|
||||
BuildEventsListenerRegistryHolder(null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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 org.gradle.tooling.events.FinishEvent
|
||||
import org.gradle.tooling.events.OperationCompletionListener
|
||||
|
||||
//Available since Gradle 6.1
|
||||
class KotlinGradleBuildListener(
|
||||
// val gradle: Gradle,
|
||||
val services: KotlinGradleFinishBuildHandler
|
||||
) : OperationCompletionListener {
|
||||
|
||||
override fun onFinish(event: FinishEvent) {
|
||||
// services.buildFinished(gradle)
|
||||
}
|
||||
|
||||
}
|
||||
+46
-61
@@ -10,20 +10,18 @@ import org.gradle.BuildResult
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.invocation.Gradle
|
||||
import org.gradle.api.logging.Logging
|
||||
import org.jetbrains.kotlin.compilerRunner.DELETED_SESSION_FILE_PREFIX
|
||||
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.report.configureBuildReporter
|
||||
import org.jetbrains.kotlin.gradle.utils.relativeToRoot
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.sumByLong
|
||||
import java.lang.management.ManagementFactory
|
||||
import kotlin.math.max
|
||||
import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable
|
||||
|
||||
|
||||
//Support Gradle 6 and less. Move to
|
||||
internal class KotlinGradleBuildServices private constructor(
|
||||
private val gradle: Gradle
|
||||
) : BuildAdapter() {
|
||||
|
||||
companion object {
|
||||
private val CLASS_NAME = KotlinGradleBuildServices::class.java.simpleName
|
||||
const val FORCE_SYSTEM_GC_MESSAGE = "Forcing System.gc()"
|
||||
@@ -34,36 +32,69 @@ internal class KotlinGradleBuildServices private constructor(
|
||||
val ALREADY_INITIALIZED_MESSAGE = "$CLASS_NAME is already initialized"
|
||||
|
||||
@field:Volatile
|
||||
private var instance: KotlinGradleBuildServices? = null
|
||||
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(gradle: Gradle): KotlinGradleBuildServices {
|
||||
fun getInstance(project: Project, listenerRegistryHolder: BuildEventsListenerRegistryHolder): KotlinGradleBuildServices {
|
||||
val log = Logging.getLogger(KotlinGradleBuildServices::class.java)
|
||||
val kotlinGradleListenerProvider: org.gradle.api.provider.Provider<KotlinGradleBuildListener> = project.provider {
|
||||
KotlinGradleBuildListener(KotlinGradleFinishBuildHandler())
|
||||
}
|
||||
|
||||
if (instance != null) {
|
||||
log.kotlinDebug(ALREADY_INITIALIZED_MESSAGE)
|
||||
return instance!!
|
||||
}
|
||||
|
||||
val gradle = project.gradle
|
||||
val services = KotlinGradleBuildServices(gradle)
|
||||
gradle.addBuildListener(services)
|
||||
instance = services
|
||||
log.kotlinDebug(INIT_MESSAGE)
|
||||
if (isConfigurationCacheAvailable(gradle)) {
|
||||
listenerRegistryHolder.listenerRegistry!!.onTaskCompletion(kotlinGradleListenerProvider)
|
||||
} else {
|
||||
gradle.addBuildListener(services)
|
||||
instance = services
|
||||
log.kotlinDebug(INIT_MESSAGE)
|
||||
}
|
||||
|
||||
services.buildStarted()
|
||||
return services
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private val log = Logging.getLogger(this.javaClass)
|
||||
private var startMemory: Long? = null
|
||||
private val shouldReportMemoryUsage = System.getProperty(SHOULD_REPORT_MEMORY_USAGE_PROPERTY) != null
|
||||
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() {
|
||||
startMemory = getUsedMemoryKb()
|
||||
buildHandler = KotlinGradleFinishBuildHandler()
|
||||
buildHandler!!.buildStart()
|
||||
|
||||
TaskLoggers.clear()
|
||||
TaskExecutionResults.clear()
|
||||
@@ -72,57 +103,11 @@ internal class KotlinGradleBuildServices private constructor(
|
||||
}
|
||||
|
||||
override fun buildFinished(result: BuildResult) {
|
||||
TaskLoggers.clear()
|
||||
TaskExecutionResults.clear()
|
||||
|
||||
val gradle = result.gradle!!
|
||||
GradleCompilerRunner.clearBuildModulesInfo()
|
||||
|
||||
val rootProject = gradle.rootProject
|
||||
val sessionsDir = GradleCompilerRunner.sessionsDir(rootProject)
|
||||
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)}")
|
||||
}
|
||||
for (file in sessionFiles) {
|
||||
file.delete()
|
||||
log.kotlinDebug { DELETED_SESSION_FILE_PREFIX + file.relativeToRoot(rootProject) }
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldReportMemoryUsage) {
|
||||
val startMem = startMemory!!
|
||||
val endMem = getUsedMemoryKb()!!
|
||||
|
||||
// the value reported here is not necessarily a leak, since it is calculated before collecting the plugin classes
|
||||
// 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)")
|
||||
}
|
||||
|
||||
gradle.removeListener(this)
|
||||
buildHandler!!.buildFinished(result.gradle!!)
|
||||
instance = null
|
||||
log.kotlinDebug(DISPOSE_MESSAGE)
|
||||
}
|
||||
|
||||
private fun getUsedMemoryKb(): Long? {
|
||||
if (!shouldReportMemoryUsage) return null
|
||||
|
||||
log.lifecycle(FORCE_SYSTEM_GC_MESSAGE)
|
||||
val gcCountBefore = getGcCount()
|
||||
System.gc()
|
||||
while (getGcCount() == gcCountBefore) {
|
||||
}
|
||||
|
||||
val rt = Runtime.getRuntime()
|
||||
return (rt.totalMemory() - rt.freeMemory()) / 1024
|
||||
}
|
||||
|
||||
private fun getGcCount(): Long =
|
||||
ManagementFactory.getGarbageCollectorMXBeans().sumByLong { max(0, it.collectionCount) }
|
||||
|
||||
private val multipleProjectsHolder = KotlinPluginInMultipleProjectsHolder(
|
||||
trackPluginVersionsSeparately = true
|
||||
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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 org.gradle.api.invocation.Gradle
|
||||
import org.gradle.api.logging.Logging
|
||||
import org.jetbrains.kotlin.compilerRunner.DELETED_SESSION_FILE_PREFIX
|
||||
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.utils.addToStdlib.sumByLong
|
||||
import java.lang.management.ManagementFactory
|
||||
import kotlin.math.max
|
||||
|
||||
// move to KotlinGradleBuildListener when min supported version is 6.1
|
||||
class KotlinGradleFinishBuildHandler {
|
||||
|
||||
private val log = Logging.getLogger(this.javaClass)
|
||||
private var startMemory: Long? = null
|
||||
private val shouldReportMemoryUsage = System.getProperty(KotlinGradleBuildServices.SHOULD_REPORT_MEMORY_USAGE_PROPERTY) != null
|
||||
|
||||
fun buildStart() {
|
||||
startMemory = getUsedMemoryKb()
|
||||
}
|
||||
|
||||
fun buildFinished(gradle: Gradle) {
|
||||
TaskLoggers.clear()
|
||||
TaskExecutionResults.clear()
|
||||
|
||||
GradleCompilerRunner.clearBuildModulesInfo()
|
||||
|
||||
val rootProject = gradle.rootProject
|
||||
val sessionsDir = GradleCompilerRunner.sessionsDir(rootProject)
|
||||
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)}")
|
||||
}
|
||||
for (file in sessionFiles) {
|
||||
file.delete()
|
||||
log.kotlinDebug { DELETED_SESSION_FILE_PREFIX + file.relativeToRoot(rootProject) }
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldReportMemoryUsage) {
|
||||
val startMem = startMemory!!
|
||||
val endMem = getUsedMemoryKb()!!
|
||||
|
||||
// the value reported here is not necessarily a leak, since it is calculated before collecting the plugin classes
|
||||
// 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)")
|
||||
}
|
||||
|
||||
gradle.removeListener(this)
|
||||
}
|
||||
|
||||
internal fun getUsedMemoryKb(): Long? {
|
||||
if (!shouldReportMemoryUsage) return null
|
||||
|
||||
log.lifecycle(KotlinGradleBuildServices.FORCE_SYSTEM_GC_MESSAGE)
|
||||
val gcCountBefore = getGcCount()
|
||||
System.gc()
|
||||
while (getGcCount() == gcCountBefore) {
|
||||
}
|
||||
|
||||
val rt = Runtime.getRuntime()
|
||||
return (rt.totalMemory() - rt.freeMemory()) / 1024
|
||||
}
|
||||
|
||||
private fun getGcCount(): Long =
|
||||
ManagementFactory.getGarbageCollectorMXBeans().sumByLong { max(0, it.collectionCount) }
|
||||
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
|
||||
+1
-1
@@ -103,7 +103,7 @@ internal abstract class KotlinSourceSetProcessor<T : AbstractKotlinCompile<*>>(
|
||||
|
||||
private fun prepareKotlinCompileTask(): TaskProvider<out T> =
|
||||
registerKotlinCompileTask(register = ::doRegisterTask).also { task ->
|
||||
kotlinCompilation.output.addClassesDir { project.files(task.map { it.destinationDir }) }
|
||||
kotlinCompilation.output.addClassesDir { project.files(task.map { it.destinationDir }).builtBy(task) }
|
||||
}
|
||||
|
||||
protected fun registerKotlinCompileTask(
|
||||
|
||||
+6
-2
@@ -24,6 +24,7 @@ import org.gradle.api.internal.FeaturePreviews
|
||||
import org.gradle.api.internal.file.FileResolver
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.api.logging.Logging
|
||||
import org.gradle.build.event.BuildEventsListenerRegistry
|
||||
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
|
||||
import org.jetbrains.kotlin.gradle.dsl.*
|
||||
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
|
||||
@@ -49,6 +50,7 @@ import kotlin.reflect.KClass
|
||||
abstract class KotlinBasePluginWrapper(
|
||||
protected val fileResolver: FileResolver
|
||||
) : Plugin<Project> {
|
||||
|
||||
private val log = Logging.getLogger(this.javaClass)
|
||||
val kotlinPluginVersion = loadKotlinVersionFromResource(log)
|
||||
|
||||
@@ -58,7 +60,8 @@ abstract class KotlinBasePluginWrapper(
|
||||
DefaultKotlinSourceSetFactory(project, fileResolver)
|
||||
|
||||
override fun apply(project: Project) {
|
||||
val statisticsReporter = KotlinBuildStatsService.getOrCreateInstance(project.gradle)
|
||||
val listenerRegistryHolder = BuildEventsListenerRegistryHolder.getInstance(project)
|
||||
val statisticsReporter = KotlinBuildStatsService.getOrCreateInstance(project, listenerRegistryHolder)
|
||||
statisticsReporter?.report(StringMetrics.KOTLIN_COMPILER_VERSION, kotlinPluginVersion)
|
||||
|
||||
checkGradleCompatibility()
|
||||
@@ -80,7 +83,8 @@ abstract class KotlinBasePluginWrapper(
|
||||
|
||||
// TODO: consider only set if if daemon or parallel compilation are enabled, though this way it should be safe too
|
||||
System.setProperty(org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY, "true")
|
||||
val kotlinGradleBuildServices = KotlinGradleBuildServices.getInstance(project.gradle)
|
||||
|
||||
val kotlinGradleBuildServices = KotlinGradleBuildServices.getInstance(project, listenerRegistryHolder)
|
||||
|
||||
kotlinGradleBuildServices.detectKotlinPluginLoadedInMultipleProjects(project, kotlinPluginVersion)
|
||||
|
||||
|
||||
+3
-3
@@ -27,16 +27,16 @@ import java.io.File
|
||||
|
||||
internal fun AbstractCompile.appendClasspathDynamically(file: File) {
|
||||
var added = false
|
||||
|
||||
val objects = project.objects
|
||||
doFirst {
|
||||
if (file !in classpath) {
|
||||
classpath += project.files(file)
|
||||
classpath += objects.fileCollection().from(file)
|
||||
added = true
|
||||
}
|
||||
}
|
||||
doLast {
|
||||
if (added) {
|
||||
classpath -= project.files(file)
|
||||
classpath -= objects.fileCollection().from(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+112
-44
@@ -24,9 +24,14 @@ import java.util.zip.ZipOutputStream
|
||||
import javax.xml.parsers.DocumentBuilderFactory
|
||||
|
||||
internal sealed class MetadataDependencyResolution(
|
||||
@field:Transient // can't be used with Gradle Instant Execution, but fortunately not needed when deserialized
|
||||
val dependency: ResolvedComponentResult,
|
||||
@field:Transient
|
||||
val projectDependency: Project?
|
||||
) {
|
||||
/** Evaluate and store the value, as the [dependency] will be lost during Gradle instant execution */
|
||||
// val originalArtifactFiles: List<File> = dependency.dependents.flatMap { it.allModuleArtifacts } .map { it.file }
|
||||
|
||||
override fun toString(): String {
|
||||
val verb = when (this) {
|
||||
is KeepOriginalDependency -> "keep"
|
||||
@@ -59,7 +64,10 @@ internal sealed class MetadataDependencyResolution(
|
||||
* If [doProcessFiles] is true, these temporary files are actually re-created during the call,
|
||||
* otherwise only their paths are returned, while the files might be missing.
|
||||
*/
|
||||
abstract fun getMetadataFilesBySourceSet(baseDir: File, doProcessFiles: Boolean): Map<String, FileCollection>
|
||||
fun getMetadataFilesBySourceSet(baseDir: File, doProcessFiles: Boolean): Map<String, FileCollection> =
|
||||
getExtractableMetadataFiles(baseDir).getMetadataFilesPerSourceSet(doProcessFiles)
|
||||
|
||||
abstract fun getExtractableMetadataFiles(baseDir: File): ExtractableMetadataFiles
|
||||
|
||||
override fun toString(): String =
|
||||
super.toString() + ", sourceSets = " + allVisibleSourceSetNames.joinToString(", ", "[", "]") {
|
||||
@@ -183,6 +191,7 @@ internal class GranularMetadataTransformation(
|
||||
|
||||
allModuleDependencies.forEach { resolvedDependency ->
|
||||
if (resolvedDependency.selected !in visitedDependencies) {
|
||||
// val files = resolvedDependency.moduleArtifacts.map { it.file }
|
||||
result.add(
|
||||
MetadataDependencyResolution.ExcludeAsUnrequested(
|
||||
resolvedDependency.selected,
|
||||
@@ -273,6 +282,20 @@ internal class GranularMetadataTransformation(
|
||||
module, resolvedToProject, projectStructureMetadata, allVisibleSourceSets, visibleSourceSetsExcludingDependsOn,
|
||||
transitiveDependenciesToVisit, mppDependencyMetadataExtractor
|
||||
)
|
||||
/*
|
||||
return object : MetadataDependencyResolution.ChooseVisibleSourceSets(
|
||||
module,
|
||||
projectDependency,
|
||||
projectStructureMetadata,
|
||||
allVisibleSourceSets,
|
||||
visibleSourceSetsExcludingDependsOn,
|
||||
transitiveDependenciesToVisit
|
||||
) {
|
||||
override fun getExtractableMetadataFiles(baseDir: File): ExtractableMetadataFiles =
|
||||
mppDependencyMetadataExtractor.getExtractableMetadataFiles(visibleSourceSetsExcludingDependsOn, baseDir)
|
||||
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
private class ChooseVisibleSourceSetsImpl(
|
||||
@@ -291,18 +314,24 @@ internal class GranularMetadataTransformation(
|
||||
visibleSourceSetNamesExcludingDependsOn,
|
||||
visibleTransitiveDependencies
|
||||
) {
|
||||
override fun getMetadataFilesBySourceSet(baseDir: File, doProcessFiles: Boolean): Map<String, FileCollection> =
|
||||
metadataExtractor.getVisibleSourceSetsMetadata(visibleSourceSetNamesExcludingDependsOn, baseDir, doProcessFiles)
|
||||
override fun getExtractableMetadataFiles(baseDir: File): ExtractableMetadataFiles =
|
||||
object : ExtractableMetadataFiles() {
|
||||
override fun getMetadataFilesPerSourceSet(doProcessFiles: Boolean) : Map<String, FileCollection>
|
||||
= metadataExtractor.getExtractableMetadataFiles(visibleSourceSetNamesExcludingDependsOn, baseDir, doProcessFiles)
|
||||
.getMetadataFilesPerSourceSet(doProcessFiles)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private abstract class MppDependencyMetadataExtractor(val project: Project, val dependency: ResolvedComponentResult) {
|
||||
abstract fun getProjectStructureMetadata(): KotlinProjectStructureMetadata?
|
||||
abstract fun getVisibleSourceSetsMetadata(
|
||||
|
||||
abstract fun getExtractableMetadataFiles(
|
||||
visibleSourceSetNames: Set<String>,
|
||||
baseDir: File,
|
||||
doProcessFiles: Boolean
|
||||
): Map<String, FileCollection>
|
||||
): ExtractableMetadataFiles
|
||||
}
|
||||
|
||||
private class ProjectMppDependencyMetadataExtractor(
|
||||
@@ -313,14 +342,19 @@ private class ProjectMppDependencyMetadataExtractor(
|
||||
override fun getProjectStructureMetadata(): KotlinProjectStructureMetadata? =
|
||||
buildKotlinProjectStructureMetadata(dependencyProject)
|
||||
|
||||
override fun getVisibleSourceSetsMetadata(
|
||||
override fun getExtractableMetadataFiles(
|
||||
visibleSourceSetNames: Set<String>,
|
||||
baseDir: File,
|
||||
doProcessFiles: Boolean
|
||||
): Map<String, FileCollection> =
|
||||
dependencyProject.multiplatformExtension.targets.getByName(KotlinMultiplatformPlugin.METADATA_TARGET_NAME).compilations
|
||||
): ExtractableMetadataFiles {
|
||||
val result = dependencyProject.multiplatformExtension.targets.getByName(KotlinMultiplatformPlugin.METADATA_TARGET_NAME).compilations
|
||||
.filter { it.name in visibleSourceSetNames }
|
||||
.associate { it.defaultSourceSet.name to it.output.classesDirs }
|
||||
|
||||
return object : ExtractableMetadataFiles() {
|
||||
override fun getMetadataFilesPerSourceSet(doProcessFiles: Boolean): Map<String, FileCollection> = result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class JarArtifactMppDependencyMetadataExtractor(
|
||||
@@ -344,72 +378,106 @@ private class JarArtifactMppDependencyMetadataExtractor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun getVisibleSourceSetsMetadata(
|
||||
override fun getExtractableMetadataFiles(
|
||||
visibleSourceSetNames: Set<String>,
|
||||
baseDir: File,
|
||||
doProcessFiles: Boolean
|
||||
): Map<String, FileCollection> {
|
||||
): ExtractableMetadataFiles {
|
||||
// val artifactFile = artifact.file
|
||||
val primaryArtifact = primaryArtifact
|
||||
val moduleId = ModuleIds.fromComponent(project, dependency)
|
||||
|
||||
return extractSourceSetMetadataFromArtifacts(
|
||||
// val jarArtifact = artifact
|
||||
// ?: return object : ExtractableMetadataFiles() {
|
||||
// override fun getMetadataFilesPerSourceSet(doProcessFiles: Boolean): Map<String, FileCollection> = emptyMap()
|
||||
// }
|
||||
|
||||
return JarExtractableMetadataFiles(
|
||||
moduleId,
|
||||
project,
|
||||
primaryArtifact,
|
||||
// artifactJar,
|
||||
// visibleSourceSetNames,
|
||||
baseDir,
|
||||
doProcessFiles,
|
||||
visibleSourceSetNames.associate { it to (metadataArtifactBySourceSet[it] ?: primaryArtifact) }
|
||||
)
|
||||
}
|
||||
|
||||
private fun extractSourceSetMetadataFromArtifacts(
|
||||
module: ModuleDependencyIdentifier,
|
||||
baseDir: File,
|
||||
private class JarExtractableMetadataFiles(
|
||||
private val module: ModuleDependencyIdentifier,
|
||||
private val project: Project,
|
||||
private val primaryArtifact: File,
|
||||
private val baseDir: File,
|
||||
doProcessFiles: Boolean,
|
||||
artifactBySourceSet: Map<String, File>
|
||||
): Map<String, FileCollection> {
|
||||
val moduleString = "${module.groupId}-${module.moduleId}"
|
||||
val transformedModuleRoot = run { baseDir.resolve(moduleString).also { it.mkdirs() } }
|
||||
private val artifactBySourceSet: Map<String, File>
|
||||
) : ExtractableMetadataFiles() {
|
||||
|
||||
val resultFiles = mutableMapOf<String, FileCollection>()
|
||||
//TODO its part of extractor. Move it
|
||||
fun getProjectStructureMetadata(): KotlinProjectStructureMetadata? {
|
||||
return ZipFile(primaryArtifact).use { zip ->
|
||||
val metadata = zip.getEntry("META-INF/$MULTIPLATFORM_PROJECT_METADATA_FILE_NAME")
|
||||
?: return null
|
||||
|
||||
val projectStructureMetadata = checkNotNull(getProjectStructureMetadata()) {
|
||||
"can't extract metadata from a module without project structure metadata"
|
||||
val metadataXmlDocument = zip.getInputStream(metadata).use { inputStream ->
|
||||
DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(inputStream)
|
||||
}
|
||||
|
||||
parseKotlinSourceSetMetadataFromXml(metadataXmlDocument)
|
||||
}
|
||||
}
|
||||
|
||||
artifactBySourceSet.forEach { (sourceSetName, artifact) ->
|
||||
ZipFile(artifact).use { zip ->
|
||||
val entries = zip.entries().asSequence().filter { it.name.startsWith("$sourceSetName/") }.toList()
|
||||
override fun getMetadataFilesPerSourceSet(doProcessFiles: Boolean): Map<String, FileCollection> {
|
||||
val moduleString = "${module.groupId}-${module.moduleId}"
|
||||
val transformedModuleRoot = run { baseDir.resolve(moduleString).also { it.mkdirs() } }
|
||||
|
||||
// TODO: once IJ supports non-JAR metadata dependencies, extract to a directory, not a JAR
|
||||
// Also, if both IJ and the CLI compiler can read metadata from a path inside a JAR, then no operations will be needed
|
||||
val resultFiles = mutableMapOf<String, FileCollection>()
|
||||
val projectStructureMetadata = checkNotNull(getProjectStructureMetadata()) {
|
||||
"can't extract metadata from a module without project structure metadata"
|
||||
}
|
||||
// val artifactJar :File= artifactBySourceSet.values().first()
|
||||
artifactBySourceSet.forEach { (sourceSetName, artifact) ->
|
||||
ZipFile(artifact).use { zip ->
|
||||
val entries = zip.entries().asSequence().filter { it.name.startsWith("$sourceSetName/") }.toList()
|
||||
|
||||
if (entries.any()) {
|
||||
val extension = projectStructureMetadata.sourceSetBinaryLayout[sourceSetName]?.archiveExtension
|
||||
?: SourceSetMetadataLayout.METADATA.archiveExtension
|
||||
// TODO: once IJ supports non-JAR metadata dependencies, extract to a directory, not a JAR
|
||||
// Also, if both IJ and the CLI compiler can read metadata from a path inside a JAR, then no operations will be needed
|
||||
|
||||
val extractToJarFile = transformedModuleRoot.resolve("$moduleString-$sourceSetName.$extension")
|
||||
resultFiles[sourceSetName] = project.files(extractToJarFile)
|
||||
if (entries.any()) {
|
||||
val extension = projectStructureMetadata.sourceSetBinaryLayout[sourceSetName]?.archiveExtension
|
||||
?: SourceSetMetadataLayout.METADATA.archiveExtension
|
||||
|
||||
if (doProcessFiles) {
|
||||
ZipOutputStream(extractToJarFile.outputStream()).use { resultZipOutput ->
|
||||
for (entry in entries) {
|
||||
if (entry.isDirectory)
|
||||
continue
|
||||
val extractToJarFile = transformedModuleRoot.resolve("$moduleString-$sourceSetName.$extension")
|
||||
resultFiles[sourceSetName] = project.files(extractToJarFile)
|
||||
|
||||
// Drop the source set name from the entry path
|
||||
val resultEntry = ZipEntry(entry.name.substringAfter("/"))
|
||||
if (doProcessFiles) {
|
||||
ZipOutputStream(extractToJarFile.outputStream()).use { resultZipOutput ->
|
||||
for (entry in entries) {
|
||||
if (entry.isDirectory)
|
||||
continue
|
||||
|
||||
zip.getInputStream(entry).use { inputStream ->
|
||||
resultZipOutput.putNextEntry(resultEntry)
|
||||
inputStream.copyTo(resultZipOutput)
|
||||
resultZipOutput.closeEntry()
|
||||
// Drop the source set name from the entry path
|
||||
val resultEntry = ZipEntry(entry.name.substringAfter("/"))
|
||||
|
||||
zip.getInputStream(entry).use { inputStream ->
|
||||
resultZipOutput.putNextEntry(resultEntry)
|
||||
inputStream.copyTo(resultZipOutput)
|
||||
resultZipOutput.closeEntry()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resultFiles
|
||||
return resultFiles
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This class is needed to encapsulate how we extract the files and point to them in a way that doesn't capture the Gradle project state
|
||||
internal abstract class ExtractableMetadataFiles {
|
||||
abstract fun getMetadataFilesPerSourceSet(doProcessFiles: Boolean): Map<String, FileCollection>
|
||||
}
|
||||
|
||||
|
||||
+47
-17
@@ -15,22 +15,28 @@ import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.getSourceSetHierarchy
|
||||
import org.jetbrains.kotlin.gradle.targets.metadata.ALL_COMPILE_METADATA_CONFIGURATION_NAME
|
||||
import org.jetbrains.kotlin.gradle.targets.metadata.KotlinMetadataTargetConfigurator
|
||||
import org.jetbrains.kotlin.gradle.utils.getValue
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
open class TransformKotlinGranularMetadata
|
||||
@Inject constructor(
|
||||
@get:Internal
|
||||
@field:Transient
|
||||
val kotlinSourceSet: KotlinSourceSet
|
||||
) : DefaultTask() {
|
||||
|
||||
@get:OutputDirectory
|
||||
val outputsDir: File = project.buildDir.resolve("kotlinSourceSetMetadata/${kotlinSourceSet.name}")
|
||||
val outputsDir: File by project.provider {
|
||||
project.buildDir.resolve("kotlinSourceSetMetadata/${kotlinSourceSet.name}")
|
||||
}
|
||||
|
||||
@Suppress("unused") // Gradle input
|
||||
@get:InputFiles
|
||||
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||
internal val allSourceSetsMetadataConfiguration = project.configurations.getByName(ALL_COMPILE_METADATA_CONFIGURATION_NAME)
|
||||
internal val allSourceSetsMetadataConfiguration: FileCollection by lazy {
|
||||
project.files(project.configurations.getByName(ALL_COMPILE_METADATA_CONFIGURATION_NAME))
|
||||
}
|
||||
|
||||
private val participatingSourceSets: Set<KotlinSourceSet>
|
||||
get() = transformation.kotlinSourceSet.getSourceSetHierarchy().toMutableSet().apply {
|
||||
@@ -40,15 +46,14 @@ open class TransformKotlinGranularMetadata
|
||||
|
||||
@Suppress("unused") // Gradle input
|
||||
@get:Input
|
||||
internal val inputSourceSetsAndCompilations: Map<String, Iterable<String>>
|
||||
get() {
|
||||
val sourceSets = participatingSourceSets
|
||||
return CompilationSourceSetUtil.compilationsBySourceSets(project)
|
||||
.filterKeys { it in sourceSets }
|
||||
.entries.associate { (sourceSet, compilations) ->
|
||||
sourceSet.name to compilations.map { it.name }.sorted()
|
||||
}
|
||||
internal val inputSourceSetsAndCompilations: Map<String, Iterable<String>> by project.provider {
|
||||
val sourceSets = participatingSourceSets
|
||||
CompilationSourceSetUtil.compilationsBySourceSets(project)
|
||||
.filterKeys { it in sourceSets }
|
||||
.entries.associate { (sourceSet, compilations) ->
|
||||
sourceSet.name to compilations.map { it.name }.sorted()
|
||||
}
|
||||
}
|
||||
|
||||
private val participatingCompilations: Iterable<KotlinCompilation<*>>
|
||||
get() {
|
||||
@@ -58,13 +63,15 @@ open class TransformKotlinGranularMetadata
|
||||
|
||||
@Suppress("unused") // Gradle input
|
||||
@get:Input
|
||||
internal val inputCompilationDependencies: Map<String, Set<List<String?>>>
|
||||
get() = participatingCompilations.associate {
|
||||
internal val inputCompilationDependencies: Map<String, Set<List<String?>>> by project.provider {
|
||||
participatingCompilations.associate {
|
||||
it.name to project.configurations.getByName(it.compileDependencyConfigurationName)
|
||||
.allDependencies.map { listOf(it.group, it.name, it.version) }.toSet()
|
||||
}
|
||||
}
|
||||
|
||||
@get:Internal
|
||||
@delegate:Transient
|
||||
internal val transformation: GranularMetadataTransformation by lazy {
|
||||
GranularMetadataTransformation(
|
||||
project,
|
||||
@@ -82,14 +89,39 @@ open class TransformKotlinGranularMetadata
|
||||
}
|
||||
|
||||
@get:Internal
|
||||
internal val metadataDependencyResolutions: Iterable<MetadataDependencyResolution>
|
||||
get() = transformation.metadataDependencyResolutions
|
||||
@delegate:Transient // exclude from Gradle instant execution state
|
||||
internal val metadataDependencyResolutions: Iterable<MetadataDependencyResolution> by project.provider {
|
||||
transformation.metadataDependencyResolutions
|
||||
}
|
||||
|
||||
//TODO avoid using it
|
||||
@get:Internal
|
||||
internal val filesByResolution: Map<out MetadataDependencyResolution, FileCollection>
|
||||
get() = metadataDependencyResolutions.filterIsInstance<MetadataDependencyResolution.ChooseVisibleSourceSets>()
|
||||
.associate { it to project.files(it.getMetadataFilesBySourceSet(outputsDir, doProcessFiles = false).values) }
|
||||
|
||||
// @get:Internal
|
||||
// internal val filesByOriginalFiles: Map<out Iterable<File>, FileCollection> by project.provider {
|
||||
// metadataDependencyResolutions.associate {
|
||||
// it.originalArtifactFiles to project.files(
|
||||
// when (it) {
|
||||
// is MetadataDependencyResolution.ChooseVisibleSourceSets ->
|
||||
// it.getMetadataFilesBySourceSet(outputsDir, doProcessFiles = false).values
|
||||
// is MetadataDependencyResolution.ExcludeAsUnrequested ->
|
||||
// emptyList()
|
||||
// is MetadataDependencyResolution.KeepOriginalDependency ->
|
||||
// it.originalArtifactFiles
|
||||
// }
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
|
||||
private val extractableFiles by project.provider {
|
||||
transformation.metadataDependencyResolutions
|
||||
.filterIsInstance<MetadataDependencyResolution.ChooseVisibleSourceSets>()
|
||||
.map { it.getExtractableMetadataFiles(outputsDir) }
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun transformMetadata() {
|
||||
if (outputsDir.isDirectory) {
|
||||
@@ -97,8 +129,6 @@ open class TransformKotlinGranularMetadata
|
||||
}
|
||||
outputsDir.mkdirs()
|
||||
|
||||
metadataDependencyResolutions
|
||||
.filterIsInstance<MetadataDependencyResolution.ChooseVisibleSourceSets>()
|
||||
.forEach { it.getMetadataFilesBySourceSet(outputsDir, doProcessFiles = true) }
|
||||
extractableFiles.forEach { it.getMetadataFilesPerSourceSet(doProcessFiles = true) }
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -69,6 +69,7 @@ internal class DefaultLanguageSettingsBuilder : LanguageSettingsBuilder {
|
||||
}
|
||||
|
||||
/* A Kotlin task that is responsible for code analysis of the owner of this language settings builder. */
|
||||
@Transient // not needed during Gradle Instant Execution
|
||||
var compilerPluginOptionsTask: Lazy<AbstractCompile?> = lazyOf(null)
|
||||
|
||||
val compilerPluginArguments: List<String>?
|
||||
@@ -76,7 +77,7 @@ internal class DefaultLanguageSettingsBuilder : LanguageSettingsBuilder {
|
||||
val pluginOptionsTask = compilerPluginOptionsTask.value ?: return null
|
||||
return when (pluginOptionsTask) {
|
||||
is AbstractKotlinCompile<*> -> pluginOptionsTask.pluginOptions
|
||||
is AbstractKotlinNativeCompile<*> -> pluginOptionsTask.compilerPluginOptions
|
||||
is AbstractKotlinNativeCompile<*, *> -> pluginOptionsTask.compilerPluginOptions
|
||||
else -> error("Unexpected task: $pluginOptionsTask")
|
||||
}.arguments
|
||||
}
|
||||
@@ -86,7 +87,7 @@ internal class DefaultLanguageSettingsBuilder : LanguageSettingsBuilder {
|
||||
val pluginClasspathTask = compilerPluginOptionsTask.value ?: return null
|
||||
return when (pluginClasspathTask) {
|
||||
is AbstractKotlinCompile<*> -> pluginClasspathTask.pluginClasspath
|
||||
is AbstractKotlinNativeCompile<*> -> pluginClasspathTask.compilerPluginClasspath ?: pluginClasspathTask.project.files()
|
||||
is AbstractKotlinNativeCompile<*, *> -> pluginClasspathTask.compilerPluginClasspath ?: pluginClasspathTask.project.files()
|
||||
else -> error("Unexpected task: $pluginClasspathTask")
|
||||
}
|
||||
}
|
||||
|
||||
+215
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.statistics
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.DependencySet
|
||||
import org.gradle.api.invocation.Gradle
|
||||
import org.gradle.api.logging.Logging
|
||||
import org.jetbrains.kotlin.gradle.utils.API
|
||||
import org.jetbrains.kotlin.gradle.utils.COMPILE
|
||||
import org.jetbrains.kotlin.gradle.utils.IMPLEMENTATION
|
||||
import org.jetbrains.kotlin.gradle.utils.RUNTIME
|
||||
import org.jetbrains.kotlin.statistics.BuildSessionLogger
|
||||
import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics
|
||||
import org.jetbrains.kotlin.statistics.metrics.NumericalMetrics
|
||||
import org.jetbrains.kotlin.statistics.metrics.StringMetrics
|
||||
import java.io.File
|
||||
import java.lang.management.ManagementFactory
|
||||
import javax.management.MBeanServer
|
||||
import javax.management.ObjectName
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
class KotlinBuildStatHandler {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
internal fun getLogger() = Logging.getLogger(KotlinBuildStatHandler::class.java)
|
||||
|
||||
internal fun <T> runSafe(methodName: String, action: () -> T?): T? {
|
||||
return try {
|
||||
getLogger().debug("Executing [$methodName]")
|
||||
action.invoke()
|
||||
} catch (e: Throwable) {
|
||||
logException("Could not execute [$methodName]", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
internal fun logException(description: String, e: Throwable) {
|
||||
getLogger().info(description)
|
||||
getLogger().debug(e.message, e)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun buildFinished(
|
||||
gradle: Gradle?,
|
||||
beanName: ObjectName,
|
||||
sessionLogger: BuildSessionLogger,
|
||||
action: String?,
|
||||
failure: Throwable?
|
||||
) {
|
||||
runSafe("${KotlinBuildStatHandler::class.java}.buildFinished") {
|
||||
try {
|
||||
try {
|
||||
if (gradle != null) reportGlobalMetrics(gradle, sessionLogger)
|
||||
} finally {
|
||||
sessionLogger.finishBuildSession(action, failure)
|
||||
}
|
||||
} finally {
|
||||
val mbs: MBeanServer = ManagementFactory.getPlatformMBeanServer()
|
||||
if (mbs.isRegistered(beanName)) {
|
||||
mbs.unregisterMBean(beanName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun reportGlobalMetrics(gradle: Gradle, sessionLogger: BuildSessionLogger) {
|
||||
System.getProperty("os.name")?.also {
|
||||
sessionLogger.report(StringMetrics.OS_TYPE, System.getProperty("os.name"))
|
||||
}
|
||||
sessionLogger.report(NumericalMetrics.CPU_NUMBER_OF_CORES, Runtime.getRuntime().availableProcessors().toLong())
|
||||
sessionLogger.report(StringMetrics.GRADLE_VERSION, gradle.gradleVersion)
|
||||
sessionLogger.report(BooleanMetrics.EXECUTED_FROM_IDEA, System.getProperty("idea.active") != null)
|
||||
sessionLogger.report(NumericalMetrics.GRADLE_DAEMON_HEAP_SIZE, Runtime.getRuntime().maxMemory())
|
||||
sessionLogger.report(
|
||||
BooleanMetrics.KOTLIN_OFFICIAL_CODESTYLE,
|
||||
gradle.rootProject.properties["kotlin.code.style"] == "official"
|
||||
) // constants are saved in IDEA plugin and could not be accessed directly
|
||||
|
||||
gradle.taskGraph.whenReady() { taskExecutionGraph ->
|
||||
val executedTaskNames = taskExecutionGraph.allTasks.map { it.name }.distinct()
|
||||
report(sessionLogger, BooleanMetrics.COMPILATION_STARTED, executedTaskNames.contains("compileKotlin"), null)
|
||||
report(sessionLogger, BooleanMetrics.TESTS_EXECUTED, executedTaskNames.contains("compileTestKotlin"), null)
|
||||
report(sessionLogger, BooleanMetrics.MAVEN_PUBLISH_EXECUTED, executedTaskNames.contains("install"), null)
|
||||
}
|
||||
|
||||
fun buildSrcExists(project: Project) = File(project.projectDir, "buildSrc").exists()
|
||||
if (buildSrcExists(gradle.rootProject)) {
|
||||
sessionLogger.report(BooleanMetrics.BUILD_SRC_EXISTS, true)
|
||||
}
|
||||
val statisticOverhead = measureTimeMillis {
|
||||
gradle.allprojects { project ->
|
||||
for (configuration in project.configurations) {
|
||||
val configurationName = configuration.name
|
||||
val dependencies = configuration.dependencies
|
||||
|
||||
when (configurationName) {
|
||||
"kapt" -> {
|
||||
sessionLogger.report(BooleanMetrics.ENABLED_KAPT, true)
|
||||
dependencies?.forEach { dependency ->
|
||||
when (dependency.group) {
|
||||
"com.google.dagger" -> sessionLogger.report(BooleanMetrics.ENABLED_DAGGER, true)
|
||||
"com.android.databinding" -> sessionLogger.report(BooleanMetrics.ENABLED_DATABINDING, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
API -> {
|
||||
sessionLogger.report(NumericalMetrics.CONFIGURATION_API_COUNT, 1)
|
||||
reportLibrariesVersions(sessionLogger, dependencies)
|
||||
}
|
||||
IMPLEMENTATION -> {
|
||||
sessionLogger.report(NumericalMetrics.CONFIGURATION_IMPLEMENTATION_COUNT, 1)
|
||||
reportLibrariesVersions(sessionLogger, dependencies)
|
||||
}
|
||||
COMPILE -> {
|
||||
sessionLogger.report(NumericalMetrics.CONFIGURATION_COMPILE_COUNT, 1)
|
||||
reportLibrariesVersions(sessionLogger, dependencies)
|
||||
}
|
||||
RUNTIME -> {
|
||||
sessionLogger.report(NumericalMetrics.CONFIGURATION_RUNTIME_COUNT, 1)
|
||||
reportLibrariesVersions(sessionLogger, dependencies)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sessionLogger.report(NumericalMetrics.NUMBER_OF_SUBPROJECTS, 1)
|
||||
sessionLogger.report(BooleanMetrics.KOTLIN_KTS_USED, project.buildscript.sourceFile?.name?.endsWith(".kts") ?: false)
|
||||
sessionLogger.report(NumericalMetrics.GRADLE_NUMBER_OF_TASKS, project.tasks.names.size.toLong())
|
||||
sessionLogger.report(
|
||||
NumericalMetrics.GRADLE_NUMBER_OF_UNCONFIGURED_TASKS,
|
||||
project.tasks.names.count { name ->
|
||||
try {
|
||||
project.tasks.named(name).javaClass.name.contains("TaskCreatingProvider")
|
||||
} catch (_: Exception) {
|
||||
true
|
||||
}
|
||||
}.toLong()
|
||||
)
|
||||
|
||||
if (buildSrcExists(project)) {
|
||||
sessionLogger.report(NumericalMetrics.BUILD_SRC_COUNT, 1)
|
||||
sessionLogger.report(BooleanMetrics.BUILD_SRC_EXISTS, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
sessionLogger.report(NumericalMetrics.STATISTICS_VISIT_ALL_PROJECTS_OVERHEAD, statisticOverhead)
|
||||
}
|
||||
|
||||
private fun reportLibrariesVersions(sessionLogger: BuildSessionLogger, dependencies: DependencySet?) {
|
||||
dependencies?.forEach { dependency ->
|
||||
when {
|
||||
dependency.group?.startsWith("org.springframework") ?: false -> sessionLogger.report(
|
||||
StringMetrics.LIBRARY_SPRING_VERSION,
|
||||
dependency.version ?: "0.0.0"
|
||||
)
|
||||
dependency.group?.startsWith("com.vaadin") ?: false -> sessionLogger.report(
|
||||
StringMetrics.LIBRARY_VAADIN_VERSION,
|
||||
dependency.version ?: "0.0.0"
|
||||
)
|
||||
dependency.group?.startsWith("com.google.gwt") ?: false -> sessionLogger.report(
|
||||
StringMetrics.LIBRARY_GWT_VERSION,
|
||||
dependency.version ?: "0.0.0"
|
||||
)
|
||||
dependency.group?.startsWith("org.hibernate") ?: false -> sessionLogger.report(
|
||||
StringMetrics.LIBRARY_HIBERNATE_VERSION,
|
||||
dependency.version ?: "0.0.0"
|
||||
)
|
||||
dependency.group == "org.jetbrains.kotlin" && dependency.name.startsWith("kotlin-stdlib") -> sessionLogger.report(
|
||||
StringMetrics.KOTLIN_STDLIB_VERSION,
|
||||
dependency.version ?: "0.0.0"
|
||||
)
|
||||
dependency.group == "org.jetbrains.kotlinx" && dependency.name == "kotlinx-coroutines" -> sessionLogger.report(
|
||||
StringMetrics.KOTLIN_COROUTINES_VERSION,
|
||||
dependency.version ?: "0.0.0"
|
||||
)
|
||||
dependency.group == "org.jetbrains.kotlin" && dependency.name == "kotlin-reflect" -> sessionLogger.report(
|
||||
StringMetrics.KOTLIN_REFLECT_VERSION,
|
||||
dependency.version ?: "0.0.0"
|
||||
)
|
||||
dependency.group == "org.jetbrains.kotlinx" && dependency.name
|
||||
.startsWith("kotlinx-serialization-runtime") -> sessionLogger.report(
|
||||
StringMetrics.KOTLIN_SERIALIZATION_VERSION,
|
||||
dependency.version ?: "0.0.0"
|
||||
)
|
||||
dependency.group == "com.android.tools.build" && dependency.name.startsWith("gradle") -> sessionLogger.report(
|
||||
StringMetrics.ANDROID_GRADLE_PLUGIN_VERSION,
|
||||
dependency.version ?: "0.0.0"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun report(sessionLogger: BuildSessionLogger, metric: BooleanMetrics, value: Boolean, subprojectName: String?) {
|
||||
runSafe("report metric ${metric.name}") {
|
||||
sessionLogger.report(metric, value, subprojectName)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal fun report(sessionLogger: BuildSessionLogger, metric: NumericalMetrics, value: Long, subprojectName: String?) {
|
||||
runSafe("report metric ${metric.name}") {
|
||||
sessionLogger.report(metric, value, subprojectName)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun report(sessionLogger: BuildSessionLogger, metric: StringMetrics, value: String, subprojectName: String?) {
|
||||
runSafe("report metric ${metric.name}") {
|
||||
sessionLogger.report(metric, value, subprojectName)
|
||||
}
|
||||
}
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.statistics
|
||||
|
||||
import org.gradle.api.invocation.Gradle
|
||||
import org.gradle.tooling.events.FinishEvent
|
||||
import org.gradle.tooling.events.OperationCompletionListener
|
||||
import org.gradle.tooling.events.configuration.ProjectConfigurationFinishEvent
|
||||
import org.jetbrains.kotlin.statistics.BuildSessionLogger
|
||||
import java.lang.management.ManagementFactory
|
||||
import javax.management.MBeanServer
|
||||
import javax.management.ObjectName
|
||||
|
||||
open class KotlinBuildStatListener(val beanName: ObjectName/*, val gradle: Gradle*/) : OperationCompletionListener, AutoCloseable {
|
||||
|
||||
private var projectEvaluatedTime: Long? = null
|
||||
|
||||
override fun onFinish(event: FinishEvent?) {
|
||||
if (event is ProjectConfigurationFinishEvent) {
|
||||
projectEvaluatedTime = event.eventTime
|
||||
}
|
||||
//todo is it any chance to get failure exception?
|
||||
//todo nothing to do?
|
||||
// KotlinBuildStatHandler.runSafe("${KotlinBuildStatListener::class.java}.onFinish") {
|
||||
//
|
||||
//
|
||||
// try {
|
||||
// val finishTime = event?.result?.endTime
|
||||
// val startTime = event?.result?.startTime
|
||||
// report(NumericalMetrics.GRADLE_BUILD_DURATION, finishTime - it.buildStartedTime)
|
||||
// report(NumericalMetrics.GRADLE_EXECUTION_DURATION, finishTime - it.projectEvaluatedTime)
|
||||
// report(NumericalMetrics.BUILD_FINISH_TIME, finishTime)
|
||||
// } finally {
|
||||
// val mbs: MBeanServer = ManagementFactory.getPlatformMBeanServer()
|
||||
// if (mbs.isRegistered(beanName)) {
|
||||
// mbs.unregisterMBean(beanName)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
// val sessionLogger = BuildSessionLogger(gradle.gradleUserHomeDir)
|
||||
// KotlinBuildStatHandler.runSafe("${KotlinBuildStatListener::class.java}.close()") {
|
||||
// try {
|
||||
// try {
|
||||
// KotlinBuildStatHandler().reportGlobalMetrics(gradle, sessionLogger)
|
||||
// } finally {
|
||||
//// report(NumericalMetrics.GRADLE_BUILD_DURATION, finishTime - it.buildStartedTime)
|
||||
//// report(NumericalMetrics.GRADLE_EXECUTION_DURATION, finishTime - it.projectEvaluatedTime)
|
||||
//// report(NumericalMetrics.BUILD_FINISH_TIME, finishTime)
|
||||
// }
|
||||
//
|
||||
// } finally {
|
||||
// val mbs: MBeanServer = ManagementFactory.getPlatformMBeanServer()
|
||||
// if (mbs.isRegistered(beanName)) {
|
||||
// mbs.unregisterMBean(beanName)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
+17
-175
@@ -8,15 +8,13 @@ package org.jetbrains.kotlin.gradle.plugin.statistics
|
||||
import org.gradle.BuildAdapter
|
||||
import org.gradle.BuildResult
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.DependencySet
|
||||
import org.gradle.api.invocation.Gradle
|
||||
import org.gradle.api.logging.Logging
|
||||
import org.gradle.initialization.BuildRequestMetaData
|
||||
import org.gradle.invocation.DefaultGradle
|
||||
import org.jetbrains.kotlin.gradle.utils.API
|
||||
import org.jetbrains.kotlin.gradle.utils.COMPILE
|
||||
import org.jetbrains.kotlin.gradle.utils.IMPLEMENTATION
|
||||
import org.jetbrains.kotlin.gradle.utils.RUNTIME
|
||||
import org.jetbrains.kotlin.gradle.plugin.BuildEventsListenerRegistryHolder
|
||||
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatHandler.Companion.runSafe
|
||||
import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable
|
||||
import org.jetbrains.kotlin.statistics.BuildSessionLogger
|
||||
import org.jetbrains.kotlin.statistics.BuildSessionLogger.Companion.STATISTICS_FOLDER_NAME
|
||||
import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics
|
||||
@@ -87,8 +85,10 @@ internal abstract class KotlinBuildStatsService internal constructor() : BuildAd
|
||||
*/
|
||||
@JvmStatic
|
||||
@Synchronized
|
||||
internal fun getOrCreateInstance(gradle: Gradle): IStatisticsValuesConsumer? {
|
||||
internal fun getOrCreateInstance(project: Project, listenerRegistryHolder: BuildEventsListenerRegistryHolder): IStatisticsValuesConsumer? {
|
||||
|
||||
return runSafe("${KotlinBuildStatsService::class.java}.getOrCreateInstance") {
|
||||
val gradle = project.gradle
|
||||
statisticsIsEnabled = statisticsIsEnabled ?: checkStatisticsEnabled(gradle)
|
||||
if (statisticsIsEnabled != true) {
|
||||
null
|
||||
@@ -106,13 +106,17 @@ internal abstract class KotlinBuildStatsService internal constructor() : BuildAd
|
||||
)
|
||||
instance = JMXKotlinBuildStatsService(mbs, beanName)
|
||||
} else {
|
||||
val kotlinBuildStatProvider = project.provider{ KotlinBuildStatListener(beanName) }
|
||||
val newInstance = DefaultKotlinBuildStatsService(gradle, beanName)
|
||||
|
||||
instance = newInstance
|
||||
log.debug("Instantiated ${KotlinBuildStatsService::class.java}: new instance $instance")
|
||||
mbs.registerMBean(StandardMBean(newInstance, KotlinBuildStatsMXBean::class.java), beanName)
|
||||
}
|
||||
}
|
||||
gradle.addBuildListener(instance)
|
||||
if (!isConfigurationCacheAvailable(gradle)) {
|
||||
gradle.addBuildListener(instance)
|
||||
}
|
||||
instance
|
||||
}
|
||||
}
|
||||
@@ -130,7 +134,7 @@ internal abstract class KotlinBuildStatsService internal constructor() : BuildAd
|
||||
}
|
||||
this.report(NumericalMetrics.STATISTICS_COLLECT_METRICS_OVERHEAD, duration)
|
||||
} catch (e: Throwable) {
|
||||
logException("Could collect statistics metrics", e)
|
||||
KotlinBuildStatHandler.logException("Could collect statistics metrics", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,21 +153,6 @@ internal abstract class KotlinBuildStatsService internal constructor() : BuildAd
|
||||
gradle.rootProject.properties[ENABLE_STATISTICS_PROPERTY_NAME]?.toString()?.toBoolean() ?: DEFAULT_STATISTICS_STATE
|
||||
}
|
||||
}
|
||||
|
||||
private fun logException(description: String, e: Throwable) {
|
||||
getLogger().info(description)
|
||||
getLogger().debug(e.message, e)
|
||||
}
|
||||
|
||||
internal fun <T> runSafe(methodName: String, action: () -> T?): T? {
|
||||
return try {
|
||||
getLogger().debug("Executing [$methodName]")
|
||||
action.invoke()
|
||||
} catch (e: Throwable) {
|
||||
logException("Could not execute [$methodName]", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,132 +201,6 @@ internal class DefaultKotlinBuildStatsService internal constructor(
|
||||
return (gradle as? DefaultGradle)?.services?.get(BuildRequestMetaData::class.java)?.startTime
|
||||
}
|
||||
|
||||
private fun reportLibrariesVersions(dependencies: DependencySet?) {
|
||||
dependencies?.forEach { dependency ->
|
||||
when {
|
||||
dependency.group?.startsWith("org.springframework") ?: false -> sessionLogger.report(
|
||||
StringMetrics.LIBRARY_SPRING_VERSION,
|
||||
dependency.version ?: "0.0.0"
|
||||
)
|
||||
dependency.group?.startsWith("com.vaadin") ?: false -> sessionLogger.report(
|
||||
StringMetrics.LIBRARY_VAADIN_VERSION,
|
||||
dependency.version ?: "0.0.0"
|
||||
)
|
||||
dependency.group?.startsWith("com.google.gwt") ?: false -> sessionLogger.report(
|
||||
StringMetrics.LIBRARY_GWT_VERSION,
|
||||
dependency.version ?: "0.0.0"
|
||||
)
|
||||
dependency.group?.startsWith("org.hibernate") ?: false -> sessionLogger.report(
|
||||
StringMetrics.LIBRARY_HIBERNATE_VERSION,
|
||||
dependency.version ?: "0.0.0"
|
||||
)
|
||||
dependency.group == "org.jetbrains.kotlin" && dependency.name.startsWith("kotlin-stdlib") -> sessionLogger.report(
|
||||
StringMetrics.KOTLIN_STDLIB_VERSION,
|
||||
dependency.version ?: "0.0.0"
|
||||
)
|
||||
dependency.group == "org.jetbrains.kotlinx" && dependency.name == "kotlinx-coroutines" -> sessionLogger.report(
|
||||
StringMetrics.KOTLIN_COROUTINES_VERSION,
|
||||
dependency.version ?: "0.0.0"
|
||||
)
|
||||
dependency.group == "org.jetbrains.kotlin" && dependency.name == "kotlin-reflect" -> sessionLogger.report(
|
||||
StringMetrics.KOTLIN_REFLECT_VERSION,
|
||||
dependency.version ?: "0.0.0"
|
||||
)
|
||||
dependency.group == "org.jetbrains.kotlinx" && dependency.name
|
||||
.startsWith("kotlinx-serialization-runtime") -> sessionLogger.report(
|
||||
StringMetrics.KOTLIN_SERIALIZATION_VERSION,
|
||||
dependency.version ?: "0.0.0"
|
||||
)
|
||||
dependency.group == "com.android.tools.build" && dependency.name.startsWith("gradle") -> sessionLogger.report(
|
||||
StringMetrics.ANDROID_GRADLE_PLUGIN_VERSION,
|
||||
dependency.version ?: "0.0.0"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun reportGlobalMetrics(gradle: Gradle) {
|
||||
System.getProperty("os.name")?.also {
|
||||
sessionLogger.report(StringMetrics.OS_TYPE, System.getProperty("os.name"))
|
||||
}
|
||||
sessionLogger.report(NumericalMetrics.CPU_NUMBER_OF_CORES, Runtime.getRuntime().availableProcessors().toLong())
|
||||
sessionLogger.report(StringMetrics.GRADLE_VERSION, gradle.gradleVersion)
|
||||
sessionLogger.report(BooleanMetrics.EXECUTED_FROM_IDEA, System.getProperty("idea.active") != null)
|
||||
sessionLogger.report(NumericalMetrics.GRADLE_DAEMON_HEAP_SIZE, Runtime.getRuntime().maxMemory())
|
||||
sessionLogger.report(
|
||||
BooleanMetrics.KOTLIN_OFFICIAL_CODESTYLE,
|
||||
gradle.rootProject.properties["kotlin.code.style"] == "official"
|
||||
) // constants are saved in IDEA plugin and could not be accessed directly
|
||||
|
||||
gradle.taskGraph.whenReady() { taskExecutionGraph ->
|
||||
val executedTaskNames = taskExecutionGraph.allTasks.map { it.name }.distinct()
|
||||
report(BooleanMetrics.COMPILATION_STARTED, executedTaskNames.contains("compileKotlin"))
|
||||
report(BooleanMetrics.TESTS_EXECUTED, executedTaskNames.contains("compileTestKotlin"))
|
||||
report(BooleanMetrics.MAVEN_PUBLISH_EXECUTED, executedTaskNames.contains("install"))
|
||||
}
|
||||
|
||||
fun buildSrcExists(project: Project) = File(project.projectDir, "buildSrc").exists()
|
||||
if (buildSrcExists(gradle.rootProject)) {
|
||||
sessionLogger.report(BooleanMetrics.BUILD_SRC_EXISTS, true)
|
||||
}
|
||||
val statisticOverhead = measureTimeMillis {
|
||||
gradle.allprojects { project ->
|
||||
for (configuration in project.configurations) {
|
||||
val configurationName = configuration.name
|
||||
val dependencies = configuration.dependencies
|
||||
|
||||
when (configurationName) {
|
||||
"kapt" -> {
|
||||
sessionLogger.report(BooleanMetrics.ENABLED_KAPT, true)
|
||||
dependencies?.forEach { dependency ->
|
||||
when (dependency.group) {
|
||||
"com.google.dagger" -> sessionLogger.report(BooleanMetrics.ENABLED_DAGGER, true)
|
||||
"com.android.databinding" -> sessionLogger.report(BooleanMetrics.ENABLED_DATABINDING, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
API -> {
|
||||
sessionLogger.report(NumericalMetrics.CONFIGURATION_API_COUNT, 1)
|
||||
reportLibrariesVersions(dependencies)
|
||||
}
|
||||
IMPLEMENTATION -> {
|
||||
sessionLogger.report(NumericalMetrics.CONFIGURATION_IMPLEMENTATION_COUNT, 1)
|
||||
reportLibrariesVersions(dependencies)
|
||||
}
|
||||
COMPILE -> {
|
||||
sessionLogger.report(NumericalMetrics.CONFIGURATION_COMPILE_COUNT, 1)
|
||||
reportLibrariesVersions(dependencies)
|
||||
}
|
||||
RUNTIME -> {
|
||||
sessionLogger.report(NumericalMetrics.CONFIGURATION_RUNTIME_COUNT, 1)
|
||||
reportLibrariesVersions(dependencies)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sessionLogger.report(NumericalMetrics.NUMBER_OF_SUBPROJECTS, 1)
|
||||
sessionLogger.report(BooleanMetrics.KOTLIN_KTS_USED, project.buildscript.sourceFile?.name?.endsWith(".kts") ?: false)
|
||||
sessionLogger.report(NumericalMetrics.GRADLE_NUMBER_OF_TASKS, project.tasks.names.size.toLong())
|
||||
sessionLogger.report(
|
||||
NumericalMetrics.GRADLE_NUMBER_OF_UNCONFIGURED_TASKS,
|
||||
project.tasks.names.count { name ->
|
||||
try {
|
||||
project.tasks.named(name).javaClass.name.contains("TaskCreatingProvider")
|
||||
} catch (_: Exception) {
|
||||
true
|
||||
}
|
||||
}.toLong()
|
||||
)
|
||||
|
||||
if (buildSrcExists(project)) {
|
||||
sessionLogger.report(NumericalMetrics.BUILD_SRC_COUNT, 1)
|
||||
sessionLogger.report(BooleanMetrics.BUILD_SRC_EXISTS, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
sessionLogger.report(NumericalMetrics.STATISTICS_VISIT_ALL_PROJECTS_OVERHEAD, statisticOverhead)
|
||||
}
|
||||
|
||||
override fun projectsEvaluated(gradle: Gradle) {
|
||||
runSafe("${DefaultKotlinBuildStatsService::class.java}.projectEvaluated") {
|
||||
if (!sessionLogger.isBuildSessionStarted()) {
|
||||
@@ -351,41 +214,20 @@ internal class DefaultKotlinBuildStatsService internal constructor(
|
||||
|
||||
@Synchronized
|
||||
override fun buildFinished(result: BuildResult) {
|
||||
runSafe("${DefaultKotlinBuildStatsService::class.java}.buildFinished") {
|
||||
try {
|
||||
try {
|
||||
val gradle = result.gradle
|
||||
if (gradle != null) reportGlobalMetrics(gradle)
|
||||
} finally {
|
||||
sessionLogger.finishBuildSession(result.action, result.failure)
|
||||
}
|
||||
} finally {
|
||||
val mbs: MBeanServer = ManagementFactory.getPlatformMBeanServer()
|
||||
if (mbs.isRegistered(beanName)) {
|
||||
mbs.unregisterMBean(beanName)
|
||||
}
|
||||
instance = null
|
||||
}
|
||||
}
|
||||
KotlinBuildStatHandler().buildFinished(result.gradle, beanName, sessionLogger, result.action, result.failure)
|
||||
instance = null
|
||||
}
|
||||
|
||||
override fun report(metric: BooleanMetrics, value: Boolean, subprojectName: String?) {
|
||||
runSafe("report metric ${metric.name}") {
|
||||
sessionLogger.report(metric, value, subprojectName)
|
||||
}
|
||||
|
||||
KotlinBuildStatHandler().report(sessionLogger, metric, value, subprojectName)
|
||||
}
|
||||
|
||||
override fun report(metric: NumericalMetrics, value: Long, subprojectName: String?) {
|
||||
runSafe("report metric ${metric.name}") {
|
||||
sessionLogger.report(metric, value, subprojectName)
|
||||
}
|
||||
KotlinBuildStatHandler().report(sessionLogger, metric, value, subprojectName)
|
||||
}
|
||||
|
||||
override fun report(metric: StringMetrics, value: String, subprojectName: String?) {
|
||||
runSafe("report metric ${metric.name}") {
|
||||
sessionLogger.report(metric, value, subprojectName)
|
||||
}
|
||||
KotlinBuildStatHandler().report(sessionLogger, metric, value, subprojectName)
|
||||
}
|
||||
|
||||
override fun reportBoolean(name: String, value: Boolean, subprojectName: String?) {
|
||||
|
||||
+7
-92
@@ -16,11 +16,10 @@ import org.jetbrains.kotlin.gradle.logging.kotlinDebug
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
||||
import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskExecutionResults
|
||||
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
|
||||
import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable
|
||||
import java.io.File
|
||||
import java.lang.StringBuilder
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import kotlin.math.max
|
||||
|
||||
internal fun configureBuildReporter(gradle: Gradle, log: Logger) {
|
||||
val rootProject = gradle.rootProject
|
||||
@@ -40,8 +39,11 @@ internal fun configureBuildReporter(gradle: Gradle, log: Logger) {
|
||||
val ts = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(Calendar.getInstance().time)
|
||||
|
||||
val perfReportFile = perfLogDir.resolve("${gradle.rootProject.name}-build-$ts.txt")
|
||||
val reporter = KotlinBuildReporter(gradle, perfReportFile)
|
||||
gradle.addBuildListener(reporter)
|
||||
|
||||
if (!isConfigurationCacheAvailable(gradle)) {
|
||||
val reporter = KotlinBuildReporter(gradle, perfReportFile)
|
||||
gradle.addBuildListener(reporter)
|
||||
}
|
||||
|
||||
val buildReportMode = if (properties.buildReportVerbose) BuildReportMode.VERBOSE else BuildReportMode.SIMPLE
|
||||
|
||||
@@ -112,94 +114,7 @@ internal class KotlinBuildReporter(
|
||||
|
||||
@Synchronized
|
||||
override fun buildFinished(result: BuildResult) {
|
||||
val logger = result.gradle?.rootProject?.logger
|
||||
try {
|
||||
perfReportFile.writeText(buildInfo(result) + taskOverview() + tasksSb.toString())
|
||||
logger?.lifecycle("Kotlin build report is written to ${perfReportFile.canonicalPath}")
|
||||
} catch (e: Throwable) {
|
||||
logger?.error("Could not write Kotlin build report to ${perfReportFile.canonicalPath}", e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildInfo(result: BuildResult): String {
|
||||
val startParams = arrayListOf<String>()
|
||||
gradle.startParameter.apply {
|
||||
startParams.add("tasks = ${taskRequests.joinToString { it.args.toString() }}")
|
||||
startParams.add("excluded tasks = $excludedTaskNames")
|
||||
startParams.add("current dir = $currentDir")
|
||||
startParams.add("project properties args = $projectProperties")
|
||||
startParams.add("system properties args = $systemPropertiesArgs")
|
||||
}
|
||||
|
||||
return buildString {
|
||||
appendln("Gradle start parameters:")
|
||||
startParams.forEach {
|
||||
appendln(" $it")
|
||||
}
|
||||
if (result.failure != null) {
|
||||
appendln("Build failed: ${result.failure}")
|
||||
}
|
||||
appendln()
|
||||
}
|
||||
}
|
||||
|
||||
private fun taskOverview(): String {
|
||||
if (kotlinTaskTimeNs.isEmpty()) return buildString { appendln("No Kotlin task was run") }
|
||||
|
||||
val sb = StringBuilder()
|
||||
val kotlinTotalTimeNs = kotlinTaskTimeNs.values.sum()
|
||||
val ktTaskPercent = (kotlinTotalTimeNs.toDouble() / allTasksTimeNs * 100).asString(1)
|
||||
|
||||
sb.appendln("Total time for Kotlin tasks: ${formatTime(kotlinTotalTimeNs)} ($ktTaskPercent % of all tasks time)")
|
||||
|
||||
val table = TextTable("Time", "% of Kotlin time", "Task")
|
||||
kotlinTaskTimeNs.entries
|
||||
.sortedByDescending { (_, timeNs) -> timeNs }
|
||||
.forEach { (task, timeNs) ->
|
||||
val percent = (timeNs.toDouble() / kotlinTotalTimeNs * 100).asString(1)
|
||||
table.addRow(formatTime(timeNs), "$percent %", task.path)
|
||||
}
|
||||
table.printTo(sb)
|
||||
sb.appendln()
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
private fun formatTime(ns: Long): String {
|
||||
val seconds = ns.toDouble() / 1_000_000_000
|
||||
return seconds.asString(2) + " s"
|
||||
}
|
||||
|
||||
private fun Double.asString(decPoints: Int): String =
|
||||
String.format("%.${decPoints}f", this)
|
||||
|
||||
private class TextTable(vararg columnNames: String) {
|
||||
private val rows = ArrayList<List<String>>()
|
||||
private val columnsCount = columnNames.size
|
||||
private val maxLengths = IntArray(columnsCount) { columnNames[it].length }
|
||||
|
||||
init {
|
||||
rows.add(columnNames.toList())
|
||||
}
|
||||
|
||||
fun addRow(vararg row: String) {
|
||||
check(row.size == columnsCount) { "Row size ${row.size} differs from columns count $columnsCount" }
|
||||
rows.add(row.toList())
|
||||
|
||||
for ((i, col) in row.withIndex()) {
|
||||
maxLengths[i] = max(maxLengths[i], col.length)
|
||||
}
|
||||
}
|
||||
|
||||
fun printTo(sb: StringBuilder) {
|
||||
for (row in rows) {
|
||||
sb.appendln()
|
||||
for ((i, col) in row.withIndex()) {
|
||||
if (i > 0) sb.append("|")
|
||||
|
||||
sb.append(col.padEnd(maxLengths[i], ' '))
|
||||
}
|
||||
}
|
||||
}
|
||||
KotlinBuildReporterHandler().buildFinished(gradle, perfReportFile, kotlinTaskTimeNs.mapKeys{it.key.path}, allTasksTimeNs, result.failure)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.report
|
||||
|
||||
import org.gradle.api.invocation.Gradle
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import kotlin.math.max
|
||||
|
||||
class KotlinBuildReporterHandler {
|
||||
fun buildFinished(
|
||||
gradle: Gradle,
|
||||
perfReportFile: File,
|
||||
kotlinTaskTimeNs: Map<String, Long>,
|
||||
allTasksTimeNs: Long,
|
||||
failure: Throwable? = null
|
||||
) {
|
||||
val logger = gradle.rootProject.logger
|
||||
try {
|
||||
perfReportFile.writeText(buildInfo(gradle, failure) + taskOverview(kotlinTaskTimeNs, allTasksTimeNs))
|
||||
logger.lifecycle("Kotlin build report is written to ${perfReportFile.canonicalPath}")
|
||||
} catch (e: Throwable) {
|
||||
logger.error("Could not write Kotlin build report to ${perfReportFile.canonicalPath}", e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildInfo(gradle: Gradle, failure: Throwable?): String {
|
||||
val startParams = arrayListOf<String>()
|
||||
gradle.startParameter.apply {
|
||||
startParams.add("tasks = ${taskRequests.joinToString { it.args.toString() }}")
|
||||
startParams.add("excluded tasks = $excludedTaskNames")
|
||||
startParams.add("current dir = $currentDir")
|
||||
startParams.add("project properties args = $projectProperties")
|
||||
startParams.add("system properties args = $systemPropertiesArgs")
|
||||
}
|
||||
|
||||
return buildString {
|
||||
appendln("Gradle start parameters:")
|
||||
startParams.forEach {
|
||||
appendln(" $it")
|
||||
}
|
||||
if (failure != null) {
|
||||
appendln("Build failed: ${failure}")
|
||||
}
|
||||
appendln()
|
||||
}
|
||||
}
|
||||
|
||||
internal fun taskOverview(kotlinTaskTimeNs: Map<String, Long>, allTasksTimeNs: Long): String {
|
||||
if (kotlinTaskTimeNs.isEmpty()) return buildString { appendln("No Kotlin task was run") }
|
||||
|
||||
val sb = StringBuilder()
|
||||
val kotlinTotalTimeNs = kotlinTaskTimeNs.values.sum()
|
||||
val ktTaskPercent = (kotlinTotalTimeNs.toDouble() / allTasksTimeNs * 100).asString(1)
|
||||
|
||||
sb.appendln("Total time for Kotlin tasks: ${formatTime(kotlinTotalTimeNs)} ($ktTaskPercent % of all tasks time)")
|
||||
|
||||
val table = TextTable("Time", "% of Kotlin time", "Task")
|
||||
kotlinTaskTimeNs.entries
|
||||
.sortedByDescending { (_, timeNs) -> timeNs }
|
||||
.forEach { (taskPath, timeNs) ->
|
||||
val percent = (timeNs.toDouble() / kotlinTotalTimeNs * 100).asString(1)
|
||||
table.addRow(formatTime(timeNs), "$percent %", taskPath)
|
||||
}
|
||||
table.printTo(sb)
|
||||
sb.appendln()
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
internal class TextTable(vararg columnNames: String) {
|
||||
private val rows = ArrayList<List<String>>()
|
||||
private val columnsCount = columnNames.size
|
||||
private val maxLengths = IntArray(columnsCount) { columnNames[it].length }
|
||||
|
||||
init {
|
||||
rows.add(columnNames.toList())
|
||||
}
|
||||
|
||||
fun addRow(vararg row: String) {
|
||||
check(row.size == columnsCount) { "Row size ${row.size} differs from columns count $columnsCount" }
|
||||
rows.add(row.toList())
|
||||
|
||||
for ((i, col) in row.withIndex()) {
|
||||
maxLengths[i] = max(maxLengths[i], col.length)
|
||||
}
|
||||
}
|
||||
|
||||
fun printTo(sb: StringBuilder) {
|
||||
for (row in rows) {
|
||||
sb.appendln()
|
||||
for ((i, col) in row.withIndex()) {
|
||||
if (i > 0) sb.append("|")
|
||||
|
||||
sb.append(col.padEnd(maxLengths[i], ' '))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun formatTime(ns: Long): String {
|
||||
val seconds = ns.toDouble() / 1_000_000_000
|
||||
return seconds.asString(2) + " s"
|
||||
}
|
||||
|
||||
internal fun Double.asString(decPoints: Int): String =
|
||||
String.format("%.${decPoints}f", this)
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.report
|
||||
|
||||
import com.intellij.util.text.DateFormatUtil.formatTime
|
||||
import org.gradle.api.invocation.Gradle
|
||||
import org.gradle.tooling.events.FinishEvent
|
||||
import org.gradle.tooling.events.OperationCompletionListener
|
||||
import org.gradle.tooling.events.task.TaskOperationDescriptor
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
class KotlinBuildReporterListener(val gradle: Gradle, val perfReportFile: File) : OperationCompletionListener, AutoCloseable {
|
||||
|
||||
private val kotlinTaskTimeNs = HashMap<String, Long>()
|
||||
internal var allTasksTimeNs: Long = 0L
|
||||
|
||||
override fun onFinish(event: FinishEvent?) {
|
||||
val descriptor = event?.descriptor
|
||||
if (descriptor is TaskOperationDescriptor) {
|
||||
val taskPath = descriptor.taskPath
|
||||
val executionTime = event.result.endTime - event.result.startTime
|
||||
allTasksTimeNs += executionTime
|
||||
kotlinTaskTimeNs[taskPath] = executionTime
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
KotlinBuildReporterHandler().buildFinished(gradle, perfReportFile, kotlinTaskTimeNs, allTasksTimeNs)
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle.targets.js.ir
|
||||
import org.gradle.api.tasks.CacheableTask
|
||||
import org.gradle.workers.WorkerExecutor
|
||||
import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers
|
||||
import org.jetbrains.kotlin.gradle.tasks.GradleCompileTaskProvider
|
||||
import javax.inject.Inject
|
||||
|
||||
@CacheableTask
|
||||
@@ -16,5 +17,5 @@ internal open class KotlinJsIrLinkWithWorkers
|
||||
constructor(
|
||||
private val workerExecutor: WorkerExecutor
|
||||
) : KotlinJsIrLink() {
|
||||
override fun compilerRunner() = GradleCompilerRunnerWithWorkers(this, workerExecutor)
|
||||
override fun compilerRunner() = GradleCompilerRunnerWithWorkers(GradleCompileTaskProvider(this), workerExecutor)
|
||||
}
|
||||
+6
-3
@@ -10,6 +10,7 @@ import org.gradle.api.NamedDomainObjectContainer
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.gradle.api.plugins.JavaPlugin
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.jvm.tasks.Jar
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
||||
@@ -44,10 +45,12 @@ open class KotlinWithJavaTarget<KotlinOptionsType : KotlinCommonOptions>(
|
||||
KotlinWithJavaCompilationFactory(project, this, kotlinOptionsFactory)
|
||||
)
|
||||
|
||||
internal val defaultArtifactClassesListFile: File
|
||||
get() {
|
||||
private val layout = project.layout
|
||||
|
||||
internal val defaultArtifactClassesListFile: Provider<File> =
|
||||
layout.buildDirectory.dir(KOTLIN_BUILD_DIR_NAME).map {
|
||||
val jarTask = project.tasks.getByName(artifactsTaskName) as Jar
|
||||
return File(File(project.buildDir, KOTLIN_BUILD_DIR_NAME), "${sanitizeFileName(jarTask.archiveFileName.get())}-classes.txt")
|
||||
it.file("${sanitizeFileName(jarTask.archiveFileName.get())}-classes.txt").asFile
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+25
@@ -457,6 +457,31 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
|
||||
}
|
||||
}
|
||||
)
|
||||
/*
|
||||
val transformedFilesByOriginalFiles = project.provider {
|
||||
transformationTaskHolders
|
||||
.flatMap { it.get().filesByOriginalFiles.toList() }
|
||||
.groupBy({ it.first }, valueTransform = { it.second })
|
||||
}
|
||||
|
||||
val builtBySet = mutableSetOf<FileCollection>()
|
||||
val resultFiles = project.files(Callable {
|
||||
val originalFiles = fromFiles.toSet()
|
||||
val filesToAdd = mutableSetOf<File>()
|
||||
val filesToExclude = mutableSetOf<File>()
|
||||
|
||||
transformedFilesByOriginalFiles.get().forEach { (original, replacement) ->
|
||||
if (original.all { it in originalFiles }) {
|
||||
builtBySet.addAll(replacement)
|
||||
filesToAdd += replacement.flatMap { it.files }
|
||||
filesToExclude += original
|
||||
}
|
||||
}
|
||||
|
||||
originalFiles - filesToExclude + filesToAdd
|
||||
})
|
||||
return resultFiles.builtBy(builtBySet)
|
||||
*/
|
||||
}
|
||||
|
||||
private fun createCommonMainElementsConfiguration(target: KotlinMetadataTarget) {
|
||||
|
||||
-2
@@ -10,9 +10,7 @@ import groovy.lang.Closure
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.NamedDomainObjectContainer
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.file.SourceDirectorySet
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.gradle.util.ConfigureUtil
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
|
||||
|
||||
+1
-1
@@ -156,7 +156,7 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget>(
|
||||
val compileTaskProvider = registerTask<KotlinNativeCompile>(
|
||||
compilation.compileKotlinTaskName
|
||||
) {
|
||||
it.compilation = compilation
|
||||
it.compilation.set(compilation)
|
||||
it.group = BasePlugin.BUILD_GROUP
|
||||
it.description = "Compiles a klibrary from the '${compilation.name}' " +
|
||||
"compilation for target '${compilation.platformType.name}'."
|
||||
|
||||
+4
-5
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.gradle.targets.native.internal.PlatformLibrariesGene
|
||||
import org.jetbrains.kotlin.gradle.targets.native.internal.setUpKotlinNativePlatformDependencies
|
||||
import org.jetbrains.kotlin.gradle.utils.NativeCompilerDownloader
|
||||
import org.jetbrains.kotlin.gradle.utils.SingleActionPerProject
|
||||
import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable
|
||||
import org.jetbrains.kotlin.konan.CompilerVersion
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
@@ -89,11 +90,9 @@ abstract class AbstractKotlinNativeTargetPreset<T : KotlinNativeTarget>(
|
||||
createTargetConfigurator().configureTarget(result)
|
||||
|
||||
SingleActionPerProject.run(project, "setUpKotlinNativePlatformDependencies") {
|
||||
project.gradle.addListener(object : BuildAdapter() {
|
||||
override fun projectsEvaluated(gradle: Gradle) {
|
||||
project.setUpKotlinNativePlatformDependencies()
|
||||
}
|
||||
})
|
||||
project.gradle.projectsEvaluated {
|
||||
project.setUpKotlinNativePlatformDependencies()
|
||||
}
|
||||
}
|
||||
|
||||
if (!konanTarget.enabledOnCurrentHost) {
|
||||
|
||||
+1
-6
@@ -8,11 +8,9 @@ package org.jetbrains.kotlin.gradle.plugin.cocoapods
|
||||
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.Sync
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||
@@ -20,10 +18,7 @@ import org.jetbrains.kotlin.gradle.plugin.addExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.whenEvaluated
|
||||
import org.jetbrains.kotlin.gradle.targets.native.tasks.*
|
||||
import org.jetbrains.kotlin.gradle.tasks.DefFileTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.DummyFrameworkTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.FatFrameworkTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.PodspecTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.*
|
||||
import org.jetbrains.kotlin.gradle.utils.asValidTaskName
|
||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
|
||||
+20
-11
@@ -16,8 +16,8 @@ import org.jetbrains.kotlin.gradle.plugin.addExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.disambiguateName
|
||||
import org.jetbrains.kotlin.gradle.targets.native.tasks.NativePerformanceReport
|
||||
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
||||
import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable
|
||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||
import java.io.File
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class TaskTime(val startTime: Long) {
|
||||
@@ -66,17 +66,26 @@ open class KotlinPerformancePlugin : Plugin<Project> {
|
||||
|
||||
private fun configureTasks(project: Project, performanceExtension: PerformanceExtension) {
|
||||
// Add time listener.
|
||||
val timeListener = TaskTimerListener(project)
|
||||
project.gradle.addListener(timeListener)
|
||||
performanceExtension.trackedBinaries.forEach { binary ->
|
||||
val perfReport = project.registerTask<NativePerformanceReport>(binary.target.disambiguateName(lowerCamelCaseName("perfReport", binary.name))) {
|
||||
it.binary = binary
|
||||
it.settings = performanceExtension
|
||||
it.timeListener = timeListener
|
||||
it.group = TASK_GROUP
|
||||
it.description = "Report performance measurement results for binary '${binary.name}' of target '${binary.target.name}'."
|
||||
if (!isConfigurationCacheAvailable(project.gradle)) {
|
||||
val timeListener = TaskTimerListener(project)
|
||||
project.gradle.addListener(timeListener)
|
||||
performanceExtension.trackedBinaries.forEach { binary ->
|
||||
val perfReport = project.registerTask<NativePerformanceReport>(
|
||||
binary.target.disambiguateName(
|
||||
lowerCamelCaseName(
|
||||
"perfReport",
|
||||
binary.name
|
||||
)
|
||||
)
|
||||
) {
|
||||
it.binary = binary
|
||||
it.settings = performanceExtension
|
||||
it.timeListener = timeListener
|
||||
it.group = TASK_GROUP
|
||||
it.description = "Report performance measurement results for binary '${binary.name}' of target '${binary.target.name}'."
|
||||
}
|
||||
binary.linkTaskProvider.configure { linkTask -> linkTask.finalizedBy(perfReport) }
|
||||
}
|
||||
binary.linkTaskProvider.configure { linkTask -> linkTask.finalizedBy(perfReport) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -70,15 +70,15 @@ open class NativePerformanceReport : DefaultTask() {
|
||||
}
|
||||
|
||||
private fun getPerformanceCompilerOptions() =
|
||||
(compilerFlagsFromBinary() + binary.linkTask.compilation.kotlinOptions.freeCompilerArgs)
|
||||
(compilerFlagsFromBinary() + binary.linkTask.compilation.get().kotlinOptions.freeCompilerArgs)
|
||||
.filter { it in listOf("-g", "-opt", "-Xg0") }.map { "\"$it\"" }
|
||||
|
||||
@TaskAction
|
||||
fun generate() {
|
||||
val compileTasks = if (settings.includeAssociatedTasks)
|
||||
getAllExecutedTasks(binary.linkTask.compilation)
|
||||
getAllExecutedTasks(binary.linkTask.compilation.get())
|
||||
else
|
||||
listOf(binary.linkTask.compilation.compileKotlinTask)
|
||||
listOf(binary.linkTask.compilation.get().compileKotlinTask)
|
||||
val allExecutedTasks = listOf(binary.linkTask) + compileTasks
|
||||
val upToDateTasks = allExecutedTasks.filter { it.state.upToDate }.map { it.name }
|
||||
if (upToDateTasks.isNotEmpty()) {
|
||||
|
||||
+87
-65
@@ -13,8 +13,8 @@ import org.gradle.api.artifacts.*
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.file.FileTree
|
||||
import org.gradle.api.file.SourceDirectorySet
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.api.tasks.compile.AbstractCompile
|
||||
@@ -26,12 +26,12 @@ import org.jetbrains.kotlin.gradle.dsl.NativeCacheKind
|
||||
import org.jetbrains.kotlin.gradle.internal.ensureParentDirsCreated
|
||||
import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName
|
||||
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
|
||||
import org.jetbrains.kotlin.gradle.targets.native.internal.isAllowCommonizer
|
||||
import org.jetbrains.kotlin.gradle.utils.getValue
|
||||
import org.jetbrains.kotlin.gradle.utils.klibModuleName
|
||||
import org.jetbrains.kotlin.gradle.utils.newProperty
|
||||
import org.jetbrains.kotlin.gradle.utils.listFilesOrEmpty
|
||||
import org.jetbrains.kotlin.konan.library.KLIB_INTEROP_IR_PROVIDER_IDENTIFIER
|
||||
import org.jetbrains.kotlin.konan.properties.saveToFile
|
||||
@@ -112,7 +112,7 @@ private fun Collection<File>.filterKlibsPassedToCompiler(project: Project) = fil
|
||||
}
|
||||
|
||||
// endregion
|
||||
abstract class AbstractKotlinNativeCompile<T : KotlinCommonToolOptions> : AbstractCompile() {
|
||||
abstract class AbstractKotlinNativeCompile<T : KotlinCommonToolOptions, K : AbstractKotlinNativeCompilation> : AbstractCompile() {
|
||||
|
||||
init {
|
||||
sourceCompatibility = "1.6"
|
||||
@@ -120,7 +120,7 @@ abstract class AbstractKotlinNativeCompile<T : KotlinCommonToolOptions> : Abstra
|
||||
}
|
||||
|
||||
@get:Internal
|
||||
abstract val compilation: AbstractKotlinNativeCompilation
|
||||
abstract val compilation: Provider<K>
|
||||
|
||||
// region inputs/outputs
|
||||
@get:Input
|
||||
@@ -136,20 +136,21 @@ abstract class AbstractKotlinNativeCompile<T : KotlinCommonToolOptions> : Abstra
|
||||
abstract val baseName: String
|
||||
|
||||
// Inputs and outputs
|
||||
val libraries: FileCollection
|
||||
@InputFiles get() =
|
||||
// Avoid resolving these dependencies during task graph construction when we can't build the target:
|
||||
if (compilation.konanTarget.enabledOnCurrentHost)
|
||||
compilation.compileDependencyFiles.filterOutPublishableInteropLibs(project)
|
||||
else project.files()
|
||||
@get:InputFiles
|
||||
val libraries: FileCollection by project.provider {
|
||||
// Avoid resolving these dependencies during task graph construction when we can't build the target:
|
||||
if (compilation.get().konanTarget.enabledOnCurrentHost)
|
||||
compilation.get().compileDependencyFiles.filterOutPublishableInteropLibs(project)
|
||||
else project.files()
|
||||
}
|
||||
|
||||
override fun getClasspath(): FileCollection = libraries
|
||||
override fun setClasspath(configuration: FileCollection?) {
|
||||
throw UnsupportedOperationException("Setting classpath directly is unsupported.")
|
||||
}
|
||||
|
||||
val target: String
|
||||
@Input get() = compilation.konanTarget.name
|
||||
@get:Input
|
||||
val target: String by project.provider { compilation.get().konanTarget.name }
|
||||
|
||||
// region Compiler options.
|
||||
@get:Internal
|
||||
@@ -158,11 +159,12 @@ abstract class AbstractKotlinNativeCompile<T : KotlinCommonToolOptions> : Abstra
|
||||
abstract fun kotlinOptions(fn: Closure<*>)
|
||||
|
||||
@get:Input
|
||||
abstract val additionalCompilerOptions: Collection<String>
|
||||
abstract val additionalCompilerOptions: Provider<Collection<String>>
|
||||
|
||||
@get:Internal
|
||||
val languageSettings: LanguageSettingsBuilder
|
||||
get() = compilation.defaultSourceSet.languageSettings
|
||||
val languageSettings: LanguageSettingsBuilder by lazy {
|
||||
compilation.get().defaultSourceSet.languageSettings
|
||||
}
|
||||
|
||||
@get:Input
|
||||
val progressiveMode: Boolean
|
||||
@@ -170,8 +172,8 @@ abstract class AbstractKotlinNativeCompile<T : KotlinCommonToolOptions> : Abstra
|
||||
// endregion.
|
||||
|
||||
@get:Input
|
||||
val enableEndorsedLibs: Boolean
|
||||
get() = compilation.enableEndorsedLibs
|
||||
val enableEndorsedLibs by
|
||||
project.provider { compilation.map { it.enableEndorsedLibs }.get() }
|
||||
|
||||
val kotlinNativeVersion: String
|
||||
@Input get() = project.konanVersion.toString()
|
||||
@@ -179,11 +181,11 @@ abstract class AbstractKotlinNativeCompile<T : KotlinCommonToolOptions> : Abstra
|
||||
// OutputFile is located under the destinationDir, so there is no need to register it as a separate output.
|
||||
@Internal
|
||||
val outputFile: Provider<File> = project.provider {
|
||||
val konanTarget = compilation.konanTarget
|
||||
val konanTarget = compilation.get().konanTarget
|
||||
|
||||
val prefix = outputKind.prefix(konanTarget)
|
||||
val suffix = outputKind.suffix(konanTarget)
|
||||
val filename = "$prefix$baseName$suffix".let {
|
||||
val filename = "$prefix${baseName}$suffix".let {
|
||||
when {
|
||||
outputKind == FRAMEWORK ->
|
||||
it.asValidFrameworkName()
|
||||
@@ -241,10 +243,10 @@ abstract class AbstractKotlinNativeCompile<T : KotlinCommonToolOptions> : Abstra
|
||||
addKey("-progressive", progressiveMode)
|
||||
|
||||
if (!defaultsOnly) {
|
||||
addAll(additionalCompilerOptions)
|
||||
addAll(additionalCompilerOptions.get())
|
||||
}
|
||||
|
||||
(compilation.defaultSourceSet.languageSettings as? DefaultLanguageSettingsBuilder)?.run {
|
||||
(compilation.get().defaultSourceSet.languageSettings as? DefaultLanguageSettingsBuilder)?.run {
|
||||
addAll(freeCompilerArgs)
|
||||
}
|
||||
}
|
||||
@@ -274,7 +276,7 @@ abstract class AbstractKotlinNativeCompile<T : KotlinCommonToolOptions> : Abstra
|
||||
addArg("-target", target)
|
||||
addArg("-p", outputKind.name.toLowerCase())
|
||||
|
||||
if (compilation is KotlinSharedNativeCompilation) {
|
||||
if (compilation.get() is KotlinSharedNativeCompilation) {
|
||||
add("-Xexpect-actual-linker")
|
||||
add("-Xmetadata-klib")
|
||||
addArg("-manifest", manifestFile.get().absolutePath)
|
||||
@@ -301,7 +303,7 @@ abstract class AbstractKotlinNativeCompile<T : KotlinCommonToolOptions> : Abstra
|
||||
val output = outputFile.get()
|
||||
output.parentFile.mkdirs()
|
||||
|
||||
if (compilation is KotlinSharedNativeCompilation) {
|
||||
if (compilation.get() is KotlinSharedNativeCompilation) {
|
||||
val manifestFile: File = manifestFile.get()
|
||||
manifestFile.ensureParentDirsCreated()
|
||||
val properties = java.util.Properties()
|
||||
@@ -316,9 +318,12 @@ abstract class AbstractKotlinNativeCompile<T : KotlinCommonToolOptions> : Abstra
|
||||
/**
|
||||
* A task producing a klibrary from a compilation.
|
||||
*/
|
||||
open class KotlinNativeCompile : AbstractKotlinNativeCompile<KotlinCommonOptions>(), KotlinCompile<KotlinCommonOptions> {
|
||||
open class KotlinNativeCompile : AbstractKotlinNativeCompile<KotlinCommonOptions, AbstractKotlinNativeCompilation>(),
|
||||
KotlinCompile<KotlinCommonOptions> {
|
||||
@Internal
|
||||
final override lateinit var compilation: AbstractKotlinNativeCompilation
|
||||
@Transient // can't be serialized for Gradle configuration avoidance
|
||||
final override val compilation: Property<AbstractKotlinNativeCompilation> =
|
||||
project.newProperty()
|
||||
|
||||
@get:Input
|
||||
override val outputKind = LIBRARY
|
||||
@@ -330,8 +335,11 @@ open class KotlinNativeCompile : AbstractKotlinNativeCompile<KotlinCommonOptions
|
||||
override val debuggable = true
|
||||
|
||||
@get:Internal
|
||||
override val baseName: String
|
||||
get() = if (compilation.isMain()) project.name else "${project.name}_${compilation.name}"
|
||||
override val baseName: String by
|
||||
compilation.map { if (it.isMain()) project.name else "${project.name}_${it.name}" }
|
||||
|
||||
// Store as an explicit provider in order to allow Gradle Instant Execution to capture the state
|
||||
// private val allSourceProvider = compilation.map { project.files(it.allSources).asFileTree }
|
||||
|
||||
@get:Input
|
||||
val moduleName: String by project.provider {
|
||||
@@ -347,13 +355,21 @@ open class KotlinNativeCompile : AbstractKotlinNativeCompile<KotlinCommonOptions
|
||||
@get:Internal // these sources are normally a subset of `source` ones which are already tracked
|
||||
val commonSources: ConfigurableFileCollection = project.files()
|
||||
|
||||
// private val commonSources: FileCollection by lazy {
|
||||
// // Already taken into account in getSources method.
|
||||
// project.files(compilation.map { it.commonSources }).asFileTree
|
||||
// }
|
||||
|
||||
private val commonSourcesTree: FileTree
|
||||
get() = commonSources.asFileTree
|
||||
|
||||
private val friendModule: FileCollection?
|
||||
get() = project.files(
|
||||
project.provider { compilation.associateWithTransitiveClosure.map { it.output.allOutputs } + compilation.friendArtifacts }
|
||||
|
||||
private val friendModule: FileCollection by compilation.map { compilationInstance ->
|
||||
project.files(
|
||||
compilationInstance.associateWithTransitiveClosure.map { it.output.allOutputs },
|
||||
compilationInstance.friendArtifacts
|
||||
)
|
||||
}
|
||||
// endregion.
|
||||
|
||||
// region Language settings imported from a SourceSet.
|
||||
@@ -372,11 +388,12 @@ open class KotlinNativeCompile : AbstractKotlinNativeCompile<KotlinCommonOptions
|
||||
|
||||
// region Kotlin options.
|
||||
override val kotlinOptions: KotlinCommonOptions
|
||||
get() = compilation.kotlinOptions
|
||||
get() = compilation.get().kotlinOptions
|
||||
|
||||
@get:Input
|
||||
override val additionalCompilerOptions: Collection<String>
|
||||
get() = kotlinOptions.freeCompilerArgs
|
||||
override val additionalCompilerOptions: Provider<Collection<String>> = project.provider {
|
||||
kotlinOptions.freeCompilerArgs
|
||||
}
|
||||
|
||||
override fun kotlinOptions(fn: KotlinCommonOptions.() -> Unit) {
|
||||
kotlinOptions.fn()
|
||||
@@ -409,7 +426,7 @@ open class KotlinNativeCompile : AbstractKotlinNativeCompile<KotlinCommonOptions
|
||||
// Configure FQ module name to avoid cyclic dependencies in klib manifests (see KT-36721).
|
||||
addArg("-module-name", moduleName)
|
||||
add("-Xshort-module-name=$shortModuleName")
|
||||
val friends = friendModule?.files
|
||||
val friends = friendModule.files
|
||||
if (friends != null && friends.isNotEmpty()) {
|
||||
addArg("-friend-modules", friends.map { it.absolutePath }.joinToString(File.pathSeparator))
|
||||
}
|
||||
@@ -427,22 +444,23 @@ open class KotlinNativeCompile : AbstractKotlinNativeCompile<KotlinCommonOptions
|
||||
/**
|
||||
* A task producing a final binary from a compilation.
|
||||
*/
|
||||
open class KotlinNativeLink : AbstractKotlinNativeCompile<KotlinCommonToolOptions>() {
|
||||
open class KotlinNativeLink : AbstractKotlinNativeCompile<KotlinCommonToolOptions, KotlinNativeCompilation>() {
|
||||
|
||||
@get:Internal
|
||||
@Transient // can't be serialized for Gradle configuration avoidance
|
||||
final override val compilation: Property<KotlinNativeCompilation> = project.newProperty() { binary.compilation }
|
||||
|
||||
init {
|
||||
dependsOn(project.provider { compilation.compileKotlinTask })
|
||||
dependsOn(project.provider { compilation.get().compileKotlinTask })
|
||||
}
|
||||
|
||||
@Internal
|
||||
@Transient
|
||||
lateinit var binary: NativeBinary
|
||||
|
||||
@get:Internal
|
||||
override val compilation: KotlinNativeCompilation
|
||||
get() = binary.compilation
|
||||
|
||||
@Internal // Taken into account by getSources().
|
||||
val intermediateLibrary: Provider<File> = project.provider {
|
||||
compilation.compileKotlinTask.outputFile.get()
|
||||
val intermediateLibrary: Provider<File> = compilation.map { compilationInstance ->
|
||||
compilationInstance.compileKotlinTask.outputFile.get()
|
||||
}
|
||||
|
||||
@InputFiles
|
||||
@@ -459,27 +477,23 @@ open class KotlinNativeLink : AbstractKotlinNativeCompile<KotlinCommonToolOption
|
||||
binary.outputDirectory = destinationDir
|
||||
}
|
||||
|
||||
@get:Input
|
||||
override val outputKind: CompilerOutputKind
|
||||
get() = binary.outputKind.compilerOutputKind
|
||||
@Input get() = binary.outputKind.compilerOutputKind
|
||||
|
||||
@get:Input
|
||||
override val optimized: Boolean
|
||||
get() = binary.optimized
|
||||
@Input get() = binary.optimized
|
||||
|
||||
@get:Input
|
||||
override val debuggable: Boolean
|
||||
get() = binary.debuggable
|
||||
@Input get() = binary.debuggable
|
||||
|
||||
@get:Internal
|
||||
override val baseName: String
|
||||
get() = binary.baseName
|
||||
@Input get() = binary.baseName
|
||||
|
||||
@get:Input
|
||||
protected val konanCacheKind: NativeCacheKind
|
||||
get() = project.konanCacheKind
|
||||
|
||||
inner class NativeLinkOptions: KotlinCommonToolOptions {
|
||||
inner class NativeLinkOptions : KotlinCommonToolOptions {
|
||||
override var allWarningsAsErrors: Boolean = false
|
||||
override var suppressWarnings: Boolean = false
|
||||
override var verbose: Boolean = false
|
||||
@@ -488,8 +502,9 @@ open class KotlinNativeLink : AbstractKotlinNativeCompile<KotlinCommonToolOption
|
||||
|
||||
// We propagate compilation free args to the link task for now (see KT-33717).
|
||||
@get:Input
|
||||
override val additionalCompilerOptions: Collection<String>
|
||||
get() = kotlinOptions.freeCompilerArgs + compilation.kotlinOptions.freeCompilerArgs
|
||||
override val additionalCompilerOptions: Provider<Collection<String>> = compilation.map { compilationInstance ->
|
||||
kotlinOptions.freeCompilerArgs + compilationInstance.kotlinOptions.freeCompilerArgs
|
||||
}
|
||||
|
||||
override val kotlinOptions: KotlinCommonToolOptions = NativeLinkOptions()
|
||||
|
||||
@@ -503,18 +518,16 @@ open class KotlinNativeLink : AbstractKotlinNativeCompile<KotlinCommonToolOption
|
||||
}
|
||||
|
||||
// Binary-specific options.
|
||||
@get:Optional
|
||||
@get:Input
|
||||
val entryPoint: String?
|
||||
@Input
|
||||
@Optional
|
||||
get() = (binary as? Executable)?.entryPoint
|
||||
|
||||
@get:Input
|
||||
val linkerOpts: List<String>
|
||||
get() = binary.linkerOpts
|
||||
@Input get() = binary.linkerOpts
|
||||
|
||||
@get:Input
|
||||
val processTests: Boolean
|
||||
get() = binary is TestExecutable
|
||||
@Input get() = binary is TestExecutable
|
||||
|
||||
@get:InputFiles
|
||||
val exportLibraries: FileCollection
|
||||
@@ -527,12 +540,14 @@ open class KotlinNativeLink : AbstractKotlinNativeCompile<KotlinCommonToolOption
|
||||
}
|
||||
|
||||
@get:Input
|
||||
val isStaticFramework: Boolean
|
||||
get() = binary.let { it is Framework && it.isStatic }
|
||||
val isStaticFramework: Boolean by project.provider {
|
||||
binary.let { it is Framework && it.isStatic }
|
||||
}
|
||||
|
||||
@get:Input
|
||||
val embedBitcode: Framework.BitcodeEmbeddingMode
|
||||
get() = (binary as? Framework)?.embedBitcode ?: Framework.BitcodeEmbeddingMode.DISABLE
|
||||
val embedBitcode: Framework.BitcodeEmbeddingMode by project.provider {
|
||||
(binary as? Framework)?.embedBitcode ?: Framework.BitcodeEmbeddingMode.DISABLE
|
||||
}
|
||||
|
||||
override fun buildCompilerArgs(): List<String> = mutableListOf<String>().apply {
|
||||
addAll(super.buildCompilerArgs())
|
||||
@@ -569,9 +584,12 @@ open class KotlinNativeLink : AbstractKotlinNativeCompile<KotlinCommonToolOption
|
||||
override fun buildSourceArgs(): List<String> =
|
||||
listOf("-Xinclude=${intermediateLibrary.get().absolutePath}")
|
||||
|
||||
@get:Internal
|
||||
val apiFilesProvider = compilation.map {project.configurations.getByName(it.apiConfigurationName).files.filterKlibsPassedToCompiler(project)}
|
||||
|
||||
private fun validatedExportedLibraries() {
|
||||
val exportConfiguration = exportLibraries as? Configuration ?: return
|
||||
val apiFiles = project.configurations.getByName(compilation.apiConfigurationName).files.filterKlibsPassedToCompiler(project)
|
||||
val apiFiles = apiFilesProvider.get()
|
||||
|
||||
val failed = mutableSetOf<Dependency>()
|
||||
exportConfiguration.allDependencies.forEach {
|
||||
@@ -765,7 +783,11 @@ internal class CacheBuilder(val project: Project, val binary: NativeBinary) {
|
||||
private val String.cachedName
|
||||
get() = getCacheFileName(this, konanCacheKind)
|
||||
|
||||
private fun ensureCompilerProvidedLibPrecached(platformLibName: String, platformLibs: Map<String, File>, visitedLibs: MutableSet<String>) {
|
||||
private fun ensureCompilerProvidedLibPrecached(
|
||||
platformLibName: String,
|
||||
platformLibs: Map<String, File>,
|
||||
visitedLibs: MutableSet<String>
|
||||
) {
|
||||
if (platformLibName in visitedLibs)
|
||||
return
|
||||
visitedLibs += platformLibName
|
||||
|
||||
+24
-6
@@ -11,6 +11,7 @@ import org.gradle.api.plugins.JavaPluginConvention
|
||||
import org.gradle.api.tasks.*
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinSingleJavaTargetExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
||||
import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast
|
||||
import org.jetbrains.kotlin.gradle.utils.newProperty
|
||||
import java.io.File
|
||||
|
||||
@@ -27,18 +28,35 @@ internal open class InspectClassesForMultiModuleIC : DefaultTask() {
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
@get:OutputFile
|
||||
internal val classesListFile: File by lazy {
|
||||
(project.kotlinExtension as KotlinSingleJavaTargetExtension).target.defaultArtifactClassesListFile
|
||||
(project.kotlinExtension as KotlinSingleJavaTargetExtension).target.defaultArtifactClassesListFile.get()
|
||||
}
|
||||
|
||||
@get:InputFiles
|
||||
internal val sourceSetOutputClassesDir by lazy {
|
||||
project.convention.findPlugin(JavaPluginConvention::class.java)?.sourceSets?.findByName(sourceSetName)?.output?.classesDirs
|
||||
}
|
||||
|
||||
@get:Internal
|
||||
internal val fileTrees
|
||||
get() = sourceSetOutputClassesDir?.map {
|
||||
if (isGradleVersionAtLeast(6, 0)) {
|
||||
objects.fileTree().from(it).include("**/*.class")
|
||||
} else {
|
||||
project.fileTree(it).include("**/*.class")
|
||||
}
|
||||
}
|
||||
|
||||
@get:Internal
|
||||
internal val objects = project.objects
|
||||
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
@get:InputFiles
|
||||
internal val classFiles: FileCollection
|
||||
get() {
|
||||
val convention = project.convention.findPlugin(JavaPluginConvention::class.java)
|
||||
val sourceSet = convention?.sourceSets?.findByName(sourceSetName) ?: return project.files()
|
||||
|
||||
val fileTrees = sourceSet.output.classesDirs.map { project.fileTree(it).include("**/*.class") }
|
||||
return project.files(fileTrees)
|
||||
if (sourceSetOutputClassesDir != null) {
|
||||
return objects.fileCollection().from(fileTrees)
|
||||
}
|
||||
return objects.fileCollection()
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ open class KotlinCompileCommon : AbstractKotlinCompile<K2MetadataCompilerArgumen
|
||||
override fun callCompilerAsync(args: K2MetadataCompilerArguments, sourceRoots: SourceRoots, changedFiles: ChangedFiles) {
|
||||
val messageCollector = GradlePrintingMessageCollector(logger, args.allWarningsAsErrors)
|
||||
val outputItemCollector = OutputItemsCollectorImpl()
|
||||
val compilerRunner = compilerRunner()
|
||||
val compilerRunner = compilerRunner
|
||||
val environment = GradleCompilerEnvironment(
|
||||
computedCompilerClasspath, messageCollector, outputItemCollector,
|
||||
buildReportMode = buildReportMode,
|
||||
|
||||
+154
-63
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle.tasks
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.api.tasks.compile.AbstractCompile
|
||||
@@ -20,6 +21,7 @@ import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||
import org.jetbrains.kotlin.compilerRunner.*
|
||||
import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner.Companion.normalizeForFlagFile
|
||||
import org.jetbrains.kotlin.daemon.common.MultiModuleICSettings
|
||||
import org.jetbrains.kotlin.gradle.dsl.*
|
||||
import org.jetbrains.kotlin.gradle.incremental.ChangedFiles
|
||||
@@ -35,8 +37,12 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinCompilation
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.associateWithTransitiveClosure
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.ownModuleName
|
||||
import org.jetbrains.kotlin.gradle.report.BuildReportMode
|
||||
import org.jetbrains.kotlin.gradle.utils.*
|
||||
import org.jetbrains.kotlin.gradle.utils.getValue
|
||||
import org.jetbrains.kotlin.gradle.utils.isParentOf
|
||||
import org.jetbrains.kotlin.gradle.utils.pathsAsStringRelativeTo
|
||||
import org.jetbrains.kotlin.gradle.utils.toSortedPathsArray
|
||||
import org.jetbrains.kotlin.incremental.ChangedFiles
|
||||
import org.jetbrains.kotlin.incremental.IncrementalModuleInfo
|
||||
import org.jetbrains.kotlin.library.impl.isKotlinLibrary
|
||||
import org.jetbrains.kotlin.utils.JsLibraryUtils
|
||||
import java.io.File
|
||||
@@ -87,7 +93,7 @@ abstract class AbstractKotlinCompileTool<T : CommonToolArguments>
|
||||
|
||||
@get:Classpath
|
||||
@get:InputFiles
|
||||
internal val computedCompilerClasspath: List<File> by project.provider {
|
||||
internal val computedCompilerClasspath: List<File> by lazy {
|
||||
compilerClasspath?.takeIf { it.isNotEmpty() }
|
||||
?: compilerJarFile?.let {
|
||||
// a hack to remove compiler jar from the cp, will be dropped when compilerJarFile will be removed
|
||||
@@ -113,19 +119,51 @@ abstract class AbstractKotlinCompileTool<T : CommonToolArguments>
|
||||
protected abstract fun findKotlinCompilerClasspath(project: Project): List<File>
|
||||
}
|
||||
|
||||
public class GradleCompileTaskProvider {
|
||||
|
||||
constructor(task: Task) {
|
||||
buildDir = task.project.buildDir
|
||||
projectDir = task.project.rootProject.projectDir
|
||||
rootDir = task.project.rootProject.rootDir
|
||||
sessionsDir = GradleCompilerRunner.sessionsDir(task.project)
|
||||
projectName = task.project.rootProject.name.normalizeForFlagFile()
|
||||
buildModulesInfo = GradleCompilerRunner.buildModulesInfo(task.project.gradle)
|
||||
path = task.path
|
||||
logger = task.logger
|
||||
|
||||
}
|
||||
|
||||
val path: String
|
||||
val logger: Logger
|
||||
val buildDir: File /*= project.buildDir*/
|
||||
val projectDir: File /*= project.rootProject.projectDir*/
|
||||
val rootDir: File /*= project.rootProject.rootDir*/
|
||||
val sessionsDir: File/* = GradleCompilerRunner.sessionsDir(project)*/
|
||||
val projectName: String /*= project.rootProject.name.normalizeForFlagFile()*/
|
||||
val buildModulesInfo: IncrementalModuleInfo /*= GradleCompilerRunner.buildModulesInfo(project.gradle)*/
|
||||
}
|
||||
|
||||
abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKotlinCompileTool<T>() {
|
||||
|
||||
init {
|
||||
cacheOnlyIfEnabledForKotlin()
|
||||
}
|
||||
|
||||
@get:Internal
|
||||
private val layout = project.layout
|
||||
|
||||
// avoid creating directory in getter: this can lead to failure in parallel build
|
||||
@get:LocalState
|
||||
internal val taskBuildDirectory: File by project.provider {
|
||||
File(File(project.buildDir, KOTLIN_BUILD_DIR_NAME), name)
|
||||
}
|
||||
internal val taskBuildDirectory: File by layout.buildDirectory.dir(KOTLIN_BUILD_DIR_NAME).map { it.file(name).asFile }
|
||||
|
||||
override fun localStateDirectories(): FileCollection = project.files(taskBuildDirectory)
|
||||
|
||||
@get:Internal
|
||||
internal val projectObjects = project.objects
|
||||
|
||||
@get:LocalState
|
||||
internal val localStateDirectoriesProvider: FileCollection = projectObjects.fileCollection().from(taskBuildDirectory)
|
||||
|
||||
override fun localStateDirectories(): FileCollection = localStateDirectoriesProvider
|
||||
|
||||
// indicates that task should compile kotlin incrementally if possible
|
||||
// it's not possible when IncrementalTaskInputs#isIncremental returns false (i.e first build)
|
||||
@@ -147,9 +185,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
|
||||
internal var buildReportMode: BuildReportMode? = null
|
||||
|
||||
@get:Internal
|
||||
internal val taskData: KotlinCompileTaskData by project.provider {
|
||||
KotlinCompileTaskData.get(project, name)
|
||||
}
|
||||
internal val taskData: KotlinCompileTaskData = KotlinCompileTaskData.get(project, name)
|
||||
|
||||
@get:Input
|
||||
internal open var useModuleDetection: Boolean
|
||||
@@ -162,11 +198,9 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
|
||||
protected val multiModuleICSettings: MultiModuleICSettings
|
||||
get() = MultiModuleICSettings(taskData.buildHistoryFile, useModuleDetection)
|
||||
|
||||
@get:Classpath
|
||||
@get:InputFiles
|
||||
val pluginClasspath: FileCollection by project.provider {
|
||||
project.configurations.getByName(PLUGIN_CLASSPATH_CONFIGURATION_NAME)
|
||||
}
|
||||
@get:Classpath
|
||||
val pluginClasspath: FileCollection = project.configurations.getByName(PLUGIN_CLASSPATH_CONFIGURATION_NAME)
|
||||
|
||||
@get:Internal
|
||||
internal val pluginOptions = CompilerPluginOptions()
|
||||
@@ -175,10 +209,13 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
|
||||
@get:InputFiles
|
||||
protected val additionalClasspath = arrayListOf<File>()
|
||||
|
||||
@get:Internal
|
||||
internal val objects = project.objects
|
||||
|
||||
// Store this file collection before it is filtered by File::exists to ensure that Gradle Instant execution doesn't serialize the
|
||||
// filtered files, losing those that don't exist yet and will only be created during build
|
||||
private val compileClasspathImpl by project.provider {
|
||||
classpath + project.files(additionalClasspath)
|
||||
classpath + objects.fileCollection().from(additionalClasspath)
|
||||
}
|
||||
|
||||
@get:Internal // classpath already participates in the checks
|
||||
@@ -197,8 +234,9 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
|
||||
sourceFilesExtensionsSources.add(extensions)
|
||||
}
|
||||
|
||||
private val kotlinExt: KotlinProjectExtension
|
||||
get() = project.extensions.findByType(KotlinProjectExtension::class.java)!!
|
||||
@get:Internal
|
||||
@field:Transient
|
||||
internal val kotlinExtProvider: KotlinProjectExtension = project.extensions.findByType(KotlinProjectExtension::class.java)!!
|
||||
|
||||
override fun getDestinationDir(): File =
|
||||
taskData.destinationDir.get()
|
||||
@@ -218,13 +256,13 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
|
||||
@get:Internal
|
||||
internal var coroutinesFromGradleProperties: Coroutines? = null
|
||||
// Input is needed to force rebuild even if source files are not changed
|
||||
@get:Input
|
||||
internal val coroutinesStr: String
|
||||
get() = coroutines.name
|
||||
|
||||
@get:Internal
|
||||
internal val coroutines: Coroutines by project.provider {
|
||||
kotlinExt.experimental.coroutines
|
||||
@get:Input
|
||||
internal val coroutinesStr: Provider<String> = project.provider {coroutines.get().name}
|
||||
|
||||
@get:Input
|
||||
internal val coroutines: Provider<Coroutines> = project.provider {
|
||||
kotlinExtProvider.experimental.coroutines
|
||||
?: coroutinesFromGradleProperties
|
||||
?: Coroutines.DEFAULT
|
||||
}
|
||||
@@ -242,7 +280,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
|
||||
|
||||
@get:InputFiles
|
||||
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||
internal var commonSourceSet: FileCollection = project.files()
|
||||
internal var commonSourceSet: FileCollection = project.files() //TODO
|
||||
|
||||
@get:Input
|
||||
internal val moduleName: String by project.provider {
|
||||
@@ -262,8 +300,10 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
|
||||
|
||||
private val kotlinLogger by lazy { GradleKotlinLogger(logger) }
|
||||
|
||||
internal open fun compilerRunner(): GradleCompilerRunner =
|
||||
GradleCompilerRunner(this)
|
||||
@get:Internal
|
||||
internal val compilerRunner by lazy { compilerRunner() }
|
||||
|
||||
internal open fun compilerRunner(): GradleCompilerRunner = GradleCompilerRunner(GradleCompileTaskProvider(this))
|
||||
|
||||
@TaskAction
|
||||
fun execute(inputs: IncrementalTaskInputs) {
|
||||
@@ -297,6 +337,9 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
|
||||
return !inputs.isIncremental && getSourceRoots().kotlinSourceFiles.isEmpty()
|
||||
}
|
||||
|
||||
@get:Internal
|
||||
private val projectDir = project.rootProject.projectDir
|
||||
|
||||
private fun executeImpl(inputs: IncrementalTaskInputs) {
|
||||
// Check that the JDK tools are available in Gradle (fail-fast, instead of a fail during the compiler run):
|
||||
findToolsJar()
|
||||
@@ -304,7 +347,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
|
||||
val sourceRoots = getSourceRoots()
|
||||
val allKotlinSources = sourceRoots.kotlinSourceFiles
|
||||
|
||||
logger.kotlinDebug { "All kotlin sources: ${allKotlinSources.pathsAsStringRelativeTo(project.rootProject.projectDir)}" }
|
||||
logger.kotlinDebug { "All kotlin sources: ${allKotlinSources.pathsAsStringRelativeTo(projectDir)}" }
|
||||
|
||||
if (skipCondition(inputs)) {
|
||||
// Skip running only if non-incremental run. Otherwise, we may need to do some cleanup.
|
||||
@@ -327,13 +370,14 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
|
||||
*/
|
||||
internal abstract fun callCompilerAsync(args: T, sourceRoots: SourceRoots, changedFiles: ChangedFiles)
|
||||
|
||||
@get:Input
|
||||
internal val isMultiplatform: Boolean by lazy { project.plugins.any { it is KotlinPlatformPluginBase || it is KotlinMultiplatformPluginWrapper } }
|
||||
|
||||
@get:Internal
|
||||
internal val isMultiplatform: Boolean by project.provider {
|
||||
project.plugins.any { it is KotlinPlatformPluginBase || it is KotlinMultiplatformPluginWrapper }
|
||||
}
|
||||
internal val abstractKotlinCompileArgumentsContributor by lazy { AbstractKotlinCompileArgumentsContributor(KotlinCompileArgumentsProvider(this)) }
|
||||
|
||||
override fun setupCompilerArgs(args: T, defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) {
|
||||
AbstractKotlinCompileArgumentsContributor(thisTaskProvider).contributeArguments(
|
||||
abstractKotlinCompileArgumentsContributor.contributeArguments(
|
||||
args,
|
||||
compilerArgumentsConfigurationFlags(defaultsOnly, ignoreClasspathResolutionErrors)
|
||||
)
|
||||
@@ -350,6 +394,45 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
|
||||
}
|
||||
}
|
||||
|
||||
open class KotlinCompileArgumentsProvider<T : AbstractKotlinCompile<out CommonCompilerArguments>>(taskProvider: T) {
|
||||
|
||||
val coroutines: Provider<Coroutines>
|
||||
val logger: Logger
|
||||
val isMultiplatform: Boolean
|
||||
val pluginClasspath: FileCollection
|
||||
val pluginOptions: CompilerPluginOptions
|
||||
|
||||
init {
|
||||
coroutines = taskProvider.coroutines
|
||||
logger = taskProvider.logger
|
||||
isMultiplatform = taskProvider.isMultiplatform
|
||||
pluginClasspath = taskProvider.pluginClasspath
|
||||
pluginOptions = taskProvider.pluginOptions
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinJvmCompilerArgumentsProvider
|
||||
(taskProvider: KotlinCompile) : KotlinCompileArgumentsProvider<KotlinCompile>(taskProvider) {
|
||||
|
||||
val moduleName: String
|
||||
val friendPaths: Array<String>
|
||||
val compileClasspath: Iterable<File>
|
||||
val destinationDir: File
|
||||
internal val kotlinOptions: List<KotlinJvmOptionsImpl?>
|
||||
|
||||
init {
|
||||
// super(taskProvider)
|
||||
moduleName = taskProvider.moduleName
|
||||
friendPaths = taskProvider.friendPaths
|
||||
compileClasspath = taskProvider.compileClasspath
|
||||
destinationDir = taskProvider.destinationDir
|
||||
kotlinOptions = listOfNotNull(
|
||||
taskProvider.parentKotlinOptionsImpl as KotlinJvmOptionsImpl?,
|
||||
taskProvider.kotlinOptions as KotlinJvmOptionsImpl
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal inline val <reified T : Task> T.thisTaskProvider: TaskProvider<out T>
|
||||
get() = checkNotNull(project.locateTask<T>(name))
|
||||
|
||||
@@ -397,8 +480,8 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
|
||||
}
|
||||
|
||||
@get:Internal
|
||||
internal val compilerArgumentsContributor: CompilerArgumentsContributor<K2JVMCompilerArguments> by project.provider {
|
||||
KotlinJvmCompilerArgumentsContributor(thisTaskProvider)
|
||||
internal val compilerArgumentsContributor: CompilerArgumentsContributor<K2JVMCompilerArguments> by lazy {
|
||||
KotlinJvmCompilerArgumentsContributor(KotlinJvmCompilerArgumentsProvider(this))
|
||||
}
|
||||
|
||||
@Internal
|
||||
@@ -409,7 +492,7 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
|
||||
|
||||
val messageCollector = GradlePrintingMessageCollector(logger, args.allWarningsAsErrors)
|
||||
val outputItemCollector = OutputItemsCollectorImpl()
|
||||
val compilerRunner = compilerRunner()
|
||||
val compilerRunner = compilerRunner
|
||||
|
||||
val icEnv = if (isIncrementalCompilationEnabled()) {
|
||||
logger.info(USING_JVM_INCREMENTAL_COMPILATION_MESSAGE)
|
||||
@@ -417,7 +500,7 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
|
||||
if (hasFilesInTaskBuildDirectory()) changedFiles else ChangedFiles.Unknown(),
|
||||
taskBuildDirectory,
|
||||
usePreciseJavaTracking = usePreciseJavaTracking,
|
||||
disableMultiModuleIC = disableMultiModuleIC(),
|
||||
disableMultiModuleIC = disableMultiModuleIC,
|
||||
multiModuleICSettings = multiModuleICSettings
|
||||
)
|
||||
} else null
|
||||
@@ -439,31 +522,32 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
|
||||
)
|
||||
}
|
||||
|
||||
private fun disableMultiModuleIC(): Boolean {
|
||||
if (!isIncrementalCompilationEnabled() || javaOutputDir == null) return false
|
||||
@get:Input
|
||||
val disableMultiModuleIC: Boolean by lazy {
|
||||
if (!isIncrementalCompilationEnabled() || javaOutputDir == null) {
|
||||
false
|
||||
} else {
|
||||
|
||||
var illegalTaskOrNull: AbstractCompile? = null
|
||||
|
||||
project.tasks.configureEach {
|
||||
if (it is AbstractCompile &&
|
||||
it !is JavaCompile &&
|
||||
it !is AbstractKotlinCompile<*> &&
|
||||
javaOutputDir!!.isParentOf(it.destinationDir)
|
||||
) {
|
||||
illegalTaskOrNull = illegalTaskOrNull ?: it
|
||||
var illegalTaskOrNull: AbstractCompile? = null
|
||||
project.tasks.configureEach {
|
||||
if (it is AbstractCompile &&
|
||||
it !is JavaCompile &&
|
||||
it !is AbstractKotlinCompile<*> &&
|
||||
javaOutputDir!!.isParentOf(it.destinationDir)
|
||||
) {
|
||||
illegalTaskOrNull = illegalTaskOrNull ?: it
|
||||
}
|
||||
}
|
||||
if (illegalTaskOrNull != null) {
|
||||
val illegalTask = illegalTaskOrNull!!
|
||||
logger.info(
|
||||
"Kotlin inter-project IC is disabled: " +
|
||||
"unknown task '$illegalTask' destination dir ${illegalTask.destinationDir} " +
|
||||
"intersects with java destination dir $javaOutputDir"
|
||||
)
|
||||
}
|
||||
illegalTaskOrNull != null
|
||||
}
|
||||
|
||||
illegalTaskOrNull?.let { illegalTask ->
|
||||
logger.info(
|
||||
"Kotlin inter-project IC is disabled: " +
|
||||
"unknown task '$illegalTask' destination dir ${illegalTask.destinationDir} " +
|
||||
"intersects with java destination dir $javaOutputDir"
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// override setSource to track source directory sets and files (for generated android folders)
|
||||
@@ -483,21 +567,26 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
|
||||
internal open class KotlinCompileWithWorkers @Inject constructor(
|
||||
private val workerExecutor: WorkerExecutor
|
||||
) : KotlinCompile() {
|
||||
override fun compilerRunner() = GradleCompilerRunnerWithWorkers(this, workerExecutor)
|
||||
|
||||
@get:Internal
|
||||
val compilerRunnerValue = GradleCompilerRunnerWithWorkers(GradleCompileTaskProvider(this), workerExecutor)
|
||||
|
||||
override fun compilerRunner() = compilerRunnerValue
|
||||
}
|
||||
|
||||
@CacheableTask
|
||||
internal open class Kotlin2JsCompileWithWorkers @Inject constructor(
|
||||
private val workerExecutor: WorkerExecutor
|
||||
) : Kotlin2JsCompile() {
|
||||
override fun compilerRunner() = GradleCompilerRunnerWithWorkers(this, workerExecutor)
|
||||
|
||||
override fun compilerRunner() = GradleCompilerRunnerWithWorkers(GradleCompileTaskProvider(this), workerExecutor)
|
||||
}
|
||||
|
||||
@CacheableTask
|
||||
internal open class KotlinCompileCommonWithWorkers @Inject constructor(
|
||||
private val workerExecutor: WorkerExecutor
|
||||
) : KotlinCompileCommon() {
|
||||
override fun compilerRunner() = GradleCompilerRunnerWithWorkers(this, workerExecutor)
|
||||
override fun compilerRunner() = GradleCompilerRunnerWithWorkers(GradleCompileTaskProvider(this), workerExecutor)
|
||||
}
|
||||
|
||||
@CacheableTask
|
||||
@@ -507,8 +596,7 @@ open class Kotlin2JsCompile : AbstractKotlinCompile<K2JSCompilerArguments>(), Ko
|
||||
incremental = true
|
||||
}
|
||||
|
||||
override val kotlinOptions: KotlinJsOptions
|
||||
get() = taskData.compilation.kotlinOptions as KotlinJsOptions
|
||||
override val kotlinOptions = taskData.compilation.kotlinOptions as KotlinJsOptions
|
||||
|
||||
@get:Internal
|
||||
protected val defaultOutputFile: File
|
||||
@@ -601,6 +689,9 @@ open class Kotlin2JsCompile : AbstractKotlinCompile<K2JSCompilerArguments>(), Ko
|
||||
JsLibraryUtils::isKotlinJavascriptLibrary
|
||||
}
|
||||
|
||||
@get:Internal
|
||||
internal val absolutePathProvider = project.projectDir.absolutePath
|
||||
|
||||
override fun callCompilerAsync(args: K2JSCompilerArguments, sourceRoots: SourceRoots, changedFiles: ChangedFiles) {
|
||||
sourceRoots as SourceRoots.KotlinOnly
|
||||
|
||||
@@ -624,14 +715,14 @@ open class Kotlin2JsCompile : AbstractKotlinCompile<K2JSCompilerArguments>(), Ko
|
||||
args.friendModules = friendDependencies.joinToString(File.pathSeparator)
|
||||
|
||||
if (args.sourceMapBaseDirs == null && !args.sourceMapPrefix.isNullOrEmpty()) {
|
||||
args.sourceMapBaseDirs = project.projectDir.absolutePath
|
||||
args.sourceMapBaseDirs = absolutePathProvider
|
||||
}
|
||||
|
||||
logger.kotlinDebug("compiling with args ${ArgumentUtils.convertArgumentsToStringList(args)}")
|
||||
|
||||
val messageCollector = GradlePrintingMessageCollector(logger, args.allWarningsAsErrors)
|
||||
val outputItemCollector = OutputItemsCollectorImpl()
|
||||
val compilerRunner = compilerRunner()
|
||||
val compilerRunner = compilerRunner
|
||||
|
||||
val icEnv = if (isIncrementalCompilationEnabled()) {
|
||||
logger.info(USING_JS_INCREMENTAL_COMPILATION_MESSAGE)
|
||||
|
||||
+10
-1
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.utils
|
||||
|
||||
import org.gradle.api.invocation.Gradle
|
||||
import org.gradle.util.GradleVersion
|
||||
|
||||
internal data class ParsedGradleVersion(val major: Int, val minor: Int) : Comparable<ParsedGradleVersion> {
|
||||
@@ -56,4 +57,12 @@ internal data class ParsedGradleVersion(val major: Int, val minor: Int) : Compar
|
||||
|
||||
fun isGradleVersionAtLeast(major: Int, minor: Int) =
|
||||
ParsedGradleVersion.parse(GradleVersion.current().version)
|
||||
?.let { it >= ParsedGradleVersion(major, minor) } ?: false
|
||||
?.let { it >= ParsedGradleVersion(major, minor) } ?: false
|
||||
|
||||
fun isConfigurationCacheAvailable(gradle: Gradle) =
|
||||
try {
|
||||
val startParameters = gradle.startParameter
|
||||
startParameters.javaClass.getMethod("isConfigurationCache").invoke(startParameters) as? Boolean
|
||||
} catch (_: Exception) {
|
||||
null
|
||||
} ?: false
|
||||
|
||||
+7
-9
@@ -6,7 +6,6 @@
|
||||
package org.jetbrains.kotlin.gradle.utils
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.RegularFile
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
@@ -20,14 +19,6 @@ internal operator fun <T> Property<T>.setValue(thisRef: Any?, property: KPropert
|
||||
set(value)
|
||||
}
|
||||
|
||||
internal fun <T : Any> Project.newProperty(initialize: (() -> T)? = null): Property<T> =
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
// use Any and not T::class to allow using lists and maps as the property type, which is otherwise not allowed
|
||||
(project.objects.property(Any::class.java) as Property<T>).apply {
|
||||
if (initialize != null)
|
||||
set(provider(initialize))
|
||||
}
|
||||
|
||||
private class OptionalProviderDelegate<T>(private val provider: Provider<T?>) : ReadOnlyProperty<Any?, T?> {
|
||||
override fun getValue(thisRef: Any?, property: KProperty<*>): T? =
|
||||
if (provider.isPresent)
|
||||
@@ -38,6 +29,13 @@ private class OptionalProviderDelegate<T>(private val provider: Provider<T?>) :
|
||||
internal fun <T> Project.optionalProvider(initialize: () -> T?): ReadOnlyProperty<Any?, T?> =
|
||||
OptionalProviderDelegate(provider(initialize))
|
||||
|
||||
internal fun <T : Any> Project.newProperty(initialize: (() -> T)? = null): Property<T> =
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
(project.objects.property(Any::class.java) as Property<T>).apply {
|
||||
if (initialize != null)
|
||||
set(provider(initialize))
|
||||
}
|
||||
|
||||
// Before 5.0 fileProperty is created via ProjectLayout
|
||||
// https://docs.gradle.org/current/javadoc/org/gradle/api/model/ObjectFactory.html#fileProperty--
|
||||
internal fun Project.newFileProperty(initialize: (() -> File)? = null): RegularFileProperty {
|
||||
|
||||
Reference in New Issue
Block a user