Ensure kapt tasks don't capture sources state in configuration cache.
Kapt tasks have captured sources state inside SourceRoots container internal collection, that was cached by configuration cache. This lead to the compilation errors whenever sources files were changed (deleted or renamed), because kapt still expected previous file state to exist. Now SourceRoots will not create internal collection, but rather reuse standard Gradle FileCollection methods that perform required calculations dynamically. ^KT-46651 Fixed
This commit is contained in:
+34
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle
|
||||
|
||||
import org.gradle.api.logging.LogLevel
|
||||
import org.gradle.api.logging.configuration.WarningMode
|
||||
import org.jetbrains.kotlin.gradle.tasks.USING_JVM_INCREMENTAL_COMPILATION_MESSAGE
|
||||
import org.jetbrains.kotlin.gradle.util.*
|
||||
@@ -783,4 +784,37 @@ open class Kapt3IT : Kapt3BaseIT() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// https://youtrack.jetbrains.com/issue/KT-46651
|
||||
@Test
|
||||
fun kaptGenerateStubsShouldNotCaptureSourcesStateInConfigurationCache() {
|
||||
with(
|
||||
Project(
|
||||
"incrementalRebuild",
|
||||
directoryPrefix = "kapt2",
|
||||
gradleVersionRequirement = GradleVersionRequired.AtLeast("6.7.1"),
|
||||
minLogLevel = LogLevel.INFO
|
||||
)
|
||||
) {
|
||||
setupWorkingDir()
|
||||
val buildOptions = defaultBuildOptions().copy(
|
||||
configurationCache = true
|
||||
)
|
||||
|
||||
build("assemble", options = buildOptions) {
|
||||
assertSuccessful()
|
||||
}
|
||||
|
||||
projectDir.resolve("src/main/java/bar/UseBar.kt").apply {
|
||||
modify {
|
||||
it.replace("UseBar", "UseBar1")
|
||||
}
|
||||
renameTo(parentFile.resolve("UseBar1.kt"))
|
||||
}
|
||||
|
||||
build("assemble", options = buildOptions) {
|
||||
assertSuccessful()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -57,8 +57,8 @@ abstract class KaptGenerateStubsTask : KotlinCompile(KotlinJvmOptionsImpl()) {
|
||||
providerFactory.provider {
|
||||
kotlinCompileTask.getSourceRoots().let { compileTaskSourceRoots ->
|
||||
SourceRoots.ForJvm(
|
||||
compileTaskSourceRoots.kotlinSourceFiles.filterTo(mutableListOf()) { task.isSourceRootAllowed(it) },
|
||||
javaSourceRootsProvider = { compileTaskSourceRoots.javaSourceRoots.filterTo(mutableSetOf()) { task.isSourceRootAllowed(it) } }
|
||||
compileTaskSourceRoots.kotlinSourceFiles.filter { task.isSourceRootAllowed(it) },
|
||||
compileTaskSourceRoots.javaSourceRoots.filter { task.isSourceRootAllowed(it) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -127,6 +127,6 @@ abstract class KotlinCompileCommon @Inject constructor(
|
||||
reportingSettings = reportingSettings,
|
||||
outputFiles = allOutputFiles()
|
||||
)
|
||||
compilerRunner.runMetadataCompilerAsync(sourceRoots.kotlinSourceFiles, args, environment)
|
||||
compilerRunner.runMetadataCompilerAsync(sourceRoots.kotlinSourceFiles.files.toList(), args, environment)
|
||||
}
|
||||
}
|
||||
|
||||
+27
-31
@@ -11,62 +11,58 @@ import org.jetbrains.kotlin.gradle.utils.isJavaFile
|
||||
import org.jetbrains.kotlin.gradle.utils.isKotlinFile
|
||||
import org.jetbrains.kotlin.gradle.utils.isParentOf
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import java.util.concurrent.Callable
|
||||
|
||||
internal sealed class SourceRoots(val kotlinSourceFiles: List<File>) {
|
||||
internal sealed class SourceRoots(val kotlinSourceFiles: FileCollection) {
|
||||
private companion object {
|
||||
fun dumpPaths(files: Iterable<File>): String =
|
||||
"[${files.map { it.canonicalPath }.sorted().joinToString(prefix = "\n\t", separator = ",\n\t")}]"
|
||||
}
|
||||
|
||||
open fun log(taskName: String, logger: Logger) {
|
||||
logger.kotlinDebug { "$taskName source roots: ${dumpPaths(kotlinSourceFiles)}" }
|
||||
logger.kotlinDebug { "$taskName source roots: ${dumpPaths(kotlinSourceFiles.files)}" }
|
||||
}
|
||||
|
||||
class ForJvm constructor(
|
||||
kotlinSourceFiles: List<File>,
|
||||
private val javaSourceRootsProvider: () -> Set<File>
|
||||
kotlinSourceFiles: FileCollection,
|
||||
val javaSourceRoots: FileCollection
|
||||
) : SourceRoots(kotlinSourceFiles) {
|
||||
val javaSourceRoots: Set<File>
|
||||
get() = javaSourceRootsProvider()
|
||||
|
||||
constructor(kotlinSourceFiles: List<File>, allSourceRoots: FileCollection, taskSource: FileCollection) : this(kotlinSourceFiles, {
|
||||
findRootsForSources(allSourceRoots, taskSource.filter(File::isJavaFile)).toSet()
|
||||
})
|
||||
|
||||
companion object {
|
||||
fun create(taskSource: FileTree, sourceRoots: FilteringSourceRootsContainer, sourceFilesExtensions: List<String>): ForJvm {
|
||||
val kotlinSourceFiles = (taskSource as Iterable<File>).filter { it.isKotlinFile(sourceFilesExtensions) }
|
||||
return ForJvm(kotlinSourceFiles, sourceRoots.sourceRoots, taskSource)
|
||||
fun create(
|
||||
taskSource: FileTree,
|
||||
sourceRoots: FilteringSourceRootsContainer,
|
||||
sourceFilesExtensions: List<String>
|
||||
): ForJvm {
|
||||
return ForJvm(
|
||||
taskSource.filter { it.isKotlinFile(sourceFilesExtensions) },
|
||||
sourceRoots.sourceRoots.filterJavaRoots(
|
||||
taskSource.filter { it.isJavaFile() }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun findRootsForSources(allSourceRoots: Iterable<File>, sources: Iterable<File>): Set<File> {
|
||||
val resultRoots = HashSet<File>()
|
||||
val sourceDirs = sources.mapTo(HashSet()) { it.parentFile }
|
||||
|
||||
for (sourceDir in sourceDirs) {
|
||||
for (sourceRoot in allSourceRoots) {
|
||||
if (sourceRoot.isParentOf(sourceDir)) {
|
||||
resultRoots.add(sourceRoot)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resultRoots
|
||||
private fun FileCollection.filterJavaRoots(
|
||||
sourceDirs: FileCollection
|
||||
): FileCollection = filter { sourceRoot ->
|
||||
sourceDirs.asSequence().map { it.parentFile }.any { sourceRoot.isParentOf(it) }
|
||||
}
|
||||
}
|
||||
|
||||
override fun log(taskName: String, logger: Logger) {
|
||||
super.log(taskName, logger)
|
||||
logger.kotlinDebug { "$taskName java source roots: ${dumpPaths(javaSourceRoots)}" }
|
||||
logger.kotlinDebug { "$taskName java source roots: ${dumpPaths(javaSourceRoots.files)}" }
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinOnly(kotlinSourceFiles: List<File>) : SourceRoots(kotlinSourceFiles) {
|
||||
class KotlinOnly(kotlinSourceFiles: FileCollection) : SourceRoots(kotlinSourceFiles) {
|
||||
companion object {
|
||||
fun create(taskSource: FileTree, sourceFilesExtensions: List<String>) =
|
||||
KotlinOnly((taskSource as Iterable<File>).filter { it.isKotlinFile(sourceFilesExtensions) })
|
||||
fun create(
|
||||
taskSource: FileTree,
|
||||
sourceFilesExtensions: List<String>
|
||||
) = KotlinOnly(
|
||||
taskSource.filter { it.isKotlinFile(sourceFilesExtensions) }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-2
@@ -490,7 +490,7 @@ abstract class KotlinCompile @Inject constructor(
|
||||
kotlinScriptExtensions = sourceFilesExtensions.get().toTypedArray()
|
||||
)
|
||||
compilerRunner.runJvmCompilerAsync(
|
||||
sourceRoots.kotlinSourceFiles,
|
||||
sourceRoots.kotlinSourceFiles.files.toList(),
|
||||
commonSourceSet.toList(),
|
||||
sourceRoots.javaSourceRoots,
|
||||
javaPackagePrefix,
|
||||
@@ -799,7 +799,12 @@ abstract class Kotlin2JsCompile @Inject constructor(
|
||||
reportingSettings = reportingSettings,
|
||||
incrementalCompilationEnvironment = icEnv
|
||||
)
|
||||
compilerRunner.runJsCompilerAsync(sourceRoots.kotlinSourceFiles, commonSourceSet.toList(), args, environment)
|
||||
compilerRunner.runJsCompilerAsync(
|
||||
sourceRoots.kotlinSourceFiles.files.toList(),
|
||||
commonSourceSet.toList(),
|
||||
args,
|
||||
environment
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user