KT-45777: Clean up build cache tests for incremental compilation

- Clean up BuildCacheRelocationIT.testKotlinIncrementalCompilation
 - Delete BuildCacheIT.testKotlinCompileIncrementalBuildWithoutRelocation
   as it is already covered by the test in BuildCacheRelocationIT
 - Add BuildCacheRelocationIT.testKotlinIncrementalCompilation_withClasspathSnapshot
- Updated BuildCacheRelocationIT.testKotlinIncrementalCompilation_withClasspathSnapshot
This commit is contained in:
Hung Nguyen
2022-01-30 13:38:26 +03:00
committed by nataliya.valtman
parent 200cc9f75f
commit d018031cbf
16 changed files with 133 additions and 214 deletions
@@ -16,6 +16,7 @@ enum class BuildAttributeKind : Serializable {
}
enum class BuildAttribute(val kind: BuildAttributeKind, val readableString: String) : Serializable {
CACHE_DIRECTORY_NOT_POPULATED(BuildAttributeKind.REBUILD_REASON, "Cache directory not populated"),
NO_BUILD_HISTORY(BuildAttributeKind.REBUILD_REASON, "Build history file not found"),
NO_ABI_SNAPSHOT(BuildAttributeKind.REBUILD_REASON, "ABI snapshot not found"),
CLASSPATH_SNAPSHOT_NOT_FOUND(BuildAttributeKind.REBUILD_REASON, "Classpath snapshot not found"),
@@ -288,13 +288,13 @@ data class LookupSymbol(val name: String, val scope: String) : Comparable<Lookup
}
/**
* Wrapper of a [LookupMap] which tracks changes to the map after the initialization of this [TrackedLookupMap] instance, (unless
* Wrapper of a [LookupMap] which tracks changes to the map after the initialization of this [TrackedLookupMap] instance (unless
* [trackChanges] is set to `false`).
*/
private class TrackedLookupMap(private val lookupMap: LookupMap, private val trackChanges: Boolean) {
// Note that there may be multiple operations on the same key, and the following sets contain the *latest* differences with the original
// set of keys in the map. For example, if a key is added then removed, or vice versa, it will not be present in either set.
// Note that there may be multiple operations on the same key, and the following sets contain the *aggregated* differences with the
// original set of keys in the map. For example, if a key is added then removed, or vice versa, it will not be present in either set.
val addedKeys = if (trackChanges) mutableSetOf<LookupSymbolKey>() else null
val removedKeys = if (trackChanges) mutableSetOf<LookupSymbolKey>() else null
@@ -129,7 +129,15 @@ abstract class IncrementalCompilerRunner<
else -> providedChangedFiles
}
val compilationMode = sourcesToCompile(caches, changedFiles, args, messageCollector, classpathAbiSnapshot)
// Check whether the cache directory is populated (note that it may be deleted upon a Gradle build cache hit if the directory is
// marked as @LocalState in the Gradle task).
val cacheDirectoryNotPopulated = cacheDirectory.walk().none { it.isFile }
val compilationMode = if (cacheDirectoryNotPopulated) {
CompilationMode.Rebuild(BuildAttribute.CACHE_DIRECTORY_NOT_POPULATED)
} else {
sourcesToCompile(caches, changedFiles, args, messageCollector, classpathAbiSnapshot)
}
val exitCode = when (compilationMode) {
is CompilationMode.Incremental -> {
@@ -256,7 +256,7 @@ class IncrementalJvmCompilerRunner(
is NotAvailableDueToMissingClasspathSnapshot -> ChangesEither.Unknown(BuildAttribute.CLASSPATH_SNAPSHOT_NOT_FOUND)
is NotAvailableForNonIncrementalRun -> ChangesEither.Unknown(BuildAttribute.UNKNOWN_CHANGES_IN_GRADLE_INPUTS)
is ClasspathSnapshotDisabled -> reporter.measure(BuildTime.IC_ANALYZE_CHANGES_IN_DEPENDENCIES) {
val lastBuildInfo = BuildInfo.read(lastBuildInfoFile) ?: return CompilationMode.Rebuild(BuildAttribute.IC_IS_NOT_ENABLED)
val lastBuildInfo = BuildInfo.read(lastBuildInfoFile) ?: return CompilationMode.Rebuild(BuildAttribute.NO_BUILD_HISTORY)
reporter.reportVerbose { "Last Kotlin Build info -- $lastBuildInfo" }
val scopes = caches.lookupCache.lookupSymbols.map { it.scope.ifBlank { it.name } }.distinct()
@@ -1030,8 +1030,7 @@ fun getSomething() = 10
.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 ")
assertCompiledKotlinSources(project.relativize(androidModuleKt), output = filteredOutput)
}
}
@@ -11,26 +11,19 @@ import org.gradle.api.logging.configuration.WarningMode
import org.gradle.tooling.GradleConnector
import org.gradle.util.GradleVersion
import org.intellij.lang.annotations.Language
import org.jetbrains.kotlin.cli.common.CompilerSystemProperties.COMPILE_INCREMENTAL_WITH_ARTIFACT_TRANSFORM
import org.jetbrains.kotlin.gradle.model.ModelContainer
import org.jetbrains.kotlin.gradle.model.ModelFetcherBuildAction
import org.jetbrains.kotlin.gradle.plugin.KotlinJsCompilerType
import org.jetbrains.kotlin.gradle.report.BuildReportType
import org.jetbrains.kotlin.gradle.testbase.applyAndroidTestFixes
import org.jetbrains.kotlin.gradle.testbase.enableCacheRedirector
import org.jetbrains.kotlin.gradle.testbase.extractJavaCompiledSources
import org.jetbrains.kotlin.gradle.testbase.extractKotlinCompiledSources
import org.jetbrains.kotlin.gradle.testbase.prettyPrintXml
import org.jetbrains.kotlin.gradle.testbase.readAndCleanupTestResults
import org.jetbrains.kotlin.gradle.testbase.addPluginManagementToSettings
import org.jetbrains.kotlin.gradle.testbase.*
import org.jetbrains.kotlin.gradle.util.*
import org.jetbrains.kotlin.gradle.util.modify
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.test.RunnerWithMuteInDatabase
import org.jetbrains.kotlin.test.util.trimTrailingWhitespaces
import org.junit.After
import org.junit.AfterClass
import org.junit.Assert
import org.junit.Before
import org.junit.runner.RunWith
import java.io.File
@@ -386,14 +379,7 @@ abstract class BaseGradleIT {
}
}
class CompiledProject(val project: Project, val output: String, val resultCode: Int) {
fun getCompiledKotlinSources(output: String) =
extractKotlinCompiledSources(project.projectDir.toPath(), output).map { sourcePath -> sourcePath.toFile() }
val compiledJavaSources: Iterable<File> by lazy {
extractJavaCompiledSources(output).map { sourcePath -> sourcePath.toFile() }
}
}
class CompiledProject(val project: Project, val output: String, val resultCode: Int)
// Basically the same as `Project.build`, tells gradle to wait for debug on 5005 port
// Faster to type than `project.build("-Dorg.gradle.debug=true")` or `project.build(options = defaultBuildOptions().copy(debug = true))`
@@ -593,27 +579,6 @@ abstract class BaseGradleIT {
return map { it.canonicalFile.toRelativeString(project.projectDir) }
}
fun CompiledProject.assertSameFiles(expected: Iterable<String>, actual: Iterable<String>, messagePrefix: String): CompiledProject {
val expectedSet = expected.map { it.normalizePath() }.toSortedSet().joinToString("\n")
val actualSet = actual.map { it.normalizePath() }.toSortedSet().joinToString("\n")
Assert.assertEquals(messagePrefix, expectedSet, actualSet)
return this
}
fun CompiledProject.assertContainFiles(
expected: Iterable<String>,
actual: Iterable<String>,
messagePrefix: String = ""
): CompiledProject {
val expectedNormalized = expected.map(::normalizePath).toSortedSet()
val actualNormalized = actual.map(::normalizePath).toSortedSet()
assertTrue(
actualNormalized.containsAll(expectedNormalized),
messagePrefix + "expected files: ${expectedNormalized.joinToString()}\n !in actual files: ${actualNormalized.joinToString()}"
)
return this
}
fun CompiledProject.findTasksByPattern(pattern: String): Set<String> {
return "task '($pattern)'".toRegex().findAll(output).mapTo(HashSet()) { it.groupValues[1] }
}
@@ -778,13 +743,14 @@ Finished executing task ':$taskName'|
output: String = this.output,
suffix: String = ""
): CompiledProject {
val messagePrefix = "Compiled Kotlin files differ${suffix}:\n "
val actualSources = getCompiledKotlinSources(output).projectRelativePaths(this.project)
return if (weakTesting) {
assertContainFiles(expectedSourcesRelativePaths, actualSources, messagePrefix)
val messagePrefix = "Compiled Kotlin files differ${suffix}:\n"
val actualSources = extractCompiledKotlinFiles(output)
if (weakTesting) {
assertContainsFiles(expectedSourcesRelativePaths.toPaths(), actualSources, messagePrefix)
} else {
assertSameFiles(expectedSourcesRelativePaths, actualSources, messagePrefix)
assertSameFiles(expectedSourcesRelativePaths.toPaths(), actualSources, messagePrefix)
}
return this
}
fun CompiledProject.assertCompiledKotlinFiles(expectedFiles: Iterable<File>): CompiledProject =
@@ -799,11 +765,15 @@ Finished executing task ':$taskName'|
fun CompiledProject.assertCompiledJavaSources(
sources: Iterable<String>,
weakTesting: Boolean = false
): CompiledProject =
): CompiledProject {
val messagePrefix = "Compiled Java files differ:\n"
val actualSources = extractCompiledJavaFiles(project.projectDir, output)
if (weakTesting)
assertContainFiles(sources, compiledJavaSources.projectRelativePaths(this.project), "Compiled Java files differ:\n ")
assertContainsFiles(sources.toPaths(), actualSources, messagePrefix)
else
assertSameFiles(sources, compiledJavaSources.projectRelativePaths(this.project), "Compiled Java files differ:\n ")
assertSameFiles(sources.toPaths(), actualSources, messagePrefix)
return this
}
fun Project.resourcesDir(subproject: String? = null, sourceSet: String = "main"): String =
(subproject?.plus("/") ?: "") + "build/resources/$sourceSet/"
@@ -904,7 +874,7 @@ Finished executing task ':$taskName'|
options.incrementalJsKlib?.let { add("-Pkotlin.incremental.js.klib=$it") }
options.jsIrBackend?.let { add("-Pkotlin.js.useIrBackend=$it") }
options.usePreciseJavaTracking?.let { add("-Pkotlin.incremental.usePreciseJavaTracking=$it") }
options.useClasspathSnapshot?.let { add("-Pkotlin.incremental.useClasspathSnapshot=$it") }
options.useClasspathSnapshot?.let { add("-P${COMPILE_INCREMENTAL_WITH_ARTIFACT_TRANSFORM.property}=$it") }
options.androidGradlePluginVersion?.let { add("-Pandroid_tools_version=$it") }
if (options.debug) {
add("-Dorg.gradle.debug=true")
@@ -103,33 +103,6 @@ class BuildCacheIT : KGPBaseTest() {
}
}
@DisplayName("Incremental compilation works with cache")
@GradleTest
fun testKotlinCompileIncrementalBuildWithoutRelocation(gradleVersion: GradleVersion) {
project("buildCacheSimple", gradleVersion) {
enableLocalBuildCache(localBuildCacheDir)
build("assemble") {
assertTasksPackedToCache(":compileKotlin")
}
build("clean", "assemble") {
assertTasksFromCache(":compileKotlin")
}
val fooKtSourceFile = kotlinSourcesDir().resolve("foo.kt")
fooKtSourceFile.modify { it.replace("Int = 1", "String = \"abc\"") }
build("assemble") {
assertIncrementalCompilation(modifiedFiles = setOf(fooKtSourceFile))
}
fooKtSourceFile.modify { it.replace("String = \"abc\"", "Int = 1") }
build("clean", "assemble") {
assertTasksFromCache(":compileKotlin")
}
}
}
@DisplayName("Debug log level should not break build cache")
@GradleTest
fun testDebugLogLevelCaching(gradleVersion: GradleVersion) {
@@ -16,11 +16,13 @@
package org.jetbrains.kotlin.gradle
import org.gradle.api.logging.LogLevel
import org.gradle.api.logging.configuration.WarningMode
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.testbase.*
import org.junit.jupiter.api.DisplayName
import kotlin.io.path.createDirectory
import kotlin.io.path.pathString
@DisplayName("Build cache relocation")
@SimpleGradlePluginTests
@@ -260,20 +262,6 @@ class BuildCacheRelocationIT : KGPBaseTest() {
)
}
@DisplayName("Incremental compilation build cache does not break relocated cache")
@GradleTest
fun testKotlinCompileCachingIncrementalBuildWithRelocation(gradleVersion: GradleVersion) {
val firstProject = project("buildCacheSimple", gradleVersion) {
enableLocalBuildCache(localBuildCacheDir)
}
val secondProject = project("buildCacheSimple", gradleVersion) {
enableLocalBuildCache(localBuildCacheDir)
}
checkKotlinCompileCachingIncrementalBuild(firstProject, secondProject)
}
@DisplayName("Kapt incremental compilation works with cache")
@GradleTest
fun testKaptCachingIncrementalBuildWithoutRelocation(gradleVersion: GradleVersion) {
@@ -332,10 +320,22 @@ class BuildCacheRelocationIT : KGPBaseTest() {
}
}
private fun checkKotlinCompileCachingIncrementalBuild(
firstProject: TestProject,
secondProject: TestProject
) {
@DisplayName("Kotlin incremental compilation should work correctly")
@GradleTest
fun testKotlinIncrementalCompilation(gradleVersion: GradleVersion) {
checkKotlinIncrementalCompilation(gradleVersion)
}
@DisplayName("Kotlin incremental compilation with `kotlin.incremental.useClasspathSnapshot` feature should work correctly")
@GradleTest
fun testKotlinIncrementalCompilation_withClasspathSnapshot(gradleVersion: GradleVersion) {
checkKotlinIncrementalCompilation(gradleVersion, useClasspathSnapshot = true)
}
private fun checkKotlinIncrementalCompilation(gradleVersion: GradleVersion, useClasspathSnapshot: Boolean? = null) {
val buildOptions = defaultBuildOptions.copy(useClasspathSnapshot = useClasspathSnapshot)
val (firstProject, secondProject) = prepareTestProjects("buildCacheSimple", gradleVersion, buildOptions)
// First build, should be stored into the build cache:
firstProject.build("assemble") {
assertTasksPackedToCache(":compileKotlin")
@@ -348,9 +348,12 @@ class BuildCacheRelocationIT : KGPBaseTest() {
// Change the return type of foo() from Int to String in foo.kt, and check that fooUsage.kt is recompiled as well:
val fooKtSourceFile = secondProject.kotlinSourcesDir().resolve("foo.kt")
val fooUsageKtSourceFile = secondProject.kotlinSourcesDir().resolve("fooUsage.kt")
fooKtSourceFile.modify { it.replace("Int = 1", "String = \"abc\"") }
secondProject.build("assemble") {
assertIncrementalCompilation(modifiedFiles = setOf(fooKtSourceFile))
secondProject.build("assemble", buildOptions = buildOptions.copy(logLevel = LogLevel.DEBUG)) {
assertIncrementalCompilation(
listOf(fooKtSourceFile, fooUsageKtSourceFile).relativizeTo(secondProject.projectPath).map { it.pathString }
)
}
// Revert the change to the return type of foo(), and check if we get a cache hit
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle.testbase
import org.gradle.api.logging.LogLevel
import org.gradle.api.logging.configuration.WarningMode
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.cli.common.CompilerSystemProperties.COMPILE_INCREMENTAL_WITH_ARTIFACT_TRANSFORM
import org.jetbrains.kotlin.gradle.BaseGradleIT
import org.jetbrains.kotlin.gradle.plugin.KotlinJsCompilerType
import org.jetbrains.kotlin.gradle.report.BuildReportType
@@ -21,6 +22,7 @@ data class BuildOptions(
val configurationCacheProblems: BaseGradleIT.ConfigurationCacheProblems = BaseGradleIT.ConfigurationCacheProblems.FAIL,
val parallel: Boolean = true,
val incremental: Boolean? = null,
val useClasspathSnapshot: Boolean? = null,
val maxWorkers: Int = (Runtime.getRuntime().availableProcessors() / 4 - 1).coerceAtLeast(2),
val fileSystemWatchEnabled: Boolean = false,
val buildCacheEnabled: Boolean = false,
@@ -81,6 +83,8 @@ data class BuildOptions(
arguments.add("-Pkotlin.incremental=$incremental")
}
useClasspathSnapshot?.let { arguments.add("-P${COMPILE_INCREMENTAL_WITH_ARTIFACT_TRANSFORM.property}=$it") }
if (gradleVersion >= GradleVersion.version("6.5")) {
if (fileSystemWatchEnabled) {
arguments.add("--watch-fs")
@@ -5,14 +5,16 @@
package org.jetbrains.kotlin.gradle.testbase
import java.nio.file.Path
import java.nio.file.Paths
import kotlin.io.path.relativeTo
import org.gradle.api.logging.LogLevel
import org.gradle.testkit.runner.BuildResult
import org.intellij.lang.annotations.Language
import java.io.File
import java.nio.file.Path
import java.nio.file.Paths
private val kotlinSrcRegex by lazy { Regex("\\[KOTLIN\\] compile iteration: ([^\\r\\n]*)") }
private val kotlinSrcRegex by lazy { Regex("\\[KOTLIN] compile iteration: ([^\\r\\n]*)") }
private val javaSrcRegex by lazy { Regex("\\[DEBUG] \\[[^]]*JavaCompiler] Compiler arguments: ([^\\r\\n]*)") }
@Language("RegExp")
private fun taskOutputRegex(
@@ -42,45 +44,56 @@ fun BuildResult.getOutputForTask(taskName: String): String = taskOutputRegex(tas
?: error("Could not find output for task $taskName")
/**
* Extracts list of compiled .kt files from task output
* Extracts the list of compiled .kt files from the build output.
*
* Note: log level of output should be set to [LogLevel.DEBUG]
* The returned paths are relative to the project directory.
*
* Note: Log level of output must be set to [LogLevel.DEBUG].
*/
fun extractKotlinCompiledSources(projectDirectory: Path, output: String) =
kotlinSrcRegex.findAll(output)
.asIterable()
.flatMap { result ->
result.groups[1]!!.value.split(", ")
.map { source -> projectDirectory.resolve(source).normalize() }
}
private val javaSrcRegex by lazy { Regex("\\[DEBUG\\] \\[[^\\]]*JavaCompiler\\] Compiler arguments: ([^\\r\\n]*)") }
fun extractCompiledKotlinFiles(output: String): List<Path> {
return kotlinSrcRegex.findAll(output).asIterable()
.flatMap { matchResult -> matchResult.groups[1]!!.value.split(", ") }
.toPaths()
}
/**
* Extracts list of compiled .java files from task output
* Extracts the list of compiled .java files from the build output.
*
* Note: log level of output should be set to [LogLevel.DEBUG]
* The returned paths are relative to the project directory.
*
* Note: Log level of output must be set to [LogLevel.DEBUG].
*/
fun extractJavaCompiledSources(output: String): List<Path> =
javaSrcRegex.findAll(output).asIterable().flatMap {
it.groups[1]!!.value
.split(" ")
.filter { source -> source.endsWith(".java", ignoreCase = true) }
.map { source -> Paths.get(source).normalize() }
}
fun extractCompiledJavaFiles(projectDir: File, output: String): List<Path> {
return javaSrcRegex.findAll(output).asIterable()
.flatMap { matchResult -> matchResult.groups[1]!!.value.split(" ") }
.filter { filePath -> filePath.endsWith(".java", ignoreCase = true) }
.map { javaFilePath -> projectDir.toPath().relativize(Paths.get(javaFilePath)) }
}
/**
* Asserts all the .kt files from [expectedSources] and only they are compiled
*
* Note: log level of output should be set to [LogLevel.DEBUG]
*/
fun GradleProject.assertCompiledKotlinSources(
fun assertCompiledKotlinSources(
expectedSources: Iterable<Path>,
output: String,
errorMessageSuffix: String = ""
) {
val actualSources = extractKotlinCompiledSources(projectPath, output).map {
it.relativeTo(projectPath)
}
val actualSources = extractCompiledKotlinFiles(output)
assertSameFiles(expectedSources, actualSources, "Compiled Kotlin files differ${errorMessageSuffix}:\n")
}
}
/**
* Asserts that compilation was incremental and the set of compiled .kt files exactly match [expectedCompiledKotlinFiles].
*
* [expectedCompiledKotlinFiles] are relative to the project directory.
*
* Note: Log level of output must be set to [LogLevel.DEBUG].
*/
fun BuildResult.assertIncrementalCompilation(expectedCompiledKotlinFiles: Iterable<String>) {
assertOutputDoesNotContain("Non-incremental compilation will be performed")
val actualCompiledKotlinFiles = extractCompiledKotlinFiles(output)
assertSameFiles(expectedCompiledKotlinFiles.toPaths(), actualCompiledKotlinFiles, "Compiled Kotlin files differ:\n")
}
@@ -55,7 +55,7 @@ fun TestProject.assertSimpleConfigurationCacheScenarioWorks(
*/
@OptIn(ExperimentalPathApi::class)
private fun copyReportToTempDir(htmlReportFile: Path): Path =
createTempDir("report").let { tempDir ->
createTempDirDeleteOnExit("report").let { tempDir ->
htmlReportFile.parent.toFile().copyRecursively(tempDir.toFile())
tempDir.resolve(htmlReportFile.name)
}
@@ -10,7 +10,7 @@ import java.nio.file.Path
import kotlin.io.path.exists
import kotlin.io.path.isDirectory
import kotlin.io.path.readText
import kotlin.test.assertEquals
import kotlin.test.asserter
/**
* Asserts file under [file] path exists and is a regular file.
@@ -189,8 +189,24 @@ fun GradleProject.assertFileDoesNotContain(
}
}
fun GradleProject.assertSameFiles(expected: Iterable<Path>, actual: Iterable<Path>, messagePrefix: String) {
val expectedSet = expected.map { it.toString().normalizePath() }.toSortedSet().joinToString("\n")
val actualSet = actual.map { it.toString().normalizePath() }.toSortedSet().joinToString("\n")
assertEquals(expectedSet, actualSet, messagePrefix)
}
fun assertSameFiles(expected: Iterable<Path>, actual: Iterable<Path>, messagePrefix: String) {
val expectedSet = expected.map { it.toString().normalizePath() }.toSet()
val actualSet = actual.map { it.toString().normalizePath() }.toSet()
asserter.assertTrue(lazyMessage = {
messagePrefix +
"Actual set does not exactly match expected set.\n" +
"Expected set: ${expectedSet.sorted().joinToString(", ")}\n" +
"Actual set: ${actualSet.sorted().joinToString(", ")}\n"
}, actualSet.size == expectedSet.size && actualSet.containsAll(expectedSet))
}
fun assertContainsFiles(expected: Iterable<Path>, actual: Iterable<Path>, messagePrefix: String) {
val expectedSet = expected.map { it.toString().normalizePath() }.toSet()
val actualSet = actual.map { it.toString().normalizePath() }.toSet()
asserter.assertTrue(lazyMessage = {
messagePrefix +
"Actual set does not contain all of expected set.\n" +
"Expected set: ${expectedSet.sorted().joinToString(", ")}\n" +
"Actual set: ${actualSet.sorted().joinToString(", ")}\n"
}, actualSet.containsAll(expectedSet))
}
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.gradle.testbase
import org.gradle.testkit.runner.BuildResult
import java.nio.file.Path
/**
* Asserts Gradle output contains [expectedSubString] string.
@@ -127,70 +126,6 @@ fun BuildResult.assertNoBuildWarnings(
}
}
fun BuildResult.assertIncrementalCompilation(
modifiedFiles: Set<Path> = emptySet(),
deletedFiles: Set<Path> = emptySet()
) {
val incrementalCompilationOptions = output
.lineSequence()
.filter { it.trim().startsWith("Options for KOTLIN DAEMON: IncrementalCompilationOptions(") }
.map {
it
.removePrefix("Options for KOTLIN DAEMON: IncrementalCompilationOptions(")
.removeSuffix(")")
}
.toList()
assert(incrementalCompilationOptions.isNotEmpty()) {
printBuildOutput()
"No incremental compilation options were found in the build"
}
val modifiedFilesPath = modifiedFiles.map { it.toAbsolutePath().toString() }
val deletedFilesPath = deletedFiles.map { it.toAbsolutePath().toString() }
val hasMatch = incrementalCompilationOptions
.firstOrNull {
val optionModifiedFiles = it
.substringAfter("modifiedFiles=[")
.substringBefore("]")
.split(",")
.filter(String::isNotEmpty)
val modifiedFilesFound = if (modifiedFilesPath.isEmpty()) {
optionModifiedFiles.isEmpty()
} else {
modifiedFilesPath.subtract(optionModifiedFiles).isEmpty()
}
val optionDeletedFiles = it
.substringAfter("deletedFiles=[")
.substringBefore("]")
.split(",")
.filter(String::isNotEmpty)
val deletedFilesFound = if (deletedFilesPath.isEmpty()) {
optionDeletedFiles.isEmpty()
} else {
deletedFilesPath.subtract(optionDeletedFiles).isEmpty()
}
modifiedFilesFound && deletedFilesFound
} != null
assert(hasMatch) {
printBuildOutput()
"""
|Expected incremental compilation options with:
|- modified files: ${modifiedFilesPath.joinToString()}
|- deleted files: ${deletedFilesPath.joinToString()}
|
|but none of following compilation options match:
|${incrementalCompilationOptions.joinToString(separator = "\n")}
""".trimMargin()
}
}
/**
* Asserts compilation is running via Kotlin daemon with given jvm arguments.
*/
@@ -6,10 +6,7 @@
package org.jetbrains.kotlin.gradle.testbase
import java.io.IOException
import java.nio.file.FileVisitResult
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.SimpleFileVisitor
import java.nio.file.*
import java.nio.file.attribute.BasicFileAttributes
import kotlin.io.path.*
import kotlin.streams.asSequence
@@ -50,7 +47,7 @@ internal val Path.allJavaSources: List<Path>
*
* Prefer using JUnit5 `@TempDir` over this method when possible.
*/
internal fun createTempDir(prefix: String): Path = Files
internal fun createTempDirDeleteOnExit(prefix: String): Path = Files
.createTempDirectory(prefix)
.apply { toFile().deleteOnExit() }
@@ -108,3 +105,5 @@ internal fun Path.deleteRecursively() {
}
})
}
internal fun Iterable<String>.toPaths(): List<Path> = map { Paths.get(it) }
@@ -5,10 +5,8 @@
package org.jetbrains.kotlin.gradle.util
import org.jetbrains.kotlin.gradle.testbase.createTempDirDeleteOnExit
import java.io.File
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.relativeTo
fun File.getFileByName(name: String): File =
findFileByName(name) ?: throw AssertionError("Could not find file with name '$name' in $this")
@@ -36,10 +34,7 @@ fun File.addNewLine() {
modify { "$it\n" }
}
fun createTempDir(prefix: String): File =
Files.createTempDirectory(prefix).toFile().apply {
deleteOnExit()
}
fun createTempDir(prefix: String): File = createTempDirDeleteOnExit(prefix).toFile()
/**
* converts back slashes to forward slashes
@@ -0,0 +1,3 @@
// This class is used so that the set of compiled source files in an incremental compilation is a proper subset of the set of compiled
// source files in a non-incremental compilation, so that the two cases are not ambiguous when we check the set of compiled source files.
class StandAloneClass