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
This commit is contained in:
Yahor Berdnikau
2021-07-28 11:11:30 +02:00
committed by Space
parent c3344549a8
commit 7b6dddf012
12 changed files with 194 additions and 146 deletions
@@ -818,6 +818,7 @@ fun getSomething() = 10
project.build("assembleDebug", options = options) { project.build("assembleDebug", options = options) {
assertSuccessful() assertSuccessful()
output
} }
val androidModuleKt = project.projectDir.getFileByName("AndroidModule.kt") val androidModuleKt = project.projectDir.getFileByName("AndroidModule.kt")
@@ -830,13 +831,22 @@ fun getSomething() = 10
project.build(":app:assembleDebug", options = options) { project.build(":app:assembleDebug", options = options) {
assertSuccessful() assertSuccessful()
assertCompiledKotlinSources(project.relativize(androidModuleKt))
assertTasksExecuted( assertTasksExecuted(
":app:kaptGenerateStubsDebugKotlin", ":app:kaptGenerateStubsDebugKotlin",
":app:kaptDebugKotlin", ":app:kaptDebugKotlin",
":app:compileDebugKotlin", ":app:compileDebugKotlin",
":app:compileDebugJavaWithJavac" ":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 ")
} }
} }
@@ -567,7 +567,7 @@ abstract class BaseGradleIT {
return this return this
} }
private fun Iterable<File>.projectRelativePaths(project: Project): Iterable<String> { internal fun Iterable<File>.projectRelativePaths(project: Project): Iterable<String> {
return map { it.canonicalFile.toRelativeString(project.projectDir) } return map { it.canonicalFile.toRelativeString(project.projectDir) }
} }
@@ -96,7 +96,7 @@ class KaptIncrementalWithIsolatingApt : KaptIncrementalIT() {
) )
project.build("build") { project.build("build") {
assertSuccessful() 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") { project.build("build") {
assertSuccessful() 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'.")
} }
} }
@@ -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<File>()
val removed = ArrayList<File>()
taskInputs.outOfDate { modified.add(it.file) }
taskInputs.removed { removed.add(it.file) }
return ChangedFiles.Known(modified, removed)
}
@@ -519,7 +519,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
kaptTask.destinationDir = sourcesOutputDir kaptTask.destinationDir = sourcesOutputDir
kaptTask.kotlinSourcesDestinationDir = kotlinSourcesOutputDir kaptTask.kotlinSourcesDestinationDir = kotlinSourcesOutputDir
kaptTask.classesDir = classesOutputDir kaptTask.classesDir = classesOutputDir
kaptTask.includeCompileClasspath = includeCompileClasspath kaptTask.includeCompileClasspath.set(includeCompileClasspath)
kaptTask.isIncremental = project.isIncrementalKapt() kaptTask.isIncremental = project.isIncrementalKapt()
@@ -618,7 +618,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
kaptTaskProvider.configure { task -> kaptTaskProvider.configure { task ->
task.onlyIf { task.onlyIf {
it as KaptTask it as KaptTask
it.includeCompileClasspath || !it.kaptClasspath.isEmpty() it.includeCompileClasspath.get() || !it.kaptClasspath.isEmpty
} }
} }
@@ -10,7 +10,8 @@ import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider import org.gradle.api.provider.Provider
import org.gradle.api.tasks.* 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.BuildMetricsReporter
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporterImpl import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporterImpl
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.ClasspathSnapshot 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.*
import org.jetbrains.kotlin.gradle.tasks.cacheOnlyIfEnabledForKotlin import org.jetbrains.kotlin.gradle.tasks.cacheOnlyIfEnabledForKotlin
import org.jetbrains.kotlin.gradle.tasks.clearLocalState 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.isConfigurationCacheAvailable
import org.jetbrains.kotlin.gradle.utils.property 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.gradle.utils.propertyWithNewInstance
import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.cast
import java.io.File import java.io.File
@@ -88,8 +90,8 @@ abstract class KaptTask @Inject constructor(
@get:Internal @get:Internal
internal abstract val kaptClasspathConfigurationNames: ListProperty<String> internal abstract val kaptClasspathConfigurationNames: ListProperty<String>
@get:PathSensitive(PathSensitivity.NONE) @get:PathSensitive(PathSensitivity.NONE)
@get:Incremental
@get:IgnoreEmptyDirectories @get:IgnoreEmptyDirectories
@get:Optional @get:Optional
@get:InputFiles @get:InputFiles
@@ -114,7 +116,9 @@ abstract class KaptTask @Inject constructor(
internal val annotationProcessorOptionProviders: MutableList<Any> = mutableListOf() internal val annotationProcessorOptionProviders: MutableList<Any> = mutableListOf()
@get:Input @get:Input
internal var includeCompileClasspath: Boolean = true internal val includeCompileClasspath: Property<Boolean> = objectFactory
.propertyWithConvention(true)
.chainedFinalizeValueOnRead()
@get:Input @get:Input
internal var isIncremental = true 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", message = "Don't use directly. Used only for up-to-date checks",
level = DeprecationLevel.ERROR level = DeprecationLevel.ERROR
) )
@get:Incremental
@get:CompileClasspath @get:CompileClasspath
internal val internalAbiClasspath: FileCollection by project.provider { internal val internalAbiClasspath: FileCollection = project.objects.fileCollection().from(
if (includeCompileClasspath) project.files() else classpath { if (includeCompileClasspath.get()) null else classpath }
} )
@Suppress("unused", "DeprecatedCallableAddReplaceWith") @Suppress("unused", "DeprecatedCallableAddReplaceWith")
@@ -148,10 +153,11 @@ abstract class KaptTask @Inject constructor(
message = "Don't use directly. Used only for up-to-date checks", message = "Don't use directly. Used only for up-to-date checks",
level = DeprecationLevel.ERROR level = DeprecationLevel.ERROR
) )
@get:Incremental
@get:Classpath @get:Classpath
internal val internalNonAbiClasspath: FileCollection by project.provider { internal val internalNonAbiClasspath: FileCollection = project.objects.fileCollection().from(
if (includeCompileClasspath) classpath else project.files() { if (includeCompileClasspath.get()) classpath else null }
} )
@get:Internal @get:Internal
var useBuildCache: Boolean = false var useBuildCache: Boolean = false
@@ -165,6 +171,7 @@ abstract class KaptTask @Inject constructor(
@get:InputFiles @get:InputFiles
@get:IgnoreEmptyDirectories @get:IgnoreEmptyDirectories
@get:Incremental
@get:PathSensitive(PathSensitivity.RELATIVE) @get:PathSensitive(PathSensitivity.RELATIVE)
abstract val source: ConfigurableFileCollection abstract val source: ConfigurableFileCollection
@@ -208,7 +215,7 @@ abstract class KaptTask @Inject constructor(
} }
protected fun checkAnnotationProcessorClasspath() { protected fun checkAnnotationProcessorClasspath() {
if (!includeCompileClasspath) return if (!includeCompileClasspath.get()) return
val kaptClasspath = kaptClasspath.toSet() val kaptClasspath = kaptClasspath.toSet()
val processorsFromCompileClasspath = classpath.files.filterTo(LinkedHashSet()) { val processorsFromCompileClasspath = classpath.files.filterTo(LinkedHashSet()) {
@@ -240,86 +247,106 @@ abstract class KaptTask @Inject constructor(
@get:Internal @get:Internal
internal abstract val compiledSources: ConfigurableFileCollection internal abstract val compiledSources: ConfigurableFileCollection
protected fun getIncrementalChanges(inputs: IncrementalTaskInputs): KaptIncrementalChanges { protected fun getIncrementalChanges(inputChanges: InputChanges): KaptIncrementalChanges {
return if (isIncremental) { return if (isIncremental) {
findClasspathChanges(inputs) findClasspathChanges(inputChanges)
} else { } else {
clearLocalState() clearLocalState()
KaptIncrementalChanges.Unknown KaptIncrementalChanges.Unknown
} }
} }
private fun findClasspathChanges(inputs: IncrementalTaskInputs): KaptIncrementalChanges { private fun findClasspathChanges(inputChanges: InputChanges): KaptIncrementalChanges {
val incAptCacheDir = incAptCache.asFile.get() val incAptCacheDir = incAptCache.asFile.get()
incAptCacheDir.mkdirs() incAptCacheDir.mkdirs()
val allDataFiles = classpathStructure.files val allDataFiles = classpathStructure.files
val changedFiles = if (inputs.isIncremental) {
with(mutableSetOf<File>()) { return if (inputChanges.isIncremental) {
inputs.outOfDate { this.add(it.file) } val startTime = System.currentTimeMillis()
inputs.removed { this.add(it.file) }
return@with this @Suppress("DEPRECATION_ERROR")
val changedFiles = listOf(
source,
internalNonAbiClasspath,
internalAbiClasspath,
classpathStructure
).fold(mutableSetOf<File>()) { 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 { } 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<File>,
changedFiles: MutableSet<File>
): ClasspathSnapshot {
val loadedPrevious = ClasspathSnapshot.ClasspathSnapshotFactory.loadFrom(cacheDir)
val previousSnapshot = if (inputs.isIncremental) { val previousAndCurrentDataFiles = lazy { loadedPrevious.getAllDataFiles() + allDataFiles }
val loadedPrevious = ClasspathSnapshot.ClasspathSnapshotFactory.loadFrom(incAptCacheDir) val allChangesRecognized = changedFiles.all {
val extension = it.extension
val previousAndCurrentDataFiles = lazy { loadedPrevious.getAllDataFiles() + allDataFiles } if (extension.isEmpty() || extension == "java" || extension == "jar" || extension == "class") {
val allChangesRecognized = changedFiles.all { return@all true
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()
} }
// 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 { } else {
ClasspathSnapshot.ClasspathSnapshotFactory.getEmptySnapshot() 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 { private fun hasAnnotationProcessors(file: File): Boolean {
@@ -12,6 +12,7 @@ import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider import org.gradle.api.provider.Provider
import org.gradle.api.tasks.* import org.gradle.api.tasks.*
import org.gradle.api.tasks.incremental.IncrementalTaskInputs import org.gradle.api.tasks.incremental.IncrementalTaskInputs
import org.gradle.work.InputChanges
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.compilerRunner.GradleCompilerEnvironment import org.jetbrains.kotlin.compilerRunner.GradleCompilerEnvironment
import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner
@@ -97,11 +98,11 @@ abstract class KaptWithKotlincTask @Inject constructor(
private val reportingSettings = objectFactory.property(ReportingSettings::class.java) private val reportingSettings = objectFactory.property(ReportingSettings::class.java)
@TaskAction @TaskAction
fun compile(inputs: IncrementalTaskInputs) { fun compile(inputChanges: InputChanges) {
logger.debug("Running kapt annotation processing using the Kotlin compiler") logger.debug("Running kapt annotation processing using the Kotlin compiler")
checkAnnotationProcessorClasspath() checkAnnotationProcessorClasspath()
val incrementalChanges = getIncrementalChanges(inputs) val incrementalChanges = getIncrementalChanges(inputChanges)
if (incrementalChanges is KaptIncrementalChanges.Known) { if (incrementalChanges is KaptIncrementalChanges.Known) {
changedFiles = incrementalChanges.changedSources.toList() changedFiles = incrementalChanges.changedSources.toList()
classpathChanges = incrementalChanges.changedClasspathJvmNames.toList() classpathChanges = incrementalChanges.changedClasspathJvmNames.toList()
@@ -12,6 +12,7 @@ import org.gradle.api.provider.ProviderFactory
import org.gradle.api.tasks.* import org.gradle.api.tasks.*
import org.gradle.api.tasks.incremental.IncrementalTaskInputs import org.gradle.api.tasks.incremental.IncrementalTaskInputs
import org.gradle.process.CommandLineArgumentProvider import org.gradle.process.CommandLineArgumentProvider
import org.gradle.work.InputChanges
import org.gradle.workers.IsolationMode import org.gradle.workers.IsolationMode
import org.gradle.workers.WorkAction import org.gradle.workers.WorkAction
import org.gradle.workers.WorkParameters import org.gradle.workers.WorkParameters
@@ -99,11 +100,11 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
} }
@TaskAction @TaskAction
fun compile(inputs: IncrementalTaskInputs) { fun compile(inputChanges: InputChanges) {
logger.info("Running kapt annotation processing using the Gradle Worker API") logger.info("Running kapt annotation processing using the Gradle Worker API")
checkAnnotationProcessorClasspath() checkAnnotationProcessorClasspath()
val incrementalChanges = getIncrementalChanges(inputs) val incrementalChanges = getIncrementalChanges(inputChanges)
val (changedFiles, classpathChanges) = when (incrementalChanges) { val (changedFiles, classpathChanges) = when (incrementalChanges) {
is KaptIncrementalChanges.Unknown -> Pair(emptyList<File>(), emptyList<String>()) is KaptIncrementalChanges.Unknown -> Pair(emptyList<File>(), emptyList<String>())
is KaptIncrementalChanges.Known -> Pair(incrementalChanges.changedSources.toList(), incrementalChanges.changedClasspathJvmNames) is KaptIncrementalChanges.Known -> Pair(incrementalChanges.changedSources.toList(), incrementalChanges.changedClasspathJvmNames)
@@ -117,7 +118,7 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
val kaptFlagsForWorker = mutableSetOf<String>().apply { val kaptFlagsForWorker = mutableSetOf<String>().apply {
if (verbose.get()) add("VERBOSE") if (verbose.get()) add("VERBOSE")
if (mapDiagnosticLocations) add("MAP_DIAGNOSTIC_LOCATIONS") 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") if (incrementalChanges is KaptIncrementalChanges.Known) add("INCREMENTAL_APT")
} }
@@ -59,7 +59,9 @@ class Android25ProjectHandler(
val preJavaClasspathKey = variantData.registerPreJavacGeneratedBytecode(preJavaKotlinOutput) val preJavaClasspathKey = variantData.registerPreJavacGeneratedBytecode(preJavaKotlinOutput)
kotlinTask.configure { kotlinTaskInstance -> kotlinTask.configure { kotlinTaskInstance ->
kotlinTaskInstance.inputs.files(variantData.getSourceFolders(SourceKind.JAVA)).withPathSensitivity(PathSensitivity.RELATIVE) kotlinTaskInstance.source(
variantData.getSourceFolders(SourceKind.JAVA)
)
kotlinTaskInstance.classpath = project.files() kotlinTaskInstance.classpath = project.files()
.from(variantData.getCompileClasspath(preJavaClasspathKey)) .from(variantData.getCompileClasspath(preJavaClasspathKey))
@@ -135,7 +135,7 @@ class AndroidSubplugin :
) )
) )
kotlinCompilation.compileKotlinTaskProvider.configure { kotlinCompilation.compileKotlinTaskProvider.configure {
it.inputs.files(getLayoutDirectories(project, sourceSet.res.srcDirs)).withPathSensitivity(PathSensitivity.RELATIVE) it.source(getLayoutDirectories(project, sourceSet.res.srcDirs))
} }
} }
@@ -14,6 +14,7 @@ import org.gradle.api.invocation.Gradle
import org.gradle.api.attributes.Attribute import org.gradle.api.attributes.Attribute
import org.gradle.api.logging.Logger import org.gradle.api.logging.Logger
import org.gradle.api.model.ObjectFactory import org.gradle.api.model.ObjectFactory
import org.gradle.api.model.ReplacedBy
import org.gradle.api.provider.ListProperty import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider 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.*
import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.api.tasks.compile.AbstractCompile
import org.gradle.api.tasks.compile.JavaCompile 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.gradle.workers.WorkerExecutor
import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS
import org.jetbrains.kotlin.build.report.metrics.* 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.daemon.common.MultiModuleICSettings
import org.jetbrains.kotlin.gradle.dsl.* import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.incremental.* 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.*
import org.jetbrains.kotlin.gradle.internal.tasks.TaskConfigurator import org.jetbrains.kotlin.gradle.internal.tasks.TaskConfigurator
import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState
@@ -74,10 +76,22 @@ abstract class AbstractKotlinCompileTool<T : CommonToolArguments>
CompilerArgumentAwareWithInput<T>, CompilerArgumentAwareWithInput<T>,
TaskWithLocalState { TaskWithLocalState {
@InputFiles @ReplacedBy("stableSources")
@PathSensitive(PathSensitivity.RELATIVE)
override fun getSource() = super.getSource() 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 @get:Input
internal var useFallbackCompilerSearch: Boolean = false internal var useFallbackCompilerSearch: Boolean = false
@@ -278,6 +292,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> : AbstractKotl
@get:InputFiles @get:InputFiles
@get:IgnoreEmptyDirectories @get:IgnoreEmptyDirectories
@get:Incremental
@get:PathSensitive(PathSensitivity.RELATIVE) @get:PathSensitive(PathSensitivity.RELATIVE)
internal val commonSourceSet: ConfigurableFileCollection = objects.fileCollection() internal val commonSourceSet: ConfigurableFileCollection = objects.fileCollection()
@@ -321,7 +336,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> : AbstractKotl
private val systemPropertiesService = CompilerSystemPropertiesService.registerIfAbsent(project.gradle) private val systemPropertiesService = CompilerSystemPropertiesService.registerIfAbsent(project.gradle)
@TaskAction @TaskAction
fun execute(inputs: IncrementalTaskInputs) { fun execute(inputChanges: InputChanges) {
metrics.measure(BuildTime.GRADLE_TASK_ACTION) { metrics.measure(BuildTime.GRADLE_TASK_ACTION) {
systemPropertiesService.get().startIntercept() systemPropertiesService.get().startIntercept()
CompilerSystemProperties.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY.value = "true" CompilerSystemProperties.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY.value = "true"
@@ -330,7 +345,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> : AbstractKotl
// then Gradle forces next build to be non-incremental (see Gradle's DefaultTaskArtifactStateRepository#persistNewOutputs) // 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 // To prevent this, we backup outputs before incremental build and restore when exception is thrown
val outputsBackup: TaskOutputsBackup? = val outputsBackup: TaskOutputsBackup? =
if (isIncrementalCompilationEnabled() && inputs.isIncremental) if (isIncrementalCompilationEnabled() && inputChanges.isIncremental)
metrics.measure(BuildTime.BACKUP_OUTPUT) { metrics.measure(BuildTime.BACKUP_OUTPUT) {
TaskOutputsBackup(allOutputFiles()) TaskOutputsBackup(allOutputFiles())
} }
@@ -338,12 +353,12 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> : AbstractKotl
if (!isIncrementalCompilationEnabled()) { if (!isIncrementalCompilationEnabled()) {
clearLocalState("IC is disabled") clearLocalState("IC is disabled")
} else if (!inputs.isIncremental) { } else if (!inputChanges.isIncremental) {
clearLocalState("Task cannot run incrementally") clearLocalState("Task cannot run incrementally")
} }
try { try {
executeImpl(inputs) executeImpl(inputChanges)
} catch (t: Throwable) { } catch (t: Throwable) {
if (outputsBackup != null) { if (outputsBackup != null) {
metrics.measure(BuildTime.RESTORE_OUTPUT_FROM_BACKUP) { metrics.measure(BuildTime.RESTORE_OUTPUT_FROM_BACKUP) {
@@ -360,13 +375,21 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> : AbstractKotl
private val projectDir = project.rootProject.projectDir private val projectDir = project.rootProject.projectDir
private fun executeImpl(inputs: IncrementalTaskInputs) { @get:Internal
protected open val incrementalProps: List<FileCollection>
get() = listOfNotNull(
stableSources,
classpath,
commonSourceSet
)
private fun executeImpl(inputChanges: InputChanges) {
val sourceRoots = getSourceRoots() val sourceRoots = getSourceRoots()
val allKotlinSources = sourceRoots.kotlinSourceFiles val allKotlinSources = sourceRoots.kotlinSourceFiles
logger.kotlinDebug { "All kotlin sources: ${allKotlinSources.pathsAsStringRelativeTo(projectDir)}" } 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. // 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" } logger.kotlinDebug { "No Kotlin files found, skipping Kotlin compiler task" }
return return
@@ -375,7 +398,33 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> : AbstractKotl
sourceRoots.log(this.name, logger) sourceRoots.log(this.name, logger)
val args = prepareCompilerArguments() val args = prepareCompilerArguments()
taskBuildDirectory.get().asFile.mkdirs() taskBuildDirectory.get().asFile.mkdirs()
callCompilerAsync(args, sourceRoots, ChangedFiles(inputs)) callCompilerAsync(
args,
sourceRoots,
getChangedFiles(inputChanges, incrementalProps)
)
}
protected fun getChangedFiles(
inputChanges: InputChanges,
incrementalProps: List<FileCollection>
) = if (!inputChanges.isIncremental) {
ChangedFiles.Unknown()
} else {
incrementalProps
.fold(mutableListOf<File>() to mutableListOf<File>()) { (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 @Internal
@@ -550,6 +599,7 @@ abstract class KotlinCompile @Inject constructor(
abstract val useClasspathSnapshot: Property<Boolean> abstract val useClasspathSnapshot: Property<Boolean>
@get:Classpath @get:Classpath
@get:Incremental
@get:Optional // Set if useClasspathSnapshot == true @get:Optional // Set if useClasspathSnapshot == true
abstract val classpathSnapshot: ConfigurableFileCollection abstract val classpathSnapshot: ConfigurableFileCollection
@@ -614,6 +664,9 @@ abstract class KotlinCompile @Inject constructor(
KotlinJvmCompilerArgumentsContributor(KotlinJvmCompilerArgumentsProvider(this)) KotlinJvmCompilerArgumentsContributor(KotlinJvmCompilerArgumentsProvider(this))
} }
override val incrementalProps: List<FileCollection>
get() = super.incrementalProps + listOf(classpathSnapshotProperties.classpathSnapshot)
override fun getSourceRoots(): SourceRoots.ForJvm = jvmSourceRoots override fun getSourceRoots(): SourceRoots.ForJvm = jvmSourceRoots
override fun callCompilerAsync(args: K2JVMCompilerArguments, sourceRoots: SourceRoots, changedFiles: ChangedFiles) { override fun callCompilerAsync(args: K2JVMCompilerArguments, sourceRoots: SourceRoots, changedFiles: ChangedFiles) {
@@ -941,6 +994,7 @@ abstract class Kotlin2JsCompile @Inject constructor(
@get:InputFiles @get:InputFiles
@get:IgnoreEmptyDirectories @get:IgnoreEmptyDirectories
@get:Incremental
@get:Optional @get:Optional
@get:PathSensitive(PathSensitivity.RELATIVE) @get:PathSensitive(PathSensitivity.RELATIVE)
internal val friendDependencies: FileCollection = objectFactory internal val friendDependencies: FileCollection = objectFactory
@@ -1015,6 +1069,9 @@ abstract class Kotlin2JsCompile @Inject constructor(
@get:Internal @get:Internal
internal val absolutePathProvider = project.projectDir.absolutePath internal val absolutePathProvider = project.projectDir.absolutePath
override val incrementalProps: List<FileCollection>
get() = super.incrementalProps + listOf(friendDependencies)
override fun callCompilerAsync(args: K2JSCompilerArguments, sourceRoots: SourceRoots, changedFiles: ChangedFiles) { override fun callCompilerAsync(args: K2JSCompilerArguments, sourceRoots: SourceRoots, changedFiles: ChangedFiles) {
sourceRoots as SourceRoots.KotlinOnly sourceRoots as SourceRoots.KotlinOnly
@@ -18,15 +18,12 @@ package org.jetbrains.kotlin.gradle.utils
import org.gradle.api.GradleException import org.gradle.api.GradleException
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.ArchiveOperations import org.gradle.api.file.ArchiveOperations
import org.gradle.api.file.CopySpec import org.gradle.api.file.CopySpec
import org.gradle.api.file.FileSystemOperations import org.gradle.api.file.FileSystemOperations
import org.gradle.api.file.FileTree import org.gradle.api.file.FileTree
import org.gradle.api.internal.project.ProjectInternal import org.gradle.api.internal.project.ProjectInternal
import org.gradle.api.internal.tasks.testing.TestDescriptorInternal 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.WorkResult
import org.gradle.api.tasks.bundling.AbstractArchiveTask import org.gradle.api.tasks.bundling.AbstractArchiveTask
import org.gradle.api.tasks.testing.TestDescriptor import org.gradle.api.tasks.testing.TestDescriptor
@@ -36,30 +33,6 @@ import java.io.Serializable
const val minSupportedGradleVersion = "6.1.1" 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( internal fun checkGradleCompatibility(
withComponent: String = "the Kotlin Gradle plugin", withComponent: String = "the Kotlin Gradle plugin",
minSupportedVersion: GradleVersion = GradleVersion.version(minSupportedGradleVersion) minSupportedVersion: GradleVersion = GradleVersion.version(minSupportedGradleVersion)