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 ee03b3a1dd1..03d84c7d7fa 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 @@ -286,7 +286,12 @@ abstract class BaseGradleIT { build(*params, options = options.copy(kotlinDaemonDebugPort = debugPort), check = check) } - fun Project.build(vararg params: String, options: BuildOptions = defaultBuildOptions(), check: CompiledProject.() -> Unit) { + fun Project.build( + vararg params: String, + options: BuildOptions = defaultBuildOptions(), + projectDir: File = File(workingDir, projectName), + check: CompiledProject.() -> Unit + ) { val wrapperVersion = chooseWrapperVersionOrFinishTest() val env = createEnvironmentVariablesMap(options) @@ -295,7 +300,6 @@ abstract class BaseGradleIT { println("<=== Test build: ${this.projectName} $cmd ===>") - val projectDir = File(workingDir, projectName) if (!projectDir.exists()) { setupWorkingDir() } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BuildCacheIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BuildCacheIT.kt index 162d1fdb1fb..55c2218fa4f 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BuildCacheIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BuildCacheIT.kt @@ -135,34 +135,33 @@ class BuildCacheIT : BaseGradleIT() { } @Test - fun testKaptCachingEnabledByDefault() = with(Project("simple", GRADLE_VERSION, directoryPrefix = "kapt2")) { - prepareLocalBuildCache() + fun testKaptCachingWithIncrementalApt() { + with(Project("kaptAvoidance", GRADLE_VERSION, directoryPrefix = "kapt2")) { + prepareLocalBuildCache() - build("clean", "build") { - assertSuccessful() - assertContains("Packing task ':kaptGenerateStubsKotlin'") - assertContains("Packing task ':kaptKotlin'") - } - - build("clean", "build") { - assertSuccessful() - assertContains(":kaptGenerateStubsKotlin FROM-CACHE") - assertContains(":kaptKotlin FROM-CACHE") - } - - File(projectDir, "build.gradle").appendText( - "\n" + """ - afterEvaluate { - kaptKotlin.useBuildCache = false + val options = defaultBuildOptions().copy( + kaptOptions = KaptOptions( + verbose = true, + useWorkers = false, + incrementalKapt = true, + includeCompileClasspath = false + ) + ) + build(options = options, params = *arrayOf("clean", ":app:build")) { + assertSuccessful() + assertContains("Packing task ':app:kaptGenerateStubsKotlin'") + assertContains("Packing task ':app:kaptKotlin'") } - """.trimIndent() - ) - build("clean", "build") { - assertSuccessful() - assertContains(":kaptGenerateStubsKotlin FROM-CACHE") - assertNotContains(":kaptKotlin FROM-CACHE") - assertContains("Caching disabled for task ':kaptKotlin': 'Caching is disabled for kapt") + // copy project to a new location + val copyProject = projectDir.resolveSibling("copy_${projectDir.name}").also { it.mkdirs() } + copyRecursively(projectDir, copyProject) + + build(options = options, projectDir = copyProject.resolve(projectName), params = *arrayOf("clean", "build")) { + assertSuccessful() + assertContains(":app:kaptGenerateStubsKotlin FROM-CACHE") + assertContains(":app:kaptKotlin FROM-CACHE") + } } } } 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 d1d050b82a5..3010a3dd6fe 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 @@ -6,8 +6,8 @@ import org.gradle.api.file.FileCollection import org.gradle.api.internal.ConventionTask import org.gradle.api.tasks.* import org.gradle.api.tasks.incremental.IncrementalTaskInputs -import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptClasspathChanges import org.jetbrains.kotlin.gradle.internal.kapt.incremental.ClasspathSnapshot +import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptClasspathChanges import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptIncrementalChanges import org.jetbrains.kotlin.gradle.internal.kapt.incremental.UnknownSnapshot import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState @@ -171,21 +171,21 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { clearLocalState() return KaptIncrementalChanges.Unknown } + val allDataFiles = classpathStructure!!.files if (!inputs.isIncremental) { clearLocalState() - findClasspathChanges(classpath.files) + findClasspathChanges(allDataFiles, allDataFiles) return KaptIncrementalChanges.Unknown } val changedFiles = with(mutableSetOf()) { inputs.outOfDate { this.add(it.file) } inputs.removed { this.add(it.file) } - return@with this.toList() + return@with this } - val classpathChanges = classpath.files.let { cp -> changedFiles.filter { cp.contains(it) } } - - val classpathStatus = findClasspathChanges(classpathChanges) + val changedDataFiles = allDataFiles.filterTo(HashSet()) { it in changedFiles } + val classpathStatus = findClasspathChanges(allDataFiles, changedDataFiles) return when (classpathStatus) { is KaptClasspathChanges.Unknown -> KaptIncrementalChanges.Unknown is KaptClasspathChanges.Known -> KaptIncrementalChanges.Known( @@ -194,18 +194,17 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { } } - private fun findClasspathChanges(changedClasspath: Iterable): KaptClasspathChanges { + private fun findClasspathChanges(allDataFile: Set, changedDataFiles: Set): KaptClasspathChanges { val incAptCacheDir = incAptCache!! incAptCacheDir.mkdirs() val startTime = System.currentTimeMillis() val previousSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.loadFrom(incAptCacheDir) - val currentSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent( - incAptCacheDir, classpath.files.toList(), classpathStructure!!.files - ) + val currentSnapshot = + ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(incAptCacheDir, classpath.files.toList(), allDataFile) - val classpathChanges = currentSnapshot.diff(previousSnapshot, changedClasspath.toSet()) + val classpathChanges = currentSnapshot.diff(previousSnapshot, changedDataFiles) currentSnapshot.writeToCache() if (logger.isInfoEnabled) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/incremental/ClasspathAnalyzer.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/incremental/ClasspathAnalyzer.kt index ce5c6b80e6b..7b33aa7fd09 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/incremental/ClasspathAnalyzer.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/incremental/ClasspathAnalyzer.kt @@ -26,10 +26,7 @@ class StructureArtifactTransform : ArtifactTransform() { val dataFile = outputDirectory.resolve("output.bin") data.saveTo(dataFile) - val lazyStructureFile = outputDirectory.resolve("lazy-output.bin") - LazyClasspathEntryData(input, dataFile).saveToFile(lazyStructureFile) - - return mutableListOf(lazyStructureFile) + return mutableListOf(dataFile) } catch (e: Throwable) { throw e } @@ -86,25 +83,6 @@ private fun analyzeInputStream(input: InputStream, internalName: String, entryDa ClassDependencies(typeDependenciesExtractor.getAbiTypes(), typeDependenciesExtractor.getPrivateTypes()) } -class LazyClasspathEntryData(val classpathEntry: File, private val dataFile: File) : Serializable { - - object LazyClasspathEntrySerializer { - fun loadFromFile(file: File): LazyClasspathEntryData { - ObjectInputStream(BufferedInputStream(file.inputStream())).use { - return it.readObject() as LazyClasspathEntryData - } - } - } - - fun saveToFile(file: File) { - ObjectOutputStream(BufferedOutputStream(file.outputStream())).use { - it.writeObject(this) - } - } - - fun getClasspathEntryData(): ClasspathEntryData = ClasspathEntryData.ClasspathEntrySerializer.loadFrom(dataFile) -} - class ClasspathEntryData : Serializable { object ClasspathEntrySerializer { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/incremental/ClasspathSnapshot.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/incremental/ClasspathSnapshot.kt index fe44f91156a..5e177539fd7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/incremental/ClasspathSnapshot.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/incremental/ClasspathSnapshot.kt @@ -7,61 +7,46 @@ package org.jetbrains.kotlin.gradle.internal.kapt.incremental import java.io.* import java.util.* +import kotlin.collections.HashMap + +private const val CLASSPATH_ENTRIES_FILE = "classpath-entries.bin" +private const val CLASSPATH_STRUCTURE_FILE = "classpath-structure.bin" open class ClasspathSnapshot protected constructor( private val cacheDir: File, - private val classpath: Iterable, - val dataForFiles: (Set) -> Map + private val classpath: List, + private val dataForFiles: MutableMap ) { - val classpathData: (Set) -> Map = { files -> - val missingFiles = files.filter { !computedClasspathData.keys.contains(it) }.toSet() - - if (!missingFiles.isEmpty()) { - val computedData = dataForFiles(missingFiles) - computedClasspathData.putAll(computedData) - } - computedClasspathData - } - private val computedClasspathData: MutableMap = mutableMapOf() - object ClasspathSnapshotFactory { fun loadFrom(cacheDir: File): ClasspathSnapshot { - val classpathEntries = cacheDir.resolve("classpath-entries.bin") - val classpathStructureData = cacheDir.resolve("classpath-structure.bin") + val classpathEntries = cacheDir.resolve(CLASSPATH_ENTRIES_FILE) + val classpathStructureData = cacheDir.resolve(CLASSPATH_STRUCTURE_FILE) if (!classpathEntries.exists() || !classpathStructureData.exists()) { return UnknownSnapshot } val classpathFiles = ObjectInputStream(BufferedInputStream(classpathEntries.inputStream())).use { @Suppress("UNCHECKED_CAST") - it.readObject() as Iterable + it.readObject() as List } - val classpathData = { _: Set -> - loadPreviousData(classpathStructureData) - } - return ClasspathSnapshot(cacheDir, classpathFiles, classpathData) + val dataForFiles = + ObjectInputStream(BufferedInputStream(classpathStructureData.inputStream())).use { + @Suppress("UNCHECKED_CAST") + it.readObject() as MutableMap + } + return ClasspathSnapshot(cacheDir, classpathFiles, dataForFiles) } - fun createCurrent(cacheDir: File, classpath: Iterable, lazyClasspathData: Set): ClasspathSnapshot { - val lazyData = lazyClasspathData.map { LazyClasspathEntryData.LazyClasspathEntrySerializer.loadFromFile(it) } - val data = { files: Set -> - lazyData.filter { files.contains(it.classpathEntry) }.associate { it.classpathEntry to it.getClasspathEntryData() } - } + fun createCurrent(cacheDir: File, classpath: List, allStructureData: Set): ClasspathSnapshot { + val data = allStructureData.associateTo(HashMap(allStructureData.size)) { it to null } return ClasspathSnapshot(cacheDir, classpath, data) } - - private fun loadPreviousData(file: File): Map { - ObjectInputStream(BufferedInputStream(file.inputStream())).use { - @Suppress("UNCHECKED_CAST") - return it.readObject() as Map - } - } } private fun isCompatible(snapshot: ClasspathSnapshot) = - this != UnknownSnapshot && classpath == snapshot.classpath + this != UnknownSnapshot && snapshot != UnknownSnapshot && classpath == snapshot.classpath /** Compare this snapshot with the specified one only for the specified files. */ fun diff(previousSnapshot: ClasspathSnapshot, changedFiles: Set): KaptClasspathChanges { @@ -69,54 +54,88 @@ open class ClasspathSnapshot protected constructor( return KaptClasspathChanges.Unknown } - val currentData = classpathData(changedFiles) - val previousData = previousSnapshot.classpathData(changedFiles) + loadEntriesFor(changedFiles) + + val currentHashAbiSize = changedFiles.sumBy { dataForFiles[it]!!.classAbiHash.size } + val currentHashesToAnalyze = + HashMap(currentHashAbiSize).also { hashes -> + changedFiles.forEach { + hashes.putAll(dataForFiles[it]!!.classAbiHash) + } + } + + val currentUnchanged = dataForFiles.keys.filter { it !in changedFiles } + val previousChanged = previousSnapshot.dataForFiles.keys.filter { it !in currentUnchanged } + + check(changedFiles.size == previousChanged.size) { + """ + Number of changed files in snapshots differs. Reported changed files: $changedFiles + Current snapshot data files: ${dataForFiles.keys} + Previous snapshot data files: ${previousSnapshot.dataForFiles.keys} + """.trimIndent() + } + + val previousHashAbiSize = previousChanged.sumBy { previousSnapshot.dataForFiles.get(it)?.classAbiHash?.size ?: 0 } + val previousHashesToAnalyze = + HashMap(previousHashAbiSize).also { hashes -> + for (c in previousChanged) { + previousSnapshot.dataForFiles[c]?.let { + hashes.putAll(it.classAbiHash) + } + } + } val changedClasses = mutableSetOf() - - for (changed in changedFiles) { - val previous = previousData.getValue(changed) - val current = currentData.getValue(changed) - - for (key in previous.classAbiHash.keys + current.classAbiHash.keys) { - val previousHash = previous.classAbiHash[key] - if (previousHash == null) { - changedClasses.add(key) - continue - } - val currentHash = current.classAbiHash[key] - if (currentHash == null) { - changedClasses.add(key) - continue - } - if (!previousHash.contentEquals(currentHash)) { - changedClasses.add(key) - } + for (key in previousHashesToAnalyze.keys + currentHashesToAnalyze.keys) { + val previousHash = previousHashesToAnalyze[key] + if (previousHash == null) { + changedClasses.add(key) + continue + } + val currentHash = currentHashesToAnalyze[key] + if (currentHash == null) { + changedClasses.add(key) + continue + } + if (!previousHash.contentEquals(currentHash)) { + changedClasses.add(key) } } // We do not compute structural data for unchanged files of the current snapshot for performance reasons. // That is why we reuse the previous snapshot as that one contains all unchanged entries. - previousData.filterTo(computedClasspathData) { (key, _) -> key !in computedClasspathData } + for (unchanged in currentUnchanged) { + dataForFiles[unchanged] = previousSnapshot.dataForFiles[unchanged]!! + } val allImpactedClasses = findAllImpacted(changedClasses) return KaptClasspathChanges.Known(allImpactedClasses) } + private fun loadEntriesFor(file: Iterable) { + for (f in file) { + if (dataForFiles[f] == null) { + dataForFiles[f] = ClasspathEntryData.ClasspathEntrySerializer.loadFrom(f) + } + } + } + + private fun loadAll() { + loadEntriesFor(dataForFiles.keys) + } + fun writeToCache() { - val classpathEntries = cacheDir.resolve("classpath-entries.bin") + loadAll() + + val classpathEntries = cacheDir.resolve(CLASSPATH_ENTRIES_FILE) ObjectOutputStream(BufferedOutputStream(classpathEntries.outputStream())).use { it.writeObject(classpath) } - val classpathStructureData = cacheDir.resolve("classpath-structure.bin") - storeCurrentStructure(classpathStructureData, classpathData(classpath.toSet())) - } - - private fun storeCurrentStructure(file: File, structure: Map) { - ObjectOutputStream(BufferedOutputStream(file.outputStream())).use { - it.writeObject(structure) + val classpathStructureData = cacheDir.resolve(CLASSPATH_STRUCTURE_FILE) + ObjectOutputStream(BufferedOutputStream(classpathStructureData.outputStream())).use { + it.writeObject(dataForFiles) } } @@ -125,8 +144,8 @@ open class ClasspathSnapshot protected constructor( val transitiveDeps = HashMap>() val nonTransitiveDeps = HashMap>() - for (entry in computedClasspathData.values) { - for ((className, classDependency) in entry.classDependencies) { + for (entry in dataForFiles.values) { + for ((className, classDependency) in entry!!.classDependencies) { for (abiType in classDependency.abiTypes) { (transitiveDeps[abiType] ?: LinkedList()).let { it.add(className) @@ -165,7 +184,7 @@ open class ClasspathSnapshot protected constructor( } } -object UnknownSnapshot : ClasspathSnapshot(File(""), emptyList(), { emptyMap() }) +object UnknownSnapshot : ClasspathSnapshot(File(""), emptyList(), mutableMapOf()) sealed class KaptIncrementalChanges { object Unknown : KaptIncrementalChanges() diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/incremental/ClasspathAnalyzerTest.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/incremental/ClasspathAnalyzerTest.kt index 7ae00c316a2..57b8378e16e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/incremental/ClasspathAnalyzerTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/incremental/ClasspathAnalyzerTest.kt @@ -35,10 +35,7 @@ class ClasspathAnalyzerTest { val transform = StructureArtifactTransform().also { it.outputDirectory = tmp.newFolder() } val outputs = transform.transform(classesDir) - val lazyData = LazyClasspathEntryData.LazyClasspathEntrySerializer.loadFromFile(outputs.single()) - assertEquals(classesDir, lazyData.classpathEntry) - - val data = lazyData.getClasspathEntryData() + val data = ClasspathEntryData.ClasspathEntrySerializer.loadFrom(outputs.single()) assertEquals(setOf("test/A", "test/B"), data.classAbiHash.keys) assertEquals(setOf("test/A", "test/B"), data.classDependencies.keys) assertEquals(emptySet(), data.classDependencies["test/A"]!!.abiTypes) @@ -71,10 +68,7 @@ class ClasspathAnalyzerTest { val transform = StructureArtifactTransform().also { it.outputDirectory = tmp.newFolder() } val outputs = transform.transform(inputJar) - val lazyData = LazyClasspathEntryData.LazyClasspathEntrySerializer.loadFromFile(outputs.single()) - assertEquals(inputJar, lazyData.classpathEntry) - - val data = lazyData.getClasspathEntryData() + val data = ClasspathEntryData.ClasspathEntrySerializer.loadFrom(outputs.single()) assertEquals(setOf("test/A", "test/B"), data.classAbiHash.keys) assertEquals(setOf("test/A", "test/B"), data.classDependencies.keys) assertEquals(emptySet(), data.classDependencies["test/A"]!!.abiTypes) @@ -90,10 +84,7 @@ class ClasspathAnalyzerTest { val transform = StructureArtifactTransform().also { it.outputDirectory = tmp.newFolder() } val outputs = transform.transform(inputDir) - val lazyData = LazyClasspathEntryData.LazyClasspathEntrySerializer.loadFromFile(outputs.single()) - assertEquals(inputDir, lazyData.classpathEntry) - - val data = lazyData.getClasspathEntryData() + val data = ClasspathEntryData.ClasspathEntrySerializer.loadFrom(outputs.single()) assertTrue(data.classAbiHash.isEmpty()) assertTrue(data.classDependencies.isEmpty()) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/incremental/ClasspathSnapshotTest.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/incremental/ClasspathSnapshotTest.kt index 59353f67e64..9df969dfc45 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/incremental/ClasspathSnapshotTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/incremental/ClasspathSnapshotTest.kt @@ -18,93 +18,80 @@ class ClasspathSnapshotTest { @Test fun testSerialization() { - val (firstJar, lazyData) = generateLazyData( + val data = generateStructureData( ClassData("first/A"), ClassData("first/B") ) val snapshotDir = tmp.newFolder() - val currentSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(snapshotDir, listOf(firstJar), setOf(lazyData)) - assertEquals(KaptClasspathChanges.Unknown, currentSnapshot.diff(UnknownSnapshot, setOf(firstJar))) + val currentSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(snapshotDir, listOf(), setOf(data)) + assertEquals(KaptClasspathChanges.Unknown, currentSnapshot.diff(UnknownSnapshot, setOf(data))) currentSnapshot.writeToCache() val loadedSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.loadFrom(snapshotDir) - val diff = loadedSnapshot.diff(currentSnapshot, setOf(firstJar)) as KaptClasspathChanges.Known + val diff = loadedSnapshot.diff(currentSnapshot, setOf(data)) as KaptClasspathChanges.Known assertEquals(emptySet(), diff.names) } @Test fun testIncompatibleClasspaths() { - val firstSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(File(""), listOf(File("1.jar")), emptySet()) + val firstSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(File(""), listOf(File("a.jar")), emptySet()) val secondSnapshot = - ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(File(""), listOf(File("1.jar"), File("added.jar")), emptySet()) - assertEquals(KaptClasspathChanges.Unknown, firstSnapshot.diff(secondSnapshot, setOf(File("added.jar")))) + ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(File(""), listOf(File("b.jar")), setOf(File(""))) + assertEquals(KaptClasspathChanges.Unknown, firstSnapshot.diff(secondSnapshot, emptySet())) } @Test fun testChangedClassesFound() { - val (firstJar, firstLazyData) = generateLazyData( + val dataFile = generateStructureData( ClassData("first/A"), ClassData("first/B").also { it.withAbiDependencies("first/A") } ) - val firstSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(File(""), listOf(firstJar), setOf(firstLazyData)) - firstSnapshot.diff(UnknownSnapshot, setOf(firstJar)) + val firstSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(tmp.newFolder(), listOf(), setOf(dataFile)) + firstSnapshot.writeToCache() - val (_, changedLazyData) = generateLazyData( + generateStructureData( ClassData("first/A", ByteArray(1)), ClassData("first/B").also { it.withAbiDependencies("first/A") }, - jarInput = firstJar + outputFile = dataFile ) - val changedSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(File(""), listOf(firstJar), setOf(changedLazyData)) + val changedSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(tmp.newFolder(), listOf(), setOf(dataFile)) - val diff = changedSnapshot.diff(firstSnapshot, setOf(firstJar)) as KaptClasspathChanges.Known + val diff = changedSnapshot.diff(firstSnapshot, setOf(dataFile)) as KaptClasspathChanges.Known assertEquals(setOf("first/A", "first/B"), diff.names) } @Test fun testChangedClassesAcrossEntries() { - val (firstJar, firstLazyData) = generateLazyData( + val dataFile = generateStructureData( ClassData("first/A").also { it.withAbiDependencies("library/C") }, ClassData("first/B").also { it.withAbiDependencies("first/A") } ) - val (libraryJar, libraryLazyData) = generateLazyData(ClassData("library/C")) + val libraryDataFile = generateStructureData(ClassData("library/C")) val cacheDir = tmp.newFolder() val firstSnapshot = - ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent( - cacheDir, - listOf(firstJar, libraryJar), - setOf(firstLazyData, libraryLazyData) - ) - firstSnapshot.diff(UnknownSnapshot, setOf(firstJar, libraryJar)) + ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(cacheDir, listOf(), setOf(dataFile, libraryDataFile)) firstSnapshot.writeToCache() - val (_, changedLazyData) = generateLazyData(ClassData("library/C", ByteArray(1)), jarInput = libraryJar) + generateStructureData(ClassData("library/C", ByteArray(1)), outputFile = libraryDataFile) val changedSnapshot = - ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent( - cacheDir, - listOf(firstJar, libraryJar), - setOf(firstLazyData, changedLazyData) - ) + ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(cacheDir, listOf(), setOf(dataFile, libraryDataFile)) - val diff = changedSnapshot.diff(firstSnapshot, setOf(libraryJar)) as KaptClasspathChanges.Known + val diff = changedSnapshot.diff(firstSnapshot, setOf(libraryDataFile)) as KaptClasspathChanges.Known assertEquals(setOf("library/C", "first/A", "first/B"), diff.names) } - private fun generateLazyData( - vararg classData: ClassData, - jarInput: File = tmp.newFile() - ): Pair { + private fun generateStructureData(vararg classData: ClassData, outputFile: File = tmp.newFile()): File { val data = ClasspathEntryData() classData.forEach { data.classAbiHash[it.internalName] = it.hash data.classDependencies[it.internalName] = ClassDependencies(it.abiDeps, it.privateDeps) } - val serialized = tmp.newFile().also { data.saveTo(it) } - val lazyData = tmp.newFile().also { LazyClasspathEntryData(jarInput, serialized).saveToFile(it) } + data.saveTo(outputFile) - return Pair(jarInput, lazyData) + return outputFile } private class ClassData(