From f9acc0ab8888baee410647d78b115475e86b423b Mon Sep 17 00:00:00 2001 From: Sergey Igushkin Date: Mon, 13 Jan 2020 20:09:21 +0300 Subject: [PATCH] Support Gradle instant execution for Kapt tasks * In the Kotlin/JVM tasks, move the compiler arguments setup logic to a separate class, so that it can be reused by the Kapt tasks without directly referencing the Kotlin/JVM tasks * In the Kapt tasks, carefully capture the values using the Provider API so that the task can be serialized for Instant Execution and then deserialized and executed without relying on the project model Issue #KT-35181 Fixed --- .../kotlin/gradle/InstantExecutionIT.kt | 51 +++++-- .../kotlin/gradle/util/AGPVersion.kt | 2 +- .../internal/CompilerArgumentsContributor.kt | 126 ++++++++++++++++++ .../internal/kapt/KaptGenerateStubsTask.kt | 31 +++-- .../kotlin/gradle/internal/kapt/KaptTask.kt | 38 ++++-- .../internal/kapt/KaptWithKotlincTask.kt | 20 ++- .../internal/kapt/KaptWithoutKotlincTask.kt | 8 +- .../jetbrains/kotlin/gradle/tasks/Tasks.kt | 71 ++++------ .../kotlin/gradle/utils/providerApiUtils.kt | 13 +- 9 files changed, 268 insertions(+), 92 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/CompilerArgumentsContributor.kt diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/InstantExecutionIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/InstantExecutionIT.kt index 45f5ed97917..414f1414d03 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/InstantExecutionIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/InstantExecutionIT.kt @@ -15,7 +15,7 @@ import kotlin.test.fail class InstantExecutionIT : BaseGradleIT() { private val androidGradlePluginVersion: AGPVersion - get() = AGPVersion.v4_0_ALPHA_1 + get() = AGPVersion.v4_0_ALPHA_8 override fun defaultBuildOptions() = super.defaultBuildOptions().copy( @@ -23,7 +23,7 @@ class InstantExecutionIT : BaseGradleIT() { androidGradlePluginVersion = androidGradlePluginVersion ) - private val minimumGradleVersion = GradleVersionRequired.AtLeast("6.1-milestone-1") + private val minimumGradleVersion = GradleVersionRequired.AtLeast("6.1-rc-3") @Test fun testSimpleKotlinJvmProject() = with(Project("kotlinProject", minimumGradleVersion)) { @@ -31,14 +31,37 @@ class InstantExecutionIT : BaseGradleIT() { } @Test - fun testSimpleKotlinAndroidProject() = with(Project("AndroidProject", minimumGradleVersion)) { - applyAndroidAndroid40Alpha4KotlinVersionWorkaround() - testInstantExecutionOf(":Lib:compileFlavor1DebugKotlin", ":Android:compileFlavor1DebugKotlin") + 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") } - private fun Project.testInstantExecutionOf(vararg taskNames: String) { + @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) { + instantExecutionOf(*taskNames, buildOptions = buildOptions) { assertSuccessful() assertTasksExecuted(*taskNames) checkInstantExecutionSucceeded() @@ -49,12 +72,12 @@ class InstantExecutionIT : BaseGradleIT() { } // Then run a build where tasks states are deserialized to check that they work correctly in this mode - instantExecutionOf(*taskNames) { + instantExecutionOf(*taskNames, buildOptions = buildOptions) { assertSuccessful() assertTasksExecuted(*taskNames) } - instantExecutionOf(*taskNames) { + instantExecutionOf(*taskNames, buildOptions = buildOptions) { assertSuccessful() assertTasksUpToDate(*taskNames) } @@ -66,8 +89,12 @@ class InstantExecutionIT : BaseGradleIT() { } } - private fun Project.instantExecutionOf(vararg tasks: String, check: CompiledProject.() -> Unit) = - build("-Dorg.gradle.unsafe.instant-execution=true", *tasks, check = check) + 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 @@ -98,7 +125,7 @@ class InstantExecutionIT : BaseGradleIT() { * 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.applyAndroidAndroid40Alpha4KotlinVersionWorkaround() { + private fun Project.applyAndroid40Alpha4KotlinVersionWorkaround() { setupWorkingDir() val resolutionStrategyHack = """ diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/util/AGPVersion.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/util/AGPVersion.kt index 8d0a8bc5b16..34595cbbd82 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/util/AGPVersion.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/util/AGPVersion.kt @@ -22,6 +22,6 @@ class AGPVersion private constructor(private val versionNumber: VersionNumber) { val v3_1_0 = fromString("3.1.0") val v3_2_0 = fromString("3.2.0") val v3_3_2 = fromString("3.3.2") - val v4_0_ALPHA_1 = fromString("4.0.0-alpha01") + val v4_0_ALPHA_8 = fromString("4.0.0-alpha08") } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/CompilerArgumentsContributor.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/CompilerArgumentsContributor.kt new file mode 100644 index 00000000000..fcb398a1b70 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/CompilerArgumentsContributor.kt @@ -0,0 +1,126 @@ +/* + * 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.internal + +import org.gradle.api.tasks.TaskProvider +import org.jetbrains.kotlin.cli.common.arguments.* +import org.jetbrains.kotlin.gradle.dsl.* +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.utils.toSortedPathsArray +import org.jetbrains.kotlin.incremental.classpathAsList +import org.jetbrains.kotlin.incremental.destinationAsFile + +internal interface CompilerArgumentsContributor { + fun contributeArguments( + args: T, + flags: Collection + ) +} + +internal interface CompilerArgumentsConfigurationFlag + +internal object DefaultsOnly : CompilerArgumentsConfigurationFlag +internal object IgnoreClasspathResolutionErrors : CompilerArgumentsConfigurationFlag + +internal fun compilerArgumentsConfigurationFlags(defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) = + mutableSetOf().apply { + if (defaultsOnly) add(DefaultsOnly) + if (ignoreClasspathResolutionErrors) add(IgnoreClasspathResolutionErrors) + } + +/** The primary purpose of this class is to encapsulate compiler arguments setup done by the AbstractKotlinCompiler tasks, + * but outside the tasks, so that this state & logic can be reused without referencing the task directly. */ +internal open class AbstractKotlinCompileArgumentsContributor( + // Don't save this reference into a property! That would be hostile to Gradle instant execution + taskProvider: TaskProvider> +) : CompilerArgumentsContributor { + 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 } + + override fun contributeArguments( + args: T, + flags: Collection + ) { + args.coroutinesState = when (coroutines) { + Coroutines.ENABLE -> CommonCompilerArguments.ENABLE + Coroutines.WARN -> CommonCompilerArguments.WARN + Coroutines.ERROR -> CommonCompilerArguments.ERROR + Coroutines.DEFAULT -> CommonCompilerArguments.DEFAULT + } + + logger.kotlinDebug { "args.coroutinesState=${args.coroutinesState}" } + + if (logger.isDebugEnabled) { + args.verbose = true + } + + args.multiPlatform = isMultiplatform + + setupPlugins(args) + } + + internal fun setupPlugins(compilerArgs: T) { + compilerArgs.pluginClasspaths = pluginClasspath.toSortedPathsArray() + compilerArgs.pluginOptions = pluginOptions.arguments.toTypedArray() + } +} + +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 +) : AbstractKotlinCompileArgumentsContributor(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 + ) + } + + override fun contributeArguments( + args: K2JVMCompilerArguments, + flags: Collection + ) { + args.fillDefaultValues() + + super.contributeArguments(args, flags) + + args.moduleName = moduleName + logger.kotlinDebug { "args.moduleName = ${args.moduleName}" } + + args.friendPaths = friendPaths + logger.kotlinDebug { "args.friendPaths = ${args.friendPaths?.joinToString() ?: "[]"}" } + + if (DefaultsOnly in flags) return + + args.allowNoSourceFiles = true + args.classpathAsList = try { + compileClasspath.toList().filter { it.exists() } + } catch (e: Exception) { + if (IgnoreClasspathResolutionErrors in flags) emptyList() else throw(e) + } + args.destinationAsFile = destinationDir + + kotlinOptions.forEach { it.updateArguments(args) } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt index f9998cc368e..6c5aae04cac 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt @@ -19,15 +19,12 @@ package org.jetbrains.kotlin.gradle.internal import org.gradle.api.artifacts.Configuration import org.gradle.api.file.FileCollection import org.gradle.api.tasks.* -import org.gradle.api.tasks.incremental.IncrementalTaskInputs import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments -import org.jetbrains.kotlin.gradle.incremental.ChangedFiles -import org.jetbrains.kotlin.gradle.logging.kotlinDebug import org.jetbrains.kotlin.gradle.tasks.FilteringSourceRootsContainer import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.SourceRoots +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.incremental.classpathAsList import org.jetbrains.kotlin.incremental.destinationAsFile import java.io.File @@ -37,6 +34,7 @@ open class KaptGenerateStubsTask : KotlinCompile() { override val sourceRootsContainer = FilteringSourceRootsContainer(emptyList(), { isSourceRootAllowed(it) }) @get:Internal + @field:Transient // can't serialize task references in Gradle instant execution state internal lateinit var kotlinCompileTask: KotlinCompile @get:OutputDirectory @@ -48,7 +46,7 @@ open class KaptGenerateStubsTask : KotlinCompile() { @get:Classpath @get:InputFiles val kaptClasspath: FileCollection - get() = project.files(*kaptClasspathConfigurations.toTypedArray()) + get() = project.files(kaptClasspathConfigurations) @get:Internal internal lateinit var kaptClasspathConfigurations: List @@ -56,8 +54,9 @@ open class KaptGenerateStubsTask : KotlinCompile() { @get:Classpath @get:InputFiles @Suppress("unused") - internal val kotlinTaskPluginClasspath - get() = kotlinCompileTask.pluginClasspath + internal val kotlinTaskPluginClasspath by project.provider { + kotlinCompileTask.pluginClasspath + } @get:Input override var useModuleDetection: Boolean @@ -66,11 +65,11 @@ open class KaptGenerateStubsTask : KotlinCompile() { error("KaptGenerateStubsTask.useModuleDetection setter should not be called!") } - override fun source(vararg sources: Any?): SourceTask? { + override fun source(vararg sources: Any): SourceTask { return super.source(sourceRootsContainer.add(sources)) } - override fun setSource(sources: Any?) { + override fun setSource(sources: Any) { super.setSource(sourceRootsContainer.set(sources)) } @@ -79,8 +78,15 @@ open class KaptGenerateStubsTask : KotlinCompile() { !stubsDir.isParentOf(source) && !generatedSourcesDir.isParentOf(source) + private val compileKotlinArgumentsContributor by project.provider { + kotlinCompileTask.compilerArgumentsContributor + } + override fun setupCompilerArgs(args: K2JVMCompilerArguments, defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) { - kotlinCompileTask.setupCompilerArgs(args, ignoreClasspathResolutionErrors = ignoreClasspathResolutionErrors) + compileKotlinArgumentsContributor.contributeArguments(args, compilerArgumentsConfigurationFlags( + defaultsOnly, + ignoreClasspathResolutionErrors + )) val pluginOptionsWithKapt = pluginOptions.withWrappedKaptOptions(withApClasspath = kaptClasspath) args.pluginOptions = (pluginOptionsWithKapt.arguments + args.pluginOptions!!).toTypedArray() @@ -90,10 +96,13 @@ open class KaptGenerateStubsTask : KotlinCompile() { args.destinationAsFile = this.destinationDir } - override fun getSourceRoots(): SourceRoots.ForJvm = + private val sourceRoots by project.provider { kotlinCompileTask.getSourceRoots().let { val javaSourceRoots = it.javaSourceRoots.filterTo(HashSet()) { isSourceRootAllowed(it) } val kotlinSourceFiles = it.kotlinSourceFiles SourceRoots.ForJvm(kotlinSourceFiles, javaSourceRoots) } + } + + override fun getSourceRoots(): SourceRoots.ForJvm = sourceRoots } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt index baa641e14a5..21948a834fd 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.cacheOnlyIfEnabledForKotlin import org.jetbrains.kotlin.gradle.tasks.clearLocalState +import org.jetbrains.kotlin.gradle.utils.getValue import org.jetbrains.kotlin.gradle.utils.isJavaFile import java.io.File import java.util.jar.JarFile @@ -30,6 +31,7 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { override fun localStateDirectories(): FileCollection = project.files() @get:Internal + @field:Transient internal lateinit var kotlinCompileTask: KotlinCompile @get:Internal @@ -38,12 +40,13 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { @get:Classpath @get:InputFiles val kaptClasspath: FileCollection - get() = project.files(*kaptClasspathConfigurations.toTypedArray()) + get() = project.files(kaptClasspathConfigurations) @get:Classpath @get:InputFiles - val compilerClasspath: List - get() = kotlinCompileTask.computedCompilerClasspath + val compilerClasspath: List by project.provider { + kotlinCompileTask.computedCompilerClasspath + } @get:Internal internal lateinit var kaptClasspathConfigurations: List @@ -82,8 +85,9 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { // @Internal because _abiClasspath and _nonAbiClasspath are used for actual checks @get:Internal - val classpath: FileCollection - get() = kotlinCompileTask.classpath + val classpath: FileCollection by project.provider { + kotlinCompileTask.classpath + } @Suppress("unused", "DeprecatedCallableAddReplaceWith") @Deprecated( @@ -92,8 +96,9 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { ) @get:CompileClasspath @get:InputFiles - internal val internalAbiClasspath: FileCollection - get() = if (includeCompileClasspath) project.files() else kotlinCompileTask.classpath + internal val internalAbiClasspath: FileCollection by project.provider { + if (includeCompileClasspath) project.files() else kotlinCompileTask.classpath + } @Suppress("unused", "DeprecatedCallableAddReplaceWith") @@ -103,8 +108,9 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { ) @get:Classpath @get:InputFiles - internal val internalNonAbiClasspath: FileCollection - get() = if (includeCompileClasspath) kotlinCompileTask.classpath else project.files() + internal val internalNonAbiClasspath: FileCollection by project.provider { + if (includeCompileClasspath) kotlinCompileTask.classpath else project.files() + } @get:Internal var useBuildCache: Boolean = false @@ -120,10 +126,14 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { return result } + // store the files before filtering, so that Gradle doesn't serialize the filtered collection for instant execution state and reuse it + private val unfilteredJavaSourceRoots by project.provider { + (kotlinCompileTask.sourceRootsContainer.sourceRoots + stubsDir) + } + @get:Internal protected val javaSourceRoots: Set - get() = (kotlinCompileTask.sourceRootsContainer.sourceRoots + stubsDir) - .filterTo(HashSet(), ::isRootAllowed) + get() = unfilteredJavaSourceRoots.filterTo(HashSet(), ::isRootAllowed) private fun isRootAllowed(file: File): Boolean = file.exists() && @@ -163,8 +173,10 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { } // TODO(gavra): Here we assume that kotlinc and javac output is available for incremental runs. We should insert some checks. - @Internal - protected fun getCompiledSources() = listOfNotNull(kotlinCompileTask.destinationDir, kotlinCompileTask.javaOutputDir) + @get:Internal + internal val compiledSources by project.provider { + listOfNotNull(kotlinCompileTask.destinationDir, kotlinCompileTask.javaOutputDir) + } protected fun getIncrementalChanges(inputs: IncrementalTaskInputs): KaptIncrementalChanges { return if (isIncremental) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithKotlincTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithKotlincTask.kt index 625076ea5c9..aa218fd15ed 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithKotlincTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithKotlincTask.kt @@ -23,6 +23,8 @@ 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.utils.getValue +import org.jetbrains.kotlin.gradle.utils.optionalProvider import org.jetbrains.kotlin.gradle.utils.toSortedPathsArray import java.io.File @@ -43,8 +45,15 @@ open class KaptWithKotlincTask : KaptTask(), CompilerArgumentAwareWithInput = emptyList() private var processIncrementally = false + private val javaPackagePrefix by project.optionalProvider { kotlinCompileTask.javaPackagePrefix } + private val buildReportMode by project.optionalProvider { kotlinCompileTask.buildReportMode } + @TaskAction fun compile(inputs: IncrementalTaskInputs) { logger.debug("Running kapt annotation processing using the Kotlin compiler") @@ -87,7 +99,7 @@ open class KaptWithKotlincTask : KaptTask(), CompilerArgumentAwareWithInput - get() = project.configurations.getByName(KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME).resolve() + val kaptJars: Collection by project.provider { + project.configurations.getByName(KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME).resolve() + } @get:Input var isVerbose: Boolean = false @@ -85,7 +87,7 @@ open class KaptWithoutKotlincTask @Inject constructor(private val workerExecutor javaSourceRoots.toList(), changedFiles, - getCompiledSources(), + compiledSources, incAptCache, classpathChanges.toList(), diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt index 0931274bdba..eb9b789a7f7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt @@ -10,7 +10,6 @@ import org.gradle.api.Task import org.gradle.api.file.FileCollection import org.gradle.api.provider.Provider import org.gradle.api.tasks.* -import org.gradle.api.tasks.Optional import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.api.tasks.compile.JavaCompile import org.gradle.api.tasks.incremental.IncrementalTaskInputs @@ -24,7 +23,7 @@ import org.jetbrains.kotlin.compilerRunner.* import org.jetbrains.kotlin.daemon.common.MultiModuleICSettings import org.jetbrains.kotlin.gradle.dsl.* import org.jetbrains.kotlin.gradle.incremental.ChangedFiles -import org.jetbrains.kotlin.gradle.internal.CompilerArgumentAwareWithInput +import org.jetbrains.kotlin.gradle.internal.* import org.jetbrains.kotlin.gradle.internal.prepareCompilerArguments import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles @@ -38,8 +37,6 @@ 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.incremental.ChangedFiles -import org.jetbrains.kotlin.incremental.classpathAsList -import org.jetbrains.kotlin.incremental.destinationAsFile import org.jetbrains.kotlin.utils.LibraryUtils import java.io.File import javax.inject.Inject @@ -174,12 +171,12 @@ abstract class AbstractKotlinCompile() : AbstractKo // 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 + additionalClasspath + classpath + project.files(additionalClasspath) } @get:Internal // classpath already participates in the checks internal val compileClasspath: Iterable - get() = compileClasspathImpl.filter { it.exists() } + get() = compileClasspathImpl @field:Transient private val sourceFilesExtensionsSources: MutableList> = mutableListOf() @@ -218,7 +215,8 @@ abstract class AbstractKotlinCompile() : AbstractKo internal val coroutinesStr: String get() = coroutines.name - private val coroutines: Coroutines by project.provider { + @get:Internal + internal val coroutines: Coroutines by project.provider { kotlinExt.experimental.coroutines ?: coroutinesFromGradleProperties ?: Coroutines.DEFAULT @@ -317,27 +315,16 @@ abstract class AbstractKotlinCompile() : AbstractKo */ internal abstract fun callCompilerAsync(args: T, sourceRoots: SourceRoots, changedFiles: ChangedFiles) - private val isMultiplatform: Boolean by project.provider { + @get:Internal + internal val isMultiplatform: Boolean by project.provider { project.plugins.any { it is KotlinPlatformPluginBase || it is KotlinMultiplatformPluginWrapper } } override fun setupCompilerArgs(args: T, defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) { - args.coroutinesState = when (coroutines) { - Coroutines.ENABLE -> CommonCompilerArguments.ENABLE - Coroutines.WARN -> CommonCompilerArguments.WARN - Coroutines.ERROR -> CommonCompilerArguments.ERROR - Coroutines.DEFAULT -> CommonCompilerArguments.DEFAULT - } - - logger.kotlinDebug { "args.coroutinesState=${args.coroutinesState}" } - - if (logger.isDebugEnabled) { - args.verbose = true - } - - args.multiPlatform = isMultiplatform - - setupPlugins(args) + AbstractKotlinCompileArgumentsContributor(thisTaskProvider).contributeArguments( + args, + compilerArgumentsConfigurationFlags(defaultsOnly, ignoreClasspathResolutionErrors) + ) } internal fun setupPlugins(compilerArgs: T) { @@ -351,6 +338,9 @@ abstract class AbstractKotlinCompile() : AbstractKo } } +internal inline val T.thisTaskProvider: TaskProvider + get() = checkNotNull(project.locateTask(name)) + @CacheableTask open class KotlinCompile : AbstractKotlinCompile(), KotlinJvmCompile { @get:Internal @@ -390,28 +380,15 @@ open class KotlinCompile : AbstractKotlinCompile(), Kotl K2JVMCompilerArguments() override fun setupCompilerArgs(args: K2JVMCompilerArguments, defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) { - args.apply { fillDefaultValues() } - super.setupCompilerArgs(args, defaultsOnly = defaultsOnly, ignoreClasspathResolutionErrors = ignoreClasspathResolutionErrors) + compilerArgumentsContributor.contributeArguments(args, compilerArgumentsConfigurationFlags( + defaultsOnly, + ignoreClasspathResolutionErrors + )) + } - args.moduleName = moduleName - logger.kotlinDebug { "args.moduleName = ${args.moduleName}" } - - args.friendPaths = friendPaths - logger.kotlinDebug { "args.friendPaths = ${args.friendPaths?.joinToString() ?: "[]"}" } - - if (defaultsOnly) return - - args.allowNoSourceFiles = true - args.classpathAsList = try { - compileClasspath.toList() - } catch (e: Exception) { - if (ignoreClasspathResolutionErrors) emptyList() else throw(e) - } - args.destinationAsFile = destinationDir - parentKotlinOptionsImpl?.updateArguments(args) - kotlinOptionsImpl.updateArguments(args) - - logger.kotlinDebug { "$name destinationDir = $destinationDir" } + @get:Internal + internal val compilerArgumentsContributor: CompilerArgumentsContributor by project.provider { + KotlinJvmCompilerArgumentsContributor(thisTaskProvider) } @Internal @@ -488,13 +465,13 @@ open class KotlinCompile : AbstractKotlinCompile(), Kotl } // override setSource to track source directory sets and files (for generated android folders) - override fun setSource(sources: Any?) { + override fun setSource(sources: Any) { sourceRootsContainer.set(sources) super.setSource(sources) } // override source to track source directory sets and files (for generated android folders) - override fun source(vararg sources: Any?): SourceTask? { + override fun source(vararg sources: Any): SourceTask { sourceRootsContainer.add(*sources) return super.source(*sources) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/providerApiUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/providerApiUtils.kt index 6d3467302cf..4a6cb057b17 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/providerApiUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/providerApiUtils.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle.utils import org.gradle.api.Project import org.gradle.api.provider.Property import org.gradle.api.provider.Provider +import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KProperty internal operator fun Provider.getValue(thisRef: Any?, property: KProperty<*>) = get() @@ -22,4 +23,14 @@ internal fun Project.newProperty(initialize: (() -> T)? = null): Prope (project.objects.property(Any::class.java) as Property).apply { if (initialize != null) set(provider(initialize)) - } \ No newline at end of file + } + +private class OptionalProviderDelegate(private val provider: Provider) : ReadOnlyProperty { + override fun getValue(thisRef: Any?, property: KProperty<*>): T? = + if (provider.isPresent) + provider.get() + else null +} + +internal fun Project.optionalProvider(initialize: () -> T?): ReadOnlyProperty = + OptionalProviderDelegate(provider(initialize)) \ No newline at end of file