From 7b6dddf012db149a204b964c628f8ee5b7f1c408 Mon Sep 17 00:00:00 2001 From: Yahor Berdnikau Date: Wed, 28 Jul 2021 11:11:30 +0200 Subject: [PATCH] Replace usages of IncrementalTaskInputs with InputChanges. Gradle IncrementalTaskInputs was long time ago deprecated and not so flexible as a new proposed way - InputChanges. ^KT-47867 Fixed --- .../AbstractKotlinAndroidGradleTests.kt | 12 +- .../jetbrains/kotlin/gradle/BaseGradleIT.kt | 2 +- .../gradle/KaptIncrementalWithIsolatingApt.kt | 4 +- .../kotlin/gradle/incremental/ChangedFiles.kt | 23 --- .../kapt/Kapt3KotlinGradleSubplugin.kt | 4 +- .../kotlin/gradle/internal/kapt/KaptTask.kt | 171 ++++++++++-------- .../internal/kapt/KaptWithKotlincTask.kt | 5 +- .../internal/kapt/KaptWithoutKotlincTask.kt | 7 +- .../android/Android25ProjectHandler.kt | 4 +- .../android/internal/AndroidSubplugin.kt | 2 +- .../jetbrains/kotlin/gradle/tasks/Tasks.kt | 79 ++++++-- .../kotlin/gradle/utils/compatibiltiy.kt | 27 --- 12 files changed, 194 insertions(+), 146 deletions(-) delete mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/incremental/ChangedFiles.kt diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt index 6319ba705ea..3036096125c 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/AbstractKotlinAndroidGradleTests.kt @@ -818,6 +818,7 @@ fun getSomething() = 10 project.build("assembleDebug", options = options) { assertSuccessful() + output } val androidModuleKt = project.projectDir.getFileByName("AndroidModule.kt") @@ -830,13 +831,22 @@ fun getSomething() = 10 project.build(":app:assembleDebug", options = options) { assertSuccessful() - assertCompiledKotlinSources(project.relativize(androidModuleKt)) assertTasksExecuted( ":app:kaptGenerateStubsDebugKotlin", ":app:kaptDebugKotlin", ":app:compileDebugKotlin", ":app:compileDebugJavaWithJavac" ) + + // Output is combined with previous build, but we are only interested in the compilation + // from second build to avoid false positive test failure + val filteredOutput = output + .lineSequence() + .filter { it.contains("[KOTLIN] compile iteration:") } + .drop(1) + .joinToString(separator = "/n") + val actualSources = getCompiledKotlinSources(filteredOutput).projectRelativePaths(project) + assertSameFiles(project.relativize(androidModuleKt), actualSources, "Compiled Kotlin files differ:\n ") } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseGradleIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseGradleIT.kt index 47cfc76a92b..7c93f8a431a 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseGradleIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseGradleIT.kt @@ -567,7 +567,7 @@ abstract class BaseGradleIT { return this } - private fun Iterable.projectRelativePaths(project: Project): Iterable { + internal fun Iterable.projectRelativePaths(project: Project): Iterable { return map { it.canonicalFile.toRelativeString(project.projectDir) } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithIsolatingApt.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithIsolatingApt.kt index cf51d74e5ce..4224a067389 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithIsolatingApt.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KaptIncrementalWithIsolatingApt.kt @@ -96,7 +96,7 @@ class KaptIncrementalWithIsolatingApt : KaptIncrementalIT() { ) project.build("build") { assertSuccessful() - assertContains("Unable to use existing data, re-initializing classpath information for KAPT.") + assertContains("The input changes require a full rebuild for incremental task ':kaptKotlin'.") } } @@ -127,7 +127,7 @@ class KaptIncrementalWithIsolatingApt : KaptIncrementalIT() { } project.build("build") { assertSuccessful() - assertContains("Unable to use existing data, re-initializing classpath information for KAPT.") + assertContains("The input changes require a full rebuild for incremental task ':kaptKotlin'.") } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/incremental/ChangedFiles.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/incremental/ChangedFiles.kt deleted file mode 100644 index 8b739276c3f..00000000000 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/incremental/ChangedFiles.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2010-2018 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.incremental - -import org.jetbrains.kotlin.incremental.ChangedFiles -import java.io.File - -internal fun ChangedFiles( - @Suppress("DEPRECATION") taskInputs: org.gradle.api.tasks.incremental.IncrementalTaskInputs -): ChangedFiles { - if (!taskInputs.isIncremental) return ChangedFiles.Unknown() - - val modified = ArrayList() - val removed = ArrayList() - - taskInputs.outOfDate { modified.add(it.file) } - taskInputs.removed { removed.add(it.file) } - - return ChangedFiles.Known(modified, removed) -} diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt index e9d8430891c..26680262c20 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt @@ -519,7 +519,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To kaptTask.destinationDir = sourcesOutputDir kaptTask.kotlinSourcesDestinationDir = kotlinSourcesOutputDir kaptTask.classesDir = classesOutputDir - kaptTask.includeCompileClasspath = includeCompileClasspath + kaptTask.includeCompileClasspath.set(includeCompileClasspath) kaptTask.isIncremental = project.isIncrementalKapt() @@ -618,7 +618,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To kaptTaskProvider.configure { task -> task.onlyIf { it as KaptTask - it.includeCompileClasspath || !it.kaptClasspath.isEmpty() + it.includeCompileClasspath.get() || !it.kaptClasspath.isEmpty } } 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 d7c0244a78c..4c159c4e5b7 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 @@ -10,7 +10,8 @@ import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.tasks.* -import org.gradle.api.tasks.incremental.IncrementalTaskInputs +import org.gradle.work.Incremental +import org.gradle.work.InputChanges import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporterImpl import org.jetbrains.kotlin.gradle.internal.kapt.incremental.ClasspathSnapshot @@ -22,9 +23,10 @@ import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState import org.jetbrains.kotlin.gradle.tasks.* 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.* import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable import org.jetbrains.kotlin.gradle.utils.property +import org.jetbrains.kotlin.gradle.utils.propertyWithConvention import org.jetbrains.kotlin.gradle.utils.propertyWithNewInstance import org.jetbrains.kotlin.utils.addToStdlib.cast import java.io.File @@ -88,8 +90,8 @@ abstract class KaptTask @Inject constructor( @get:Internal internal abstract val kaptClasspathConfigurationNames: ListProperty - @get:PathSensitive(PathSensitivity.NONE) + @get:Incremental @get:IgnoreEmptyDirectories @get:Optional @get:InputFiles @@ -114,7 +116,9 @@ abstract class KaptTask @Inject constructor( internal val annotationProcessorOptionProviders: MutableList = mutableListOf() @get:Input - internal var includeCompileClasspath: Boolean = true + internal val includeCompileClasspath: Property = objectFactory + .propertyWithConvention(true) + .chainedFinalizeValueOnRead() @get:Input internal var isIncremental = true @@ -137,10 +141,11 @@ abstract class KaptTask @Inject constructor( message = "Don't use directly. Used only for up-to-date checks", level = DeprecationLevel.ERROR ) + @get:Incremental @get:CompileClasspath - internal val internalAbiClasspath: FileCollection by project.provider { - if (includeCompileClasspath) project.files() else classpath - } + internal val internalAbiClasspath: FileCollection = project.objects.fileCollection().from( + { if (includeCompileClasspath.get()) null else classpath } + ) @Suppress("unused", "DeprecatedCallableAddReplaceWith") @@ -148,10 +153,11 @@ abstract class KaptTask @Inject constructor( message = "Don't use directly. Used only for up-to-date checks", level = DeprecationLevel.ERROR ) + @get:Incremental @get:Classpath - internal val internalNonAbiClasspath: FileCollection by project.provider { - if (includeCompileClasspath) classpath else project.files() - } + internal val internalNonAbiClasspath: FileCollection = project.objects.fileCollection().from( + { if (includeCompileClasspath.get()) classpath else null } + ) @get:Internal var useBuildCache: Boolean = false @@ -165,6 +171,7 @@ abstract class KaptTask @Inject constructor( @get:InputFiles @get:IgnoreEmptyDirectories + @get:Incremental @get:PathSensitive(PathSensitivity.RELATIVE) abstract val source: ConfigurableFileCollection @@ -208,7 +215,7 @@ abstract class KaptTask @Inject constructor( } protected fun checkAnnotationProcessorClasspath() { - if (!includeCompileClasspath) return + if (!includeCompileClasspath.get()) return val kaptClasspath = kaptClasspath.toSet() val processorsFromCompileClasspath = classpath.files.filterTo(LinkedHashSet()) { @@ -240,86 +247,106 @@ abstract class KaptTask @Inject constructor( @get:Internal internal abstract val compiledSources: ConfigurableFileCollection - protected fun getIncrementalChanges(inputs: IncrementalTaskInputs): KaptIncrementalChanges { + protected fun getIncrementalChanges(inputChanges: InputChanges): KaptIncrementalChanges { return if (isIncremental) { - findClasspathChanges(inputs) + findClasspathChanges(inputChanges) } else { clearLocalState() KaptIncrementalChanges.Unknown } } - private fun findClasspathChanges(inputs: IncrementalTaskInputs): KaptIncrementalChanges { + private fun findClasspathChanges(inputChanges: InputChanges): KaptIncrementalChanges { val incAptCacheDir = incAptCache.asFile.get() incAptCacheDir.mkdirs() - val allDataFiles = classpathStructure.files - val changedFiles = if (inputs.isIncremental) { - with(mutableSetOf()) { - inputs.outOfDate { this.add(it.file) } - inputs.removed { this.add(it.file) } - return@with this + + return if (inputChanges.isIncremental) { + val startTime = System.currentTimeMillis() + + @Suppress("DEPRECATION_ERROR") + val changedFiles = listOf( + source, + internalNonAbiClasspath, + internalAbiClasspath, + classpathStructure + ).fold(mutableSetOf()) { acc, prop -> + inputChanges.getFileChanges(prop).forEach { acc.add(it.file) } + acc + } + + val previousSnapshot = loadPreviousSnapshot(incAptCacheDir, allDataFiles, changedFiles) + val currentSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory + .createCurrent( + incAptCacheDir, + classpath.files.toList(), + kaptClasspath.files.toList(), + allDataFiles + ) + val classpathChanges = currentSnapshot.diff(previousSnapshot, changedFiles) + if (classpathChanges == KaptClasspathChanges.Unknown) { + // We are unable to determine classpath changes, so clean the local state as we will run non-incrementally + clearLocalState() + } + currentSnapshot.writeToCache() + + if (logger.isInfoEnabled) { + val time = "Took ${System.currentTimeMillis() - startTime}ms." + when { + previousSnapshot == UnknownSnapshot -> + logger.info("Initializing classpath information for KAPT. $time") + classpathChanges == KaptClasspathChanges.Unknown -> + logger.info("Unable to use existing data, re-initializing classpath information for KAPT. $time") + else -> { + classpathChanges as KaptClasspathChanges.Known + logger.info("Full list of impacted classpath names: ${classpathChanges.names}. $time") + } + } + } + + return when (classpathChanges) { + is KaptClasspathChanges.Unknown -> KaptIncrementalChanges.Unknown + is KaptClasspathChanges.Known -> KaptIncrementalChanges.Known( + changedFiles.filter { it.extension == "java" }.toSet(), classpathChanges.names + ) } } else { - allDataFiles + clearLocalState("Kapt is running non-incrementally") + + ClasspathSnapshot.ClasspathSnapshotFactory + .createCurrent( + incAptCacheDir, + classpath.files.toList(), + kaptClasspath.files.toList(), + allDataFiles + ) + .writeToCache() + + KaptIncrementalChanges.Unknown } + } - val startTime = System.currentTimeMillis() + private fun loadPreviousSnapshot( + cacheDir: File, + allDataFiles: MutableSet, + changedFiles: MutableSet + ): ClasspathSnapshot { + val loadedPrevious = ClasspathSnapshot.ClasspathSnapshotFactory.loadFrom(cacheDir) - val previousSnapshot = if (inputs.isIncremental) { - val loadedPrevious = ClasspathSnapshot.ClasspathSnapshotFactory.loadFrom(incAptCacheDir) - - val previousAndCurrentDataFiles = lazy { loadedPrevious.getAllDataFiles() + allDataFiles } - val allChangesRecognized = changedFiles.all { - val extension = it.extension - if (extension.isEmpty() || extension == "java" || extension == "jar" || extension == "class") { - return@all true - } - // if not a directory, Java source file, jar, or class, it has to be a structure file, in order to understand changes - it in previousAndCurrentDataFiles.value - } - if (allChangesRecognized) { - loadedPrevious - } else { - ClasspathSnapshot.ClasspathSnapshotFactory.getEmptySnapshot() + val previousAndCurrentDataFiles = lazy { loadedPrevious.getAllDataFiles() + allDataFiles } + val allChangesRecognized = changedFiles.all { + val extension = it.extension + if (extension.isEmpty() || extension == "java" || extension == "jar" || extension == "class") { + return@all true } + // if not a directory, Java source file, jar, or class, it has to be a structure file, in order to understand changes + it in previousAndCurrentDataFiles.value + } + return if (allChangesRecognized) { + loadedPrevious } else { ClasspathSnapshot.ClasspathSnapshotFactory.getEmptySnapshot() } - val currentSnapshot = - ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent( - incAptCacheDir, - classpath.files.toList(), - kaptClasspath.files.toList(), - allDataFiles - ) - - val classpathChanges = currentSnapshot.diff(previousSnapshot, changedFiles) - if (classpathChanges == KaptClasspathChanges.Unknown) { - // We are unable to determine classpath changes, so clean the local state as we will run non-incrementally - clearLocalState() - } - currentSnapshot.writeToCache() - - if (logger.isInfoEnabled) { - val time = "Took ${System.currentTimeMillis() - startTime}ms." - when { - previousSnapshot == UnknownSnapshot -> - logger.info("Initializing classpath information for KAPT. $time") - classpathChanges == KaptClasspathChanges.Unknown -> - logger.info("Unable to use existing data, re-initializing classpath information for KAPT. $time") - else -> { - classpathChanges as KaptClasspathChanges.Known - logger.info("Full list of impacted classpath names: ${classpathChanges.names}. $time") - } - } - } - return when (classpathChanges) { - is KaptClasspathChanges.Unknown -> KaptIncrementalChanges.Unknown - is KaptClasspathChanges.Known -> KaptIncrementalChanges.Known( - changedFiles.filter { it.extension == "java" }.toSet(), classpathChanges.names - ) - } } private fun hasAnnotationProcessors(file: File): Boolean { 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 6fcf490022e..ef23cc958e8 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 @@ -12,6 +12,7 @@ import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.tasks.* import org.gradle.api.tasks.incremental.IncrementalTaskInputs +import org.gradle.work.InputChanges import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments import org.jetbrains.kotlin.compilerRunner.GradleCompilerEnvironment import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner @@ -97,11 +98,11 @@ abstract class KaptWithKotlincTask @Inject constructor( private val reportingSettings = objectFactory.property(ReportingSettings::class.java) @TaskAction - fun compile(inputs: IncrementalTaskInputs) { + fun compile(inputChanges: InputChanges) { logger.debug("Running kapt annotation processing using the Kotlin compiler") checkAnnotationProcessorClasspath() - val incrementalChanges = getIncrementalChanges(inputs) + val incrementalChanges = getIncrementalChanges(inputChanges) if (incrementalChanges is KaptIncrementalChanges.Known) { changedFiles = incrementalChanges.changedSources.toList() classpathChanges = incrementalChanges.changedClasspathJvmNames.toList() diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt index 8a4214f586e..18b3d3e6592 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt @@ -12,6 +12,7 @@ import org.gradle.api.provider.ProviderFactory import org.gradle.api.tasks.* import org.gradle.api.tasks.incremental.IncrementalTaskInputs import org.gradle.process.CommandLineArgumentProvider +import org.gradle.work.InputChanges import org.gradle.workers.IsolationMode import org.gradle.workers.WorkAction import org.gradle.workers.WorkParameters @@ -99,11 +100,11 @@ abstract class KaptWithoutKotlincTask @Inject constructor( } @TaskAction - fun compile(inputs: IncrementalTaskInputs) { + fun compile(inputChanges: InputChanges) { logger.info("Running kapt annotation processing using the Gradle Worker API") checkAnnotationProcessorClasspath() - val incrementalChanges = getIncrementalChanges(inputs) + val incrementalChanges = getIncrementalChanges(inputChanges) val (changedFiles, classpathChanges) = when (incrementalChanges) { is KaptIncrementalChanges.Unknown -> Pair(emptyList(), emptyList()) is KaptIncrementalChanges.Known -> Pair(incrementalChanges.changedSources.toList(), incrementalChanges.changedClasspathJvmNames) @@ -117,7 +118,7 @@ abstract class KaptWithoutKotlincTask @Inject constructor( val kaptFlagsForWorker = mutableSetOf().apply { if (verbose.get()) add("VERBOSE") if (mapDiagnosticLocations) add("MAP_DIAGNOSTIC_LOCATIONS") - if (includeCompileClasspath) add("INCLUDE_COMPILE_CLASSPATH") + if (includeCompileClasspath.get()) add("INCLUDE_COMPILE_CLASSPATH") if (incrementalChanges is KaptIncrementalChanges.Known) add("INCREMENTAL_APT") } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/Android25ProjectHandler.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/Android25ProjectHandler.kt index 1bd3c84532a..1e384501022 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/Android25ProjectHandler.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/Android25ProjectHandler.kt @@ -59,7 +59,9 @@ class Android25ProjectHandler( val preJavaClasspathKey = variantData.registerPreJavacGeneratedBytecode(preJavaKotlinOutput) kotlinTask.configure { kotlinTaskInstance -> - kotlinTaskInstance.inputs.files(variantData.getSourceFolders(SourceKind.JAVA)).withPathSensitivity(PathSensitivity.RELATIVE) + kotlinTaskInstance.source( + variantData.getSourceFolders(SourceKind.JAVA) + ) kotlinTaskInstance.classpath = project.files() .from(variantData.getCompileClasspath(preJavaClasspathKey)) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/internal/AndroidSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/internal/AndroidSubplugin.kt index f4839c0bce9..24e129fda3b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/internal/AndroidSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/internal/AndroidSubplugin.kt @@ -135,7 +135,7 @@ class AndroidSubplugin : ) ) kotlinCompilation.compileKotlinTaskProvider.configure { - it.inputs.files(getLayoutDirectories(project, sourceSet.res.srcDirs)).withPathSensitivity(PathSensitivity.RELATIVE) + it.source(getLayoutDirectories(project, sourceSet.res.srcDirs)) } } 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 5bae9eda9a6..7c444c60169 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 @@ -14,6 +14,7 @@ import org.gradle.api.invocation.Gradle import org.gradle.api.attributes.Attribute import org.gradle.api.logging.Logger import org.gradle.api.model.ObjectFactory +import org.gradle.api.model.ReplacedBy import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.provider.Provider @@ -22,7 +23,9 @@ import org.gradle.api.services.BuildServiceParameters import org.gradle.api.tasks.* import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.api.tasks.compile.JavaCompile -import org.gradle.api.tasks.incremental.IncrementalTaskInputs +import org.gradle.work.ChangeType +import org.gradle.work.Incremental +import org.gradle.work.InputChanges import org.gradle.workers.WorkerExecutor import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS import org.jetbrains.kotlin.build.report.metrics.* @@ -36,7 +39,6 @@ import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner.Companion.normal import org.jetbrains.kotlin.daemon.common.MultiModuleICSettings import org.jetbrains.kotlin.gradle.dsl.* import org.jetbrains.kotlin.gradle.incremental.* -import org.jetbrains.kotlin.gradle.incremental.ChangedFiles import org.jetbrains.kotlin.gradle.internal.* import org.jetbrains.kotlin.gradle.internal.tasks.TaskConfigurator import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState @@ -74,10 +76,22 @@ abstract class AbstractKotlinCompileTool CompilerArgumentAwareWithInput, TaskWithLocalState { - @InputFiles - @PathSensitive(PathSensitivity.RELATIVE) + @ReplacedBy("stableSources") override fun getSource() = super.getSource() + @get:InputFiles + @get:SkipWhenEmpty + @get:IgnoreEmptyDirectories + @get:PathSensitive(PathSensitivity.RELATIVE) + internal val stableSources: FileCollection = project.files( + { source } + ) + + @Incremental + override fun getClasspath(): FileCollection { + return super.getClasspath() + } + @get:Input internal var useFallbackCompilerSearch: Boolean = false @@ -278,6 +292,7 @@ abstract class AbstractKotlinCompile : AbstractKotl @get:InputFiles @get:IgnoreEmptyDirectories + @get:Incremental @get:PathSensitive(PathSensitivity.RELATIVE) internal val commonSourceSet: ConfigurableFileCollection = objects.fileCollection() @@ -321,7 +336,7 @@ abstract class AbstractKotlinCompile : AbstractKotl private val systemPropertiesService = CompilerSystemPropertiesService.registerIfAbsent(project.gradle) @TaskAction - fun execute(inputs: IncrementalTaskInputs) { + fun execute(inputChanges: InputChanges) { metrics.measure(BuildTime.GRADLE_TASK_ACTION) { systemPropertiesService.get().startIntercept() CompilerSystemProperties.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY.value = "true" @@ -330,7 +345,7 @@ abstract class AbstractKotlinCompile : AbstractKotl // then Gradle forces next build to be non-incremental (see Gradle's DefaultTaskArtifactStateRepository#persistNewOutputs) // To prevent this, we backup outputs before incremental build and restore when exception is thrown val outputsBackup: TaskOutputsBackup? = - if (isIncrementalCompilationEnabled() && inputs.isIncremental) + if (isIncrementalCompilationEnabled() && inputChanges.isIncremental) metrics.measure(BuildTime.BACKUP_OUTPUT) { TaskOutputsBackup(allOutputFiles()) } @@ -338,12 +353,12 @@ abstract class AbstractKotlinCompile : AbstractKotl if (!isIncrementalCompilationEnabled()) { clearLocalState("IC is disabled") - } else if (!inputs.isIncremental) { + } else if (!inputChanges.isIncremental) { clearLocalState("Task cannot run incrementally") } try { - executeImpl(inputs) + executeImpl(inputChanges) } catch (t: Throwable) { if (outputsBackup != null) { metrics.measure(BuildTime.RESTORE_OUTPUT_FROM_BACKUP) { @@ -360,13 +375,21 @@ abstract class AbstractKotlinCompile : AbstractKotl private val projectDir = project.rootProject.projectDir - private fun executeImpl(inputs: IncrementalTaskInputs) { + @get:Internal + protected open val incrementalProps: List + get() = listOfNotNull( + stableSources, + classpath, + commonSourceSet + ) + + private fun executeImpl(inputChanges: InputChanges) { val sourceRoots = getSourceRoots() val allKotlinSources = sourceRoots.kotlinSourceFiles logger.kotlinDebug { "All kotlin sources: ${allKotlinSources.pathsAsStringRelativeTo(projectDir)}" } - if (!inputs.isIncremental && skipCondition()) { + if (!inputChanges.isIncremental && skipCondition()) { // Skip running only if non-incremental run. Otherwise, we may need to do some cleanup. logger.kotlinDebug { "No Kotlin files found, skipping Kotlin compiler task" } return @@ -375,7 +398,33 @@ abstract class AbstractKotlinCompile : AbstractKotl sourceRoots.log(this.name, logger) val args = prepareCompilerArguments() taskBuildDirectory.get().asFile.mkdirs() - callCompilerAsync(args, sourceRoots, ChangedFiles(inputs)) + callCompilerAsync( + args, + sourceRoots, + getChangedFiles(inputChanges, incrementalProps) + ) + } + + protected fun getChangedFiles( + inputChanges: InputChanges, + incrementalProps: List + ) = if (!inputChanges.isIncremental) { + ChangedFiles.Unknown() + } else { + incrementalProps + .fold(mutableListOf() to mutableListOf()) { (modified, removed), prop -> + inputChanges.getFileChanges(prop).forEach { + when (it.changeType) { + ChangeType.ADDED, ChangeType.MODIFIED -> modified.add(it.file) + ChangeType.REMOVED -> removed.add(it.file) + else -> Unit + } + } + modified to removed + } + .run { + ChangedFiles.Known(first, second) + } } @Internal @@ -550,6 +599,7 @@ abstract class KotlinCompile @Inject constructor( abstract val useClasspathSnapshot: Property @get:Classpath + @get:Incremental @get:Optional // Set if useClasspathSnapshot == true abstract val classpathSnapshot: ConfigurableFileCollection @@ -614,6 +664,9 @@ abstract class KotlinCompile @Inject constructor( KotlinJvmCompilerArgumentsContributor(KotlinJvmCompilerArgumentsProvider(this)) } + override val incrementalProps: List + get() = super.incrementalProps + listOf(classpathSnapshotProperties.classpathSnapshot) + override fun getSourceRoots(): SourceRoots.ForJvm = jvmSourceRoots override fun callCompilerAsync(args: K2JVMCompilerArguments, sourceRoots: SourceRoots, changedFiles: ChangedFiles) { @@ -941,6 +994,7 @@ abstract class Kotlin2JsCompile @Inject constructor( @get:InputFiles @get:IgnoreEmptyDirectories + @get:Incremental @get:Optional @get:PathSensitive(PathSensitivity.RELATIVE) internal val friendDependencies: FileCollection = objectFactory @@ -1015,6 +1069,9 @@ abstract class Kotlin2JsCompile @Inject constructor( @get:Internal internal val absolutePathProvider = project.projectDir.absolutePath + override val incrementalProps: List + get() = super.incrementalProps + listOf(friendDependencies) + override fun callCompilerAsync(args: K2JSCompilerArguments, sourceRoots: SourceRoots, changedFiles: ChangedFiles) { sourceRoots as SourceRoots.KotlinOnly diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/compatibiltiy.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/compatibiltiy.kt index a86e50f3758..52f8a092d62 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/compatibiltiy.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/compatibiltiy.kt @@ -18,15 +18,12 @@ package org.jetbrains.kotlin.gradle.utils import org.gradle.api.GradleException import org.gradle.api.Project -import org.gradle.api.Task import org.gradle.api.file.ArchiveOperations import org.gradle.api.file.CopySpec import org.gradle.api.file.FileSystemOperations import org.gradle.api.file.FileTree import org.gradle.api.internal.project.ProjectInternal import org.gradle.api.internal.tasks.testing.TestDescriptorInternal -import org.gradle.api.tasks.TaskInputs -import org.gradle.api.tasks.TaskOutputs import org.gradle.api.tasks.WorkResult import org.gradle.api.tasks.bundling.AbstractArchiveTask import org.gradle.api.tasks.testing.TestDescriptor @@ -36,30 +33,6 @@ import java.io.Serializable const val minSupportedGradleVersion = "6.1.1" -internal val Task.inputsCompatible: TaskInputs get() = inputs - -internal val Task.outputsCompatible: TaskOutputs get() = outputs - -private val propertyMethod by lazy { - TaskInputs::class.java.methods.first { - it.name == "property" && it.parameterTypes.contentEquals(arrayOf(String::class.java, Any::class.java)) - } -} - -internal fun TaskInputs.propertyCompatible(name: String, value: Any) { - propertyMethod(this, name, value) -} - -private val inputsDirMethod by lazy { - TaskInputs::class.java.methods.first { - it.name == "dir" && it.parameterTypes.contentEquals(arrayOf(Any::class.java)) - } -} - -internal fun TaskInputs.dirCompatible(dirPath: Any) { - inputsDirMethod(this, dirPath) -} - internal fun checkGradleCompatibility( withComponent: String = "the Kotlin Gradle plugin", minSupportedVersion: GradleVersion = GradleVersion.version(minSupportedGradleVersion)