Run KAPT non-incrementally if annotation processor classpath changes
Annotation processor classpath for a KAPT run is recorded, and the current run is compared against the previous one. If those differ, KAPT should run non-incrementally. Test: KaptIncrementalWithIsolatingApt.testChangingAnnotationProcessorClasspath
This commit is contained in:
committed by
Yan Zhulanow
parent
2412b5f992
commit
0a26742501
+22
-1
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.gradle
|
|||||||
import org.jetbrains.kotlin.gradle.incapt.IncrementalProcessor
|
import org.jetbrains.kotlin.gradle.incapt.IncrementalProcessor
|
||||||
import org.jetbrains.kotlin.gradle.util.modify
|
import org.jetbrains.kotlin.gradle.util.modify
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Assert.assertTrue
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.zip.ZipEntry
|
import java.util.zip.ZipEntry
|
||||||
@@ -65,6 +64,28 @@ class KaptIncrementalWithIsolatingApt : KaptIncrementalIT() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testChangingAnnotationProcessorClasspath() {
|
||||||
|
val project = getProject()
|
||||||
|
|
||||||
|
project.build("clean", "build") {
|
||||||
|
assertSuccessful()
|
||||||
|
}
|
||||||
|
|
||||||
|
project.gradleBuildScript().appendText(
|
||||||
|
"""
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
kapt 'com.google.guava:guava:12.0'
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
project.build("build") {
|
||||||
|
assertSuccessful()
|
||||||
|
assertContains("Unable to use existing data, re-initializing classpath information for KAPT.")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val patternApt = "Processing java sources with annotation processors:"
|
private const val patternApt = "Processing java sources with annotation processors:"
|
||||||
|
|||||||
+6
-1
@@ -201,7 +201,12 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState {
|
|||||||
ClasspathSnapshot.ClasspathSnapshotFactory.getEmptySnapshot()
|
ClasspathSnapshot.ClasspathSnapshotFactory.getEmptySnapshot()
|
||||||
}
|
}
|
||||||
val currentSnapshot =
|
val currentSnapshot =
|
||||||
ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(incAptCacheDir, classpath.files.toList(), allDataFiles)
|
ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(
|
||||||
|
incAptCacheDir,
|
||||||
|
classpath.files.toList(),
|
||||||
|
kaptClasspath.files.toList(),
|
||||||
|
allDataFiles
|
||||||
|
)
|
||||||
|
|
||||||
val classpathChanges = currentSnapshot.diff(previousSnapshot, changedFiles)
|
val classpathChanges = currentSnapshot.diff(previousSnapshot, changedFiles)
|
||||||
if (classpathChanges == KaptClasspathChanges.Unknown) {
|
if (classpathChanges == KaptClasspathChanges.Unknown) {
|
||||||
|
|||||||
+23
-6
@@ -10,18 +10,21 @@ import java.util.*
|
|||||||
import kotlin.collections.HashMap
|
import kotlin.collections.HashMap
|
||||||
|
|
||||||
private const val CLASSPATH_ENTRIES_FILE = "classpath-entries.bin"
|
private const val CLASSPATH_ENTRIES_FILE = "classpath-entries.bin"
|
||||||
|
private const val ANNOTATION_PROCESSOR_CLASSPATH_ENTRIES_FILE = "ap-classpath-entries.bin"
|
||||||
private const val CLASSPATH_STRUCTURE_FILE = "classpath-structure.bin"
|
private const val CLASSPATH_STRUCTURE_FILE = "classpath-structure.bin"
|
||||||
|
|
||||||
open class ClasspathSnapshot protected constructor(
|
open class ClasspathSnapshot protected constructor(
|
||||||
private val cacheDir: File,
|
private val cacheDir: File,
|
||||||
private val classpath: List<File>,
|
private val classpath: List<File>,
|
||||||
|
private val annotationProcessorClasspath: List<File>,
|
||||||
private val dataForFiles: MutableMap<File, ClasspathEntryData?>
|
private val dataForFiles: MutableMap<File, ClasspathEntryData?>
|
||||||
) {
|
) {
|
||||||
object ClasspathSnapshotFactory {
|
object ClasspathSnapshotFactory {
|
||||||
fun loadFrom(cacheDir: File): ClasspathSnapshot {
|
fun loadFrom(cacheDir: File): ClasspathSnapshot {
|
||||||
val classpathEntries = cacheDir.resolve(CLASSPATH_ENTRIES_FILE)
|
val classpathEntries = cacheDir.resolve(CLASSPATH_ENTRIES_FILE)
|
||||||
val classpathStructureData = cacheDir.resolve(CLASSPATH_STRUCTURE_FILE)
|
val classpathStructureData = cacheDir.resolve(CLASSPATH_STRUCTURE_FILE)
|
||||||
if (!classpathEntries.exists() || !classpathStructureData.exists()) {
|
val annotationProcessorClasspathEntries= cacheDir.resolve(ANNOTATION_PROCESSOR_CLASSPATH_ENTRIES_FILE)
|
||||||
|
if (!classpathEntries.exists() || !classpathStructureData.exists() || !annotationProcessorClasspathEntries.exists()) {
|
||||||
return UnknownSnapshot
|
return UnknownSnapshot
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,25 +33,34 @@ open class ClasspathSnapshot protected constructor(
|
|||||||
it.readObject() as List<File>
|
it.readObject() as List<File>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val annotationProcessorClasspathFiles =
|
||||||
|
ObjectInputStream(BufferedInputStream(annotationProcessorClasspathEntries.inputStream())).use {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
it.readObject() as List<File>
|
||||||
|
}
|
||||||
|
|
||||||
val dataForFiles =
|
val dataForFiles =
|
||||||
ObjectInputStream(BufferedInputStream(classpathStructureData.inputStream())).use {
|
ObjectInputStream(BufferedInputStream(classpathStructureData.inputStream())).use {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
it.readObject() as MutableMap<File, ClasspathEntryData?>
|
it.readObject() as MutableMap<File, ClasspathEntryData?>
|
||||||
}
|
}
|
||||||
return ClasspathSnapshot(cacheDir, classpathFiles, dataForFiles)
|
return ClasspathSnapshot(cacheDir, classpathFiles, annotationProcessorClasspathFiles, dataForFiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createCurrent(cacheDir: File, classpath: List<File>, allStructureData: Set<File>): ClasspathSnapshot {
|
fun createCurrent(cacheDir: File, classpath: List<File>, annotationProcessorClasspath: List<File>, allStructureData: Set<File>): ClasspathSnapshot {
|
||||||
val data = allStructureData.associateTo(HashMap<File, ClasspathEntryData?>(allStructureData.size)) { it to null }
|
val data = allStructureData.associateTo(HashMap<File, ClasspathEntryData?>(allStructureData.size)) { it to null }
|
||||||
|
|
||||||
return ClasspathSnapshot(cacheDir, classpath, data)
|
return ClasspathSnapshot(cacheDir, classpath, annotationProcessorClasspath, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getEmptySnapshot() = UnknownSnapshot
|
fun getEmptySnapshot() = UnknownSnapshot
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isCompatible(snapshot: ClasspathSnapshot) =
|
private fun isCompatible(snapshot: ClasspathSnapshot) =
|
||||||
this != UnknownSnapshot && snapshot != UnknownSnapshot && classpath == snapshot.classpath
|
this != UnknownSnapshot
|
||||||
|
&& snapshot != UnknownSnapshot
|
||||||
|
&& classpath == snapshot.classpath
|
||||||
|
&& annotationProcessorClasspath == snapshot.annotationProcessorClasspath
|
||||||
|
|
||||||
/** Compare this snapshot with the specified one only for the specified files. */
|
/** Compare this snapshot with the specified one only for the specified files. */
|
||||||
fun diff(previousSnapshot: ClasspathSnapshot, changedFiles: Set<File>): KaptClasspathChanges {
|
fun diff(previousSnapshot: ClasspathSnapshot, changedFiles: Set<File>): KaptClasspathChanges {
|
||||||
@@ -128,6 +140,11 @@ open class ClasspathSnapshot protected constructor(
|
|||||||
it.writeObject(classpath)
|
it.writeObject(classpath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val annotationProcessorClasspathEntries = cacheDir.resolve(ANNOTATION_PROCESSOR_CLASSPATH_ENTRIES_FILE)
|
||||||
|
ObjectOutputStream(BufferedOutputStream(annotationProcessorClasspathEntries.outputStream())).use {
|
||||||
|
it.writeObject(annotationProcessorClasspath)
|
||||||
|
}
|
||||||
|
|
||||||
val classpathStructureData = cacheDir.resolve(CLASSPATH_STRUCTURE_FILE)
|
val classpathStructureData = cacheDir.resolve(CLASSPATH_STRUCTURE_FILE)
|
||||||
ObjectOutputStream(BufferedOutputStream(classpathStructureData.outputStream())).use {
|
ObjectOutputStream(BufferedOutputStream(classpathStructureData.outputStream())).use {
|
||||||
it.writeObject(dataForFiles)
|
it.writeObject(dataForFiles)
|
||||||
@@ -179,7 +196,7 @@ open class ClasspathSnapshot protected constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object UnknownSnapshot : ClasspathSnapshot(File(""), emptyList(), mutableMapOf())
|
object UnknownSnapshot : ClasspathSnapshot(File(""), emptyList(), emptyList(), mutableMapOf())
|
||||||
|
|
||||||
sealed class KaptIncrementalChanges {
|
sealed class KaptIncrementalChanges {
|
||||||
object Unknown : KaptIncrementalChanges()
|
object Unknown : KaptIncrementalChanges()
|
||||||
|
|||||||
+24
-9
@@ -23,7 +23,7 @@ class ClasspathSnapshotTest {
|
|||||||
)
|
)
|
||||||
|
|
||||||
val snapshotDir = tmp.newFolder()
|
val snapshotDir = tmp.newFolder()
|
||||||
val currentSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(snapshotDir, listOf(), setOf(data))
|
val currentSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(snapshotDir, listOf(), listOf(), setOf(data))
|
||||||
assertEquals(KaptClasspathChanges.Unknown, currentSnapshot.diff(UnknownSnapshot, setOf(data)))
|
assertEquals(KaptClasspathChanges.Unknown, currentSnapshot.diff(UnknownSnapshot, setOf(data)))
|
||||||
currentSnapshot.writeToCache()
|
currentSnapshot.writeToCache()
|
||||||
|
|
||||||
@@ -35,9 +35,23 @@ class ClasspathSnapshotTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testIncompatibleClasspaths() {
|
fun testIncompatibleClasspaths() {
|
||||||
val firstSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(File(""), listOf(File("a.jar")), emptySet())
|
val firstSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(File(""), listOf(File("a.jar")), listOf(), emptySet())
|
||||||
val secondSnapshot =
|
val secondSnapshot =
|
||||||
ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(File(""), listOf(File("b.jar")), setOf(File("")))
|
ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(File(""), listOf(File("b.jar")), listOf(), setOf(File("")))
|
||||||
|
assertEquals(KaptClasspathChanges.Unknown, firstSnapshot.diff(secondSnapshot, emptySet()))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testIncompatibleAnnotationProcessorClasspaths() {
|
||||||
|
val firstSnapshot =
|
||||||
|
ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(File(""), listOf(File("a.jar")), listOf(File("ap2.jar")), emptySet())
|
||||||
|
val secondSnapshot =
|
||||||
|
ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(
|
||||||
|
File(""),
|
||||||
|
listOf(File("a.jar")),
|
||||||
|
listOf(File("ap1.jar")),
|
||||||
|
setOf(File(""))
|
||||||
|
)
|
||||||
assertEquals(KaptClasspathChanges.Unknown, firstSnapshot.diff(secondSnapshot, emptySet()))
|
assertEquals(KaptClasspathChanges.Unknown, firstSnapshot.diff(secondSnapshot, emptySet()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +61,7 @@ class ClasspathSnapshotTest {
|
|||||||
ClassData("first/A"),
|
ClassData("first/A"),
|
||||||
ClassData("first/B").also { it.withAbiDependencies("first/A") }
|
ClassData("first/B").also { it.withAbiDependencies("first/A") }
|
||||||
)
|
)
|
||||||
val firstSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(tmp.newFolder(), listOf(), setOf(dataFile))
|
val firstSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(tmp.newFolder(), listOf(), listOf(), setOf(dataFile))
|
||||||
firstSnapshot.writeToCache()
|
firstSnapshot.writeToCache()
|
||||||
|
|
||||||
generateStructureData(
|
generateStructureData(
|
||||||
@@ -55,7 +69,7 @@ class ClasspathSnapshotTest {
|
|||||||
ClassData("first/B").also { it.withAbiDependencies("first/A") },
|
ClassData("first/B").also { it.withAbiDependencies("first/A") },
|
||||||
outputFile = dataFile
|
outputFile = dataFile
|
||||||
)
|
)
|
||||||
val changedSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(tmp.newFolder(), listOf(), setOf(dataFile))
|
val changedSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(tmp.newFolder(), listOf(), listOf(), setOf(dataFile))
|
||||||
|
|
||||||
val diff = changedSnapshot.diff(firstSnapshot, setOf(dataFile)) as KaptClasspathChanges.Known
|
val diff = changedSnapshot.diff(firstSnapshot, setOf(dataFile)) as KaptClasspathChanges.Known
|
||||||
assertEquals(setOf("first/A", "first/B"), diff.names)
|
assertEquals(setOf("first/A", "first/B"), diff.names)
|
||||||
@@ -72,12 +86,12 @@ class ClasspathSnapshotTest {
|
|||||||
|
|
||||||
val cacheDir = tmp.newFolder()
|
val cacheDir = tmp.newFolder()
|
||||||
val firstSnapshot =
|
val firstSnapshot =
|
||||||
ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(cacheDir, listOf(), setOf(dataFile, libraryDataFile))
|
ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(cacheDir, listOf(), listOf(), setOf(dataFile, libraryDataFile))
|
||||||
firstSnapshot.writeToCache()
|
firstSnapshot.writeToCache()
|
||||||
|
|
||||||
generateStructureData(ClassData("library/C", ByteArray(1)), outputFile = libraryDataFile)
|
generateStructureData(ClassData("library/C", ByteArray(1)), outputFile = libraryDataFile)
|
||||||
val changedSnapshot =
|
val changedSnapshot =
|
||||||
ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(cacheDir, listOf(), setOf(dataFile, libraryDataFile))
|
ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(cacheDir, listOf(), listOf(), setOf(dataFile, libraryDataFile))
|
||||||
|
|
||||||
val diff = changedSnapshot.diff(firstSnapshot, setOf(libraryDataFile)) as KaptClasspathChanges.Known
|
val diff = changedSnapshot.diff(firstSnapshot, setOf(libraryDataFile)) as KaptClasspathChanges.Known
|
||||||
assertEquals(setOf("library/C", "first/A", "first/B"), diff.names)
|
assertEquals(setOf("library/C", "first/A", "first/B"), diff.names)
|
||||||
@@ -89,11 +103,12 @@ class ClasspathSnapshotTest {
|
|||||||
ClassData("first/A"),
|
ClassData("first/A"),
|
||||||
ClassData("first/B").also { it.withAbiDependencies("first/A") }
|
ClassData("first/B").also { it.withAbiDependencies("first/A") }
|
||||||
)
|
)
|
||||||
val firstSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(tmp.newFolder(), listOf(), setOf(dataFile))
|
val firstSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(tmp.newFolder(), listOf(), listOf(), setOf(dataFile))
|
||||||
firstSnapshot.writeToCache()
|
firstSnapshot.writeToCache()
|
||||||
|
|
||||||
val copyOfDataFile = dataFile.copyTo(tmp.newFile(), overwrite = true)
|
val copyOfDataFile = dataFile.copyTo(tmp.newFile(), overwrite = true)
|
||||||
val secondSnapshot = ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(tmp.newFolder(), listOf(), setOf(copyOfDataFile))
|
val secondSnapshot =
|
||||||
|
ClasspathSnapshot.ClasspathSnapshotFactory.createCurrent(tmp.newFolder(), listOf(), listOf(), setOf(copyOfDataFile))
|
||||||
|
|
||||||
val diff = secondSnapshot.diff(firstSnapshot, setOf()) as KaptClasspathChanges.Known
|
val diff = secondSnapshot.diff(firstSnapshot, setOf()) as KaptClasspathChanges.Known
|
||||||
assertEquals(emptySet<String>(), diff.names)
|
assertEquals(emptySet<String>(), diff.names)
|
||||||
|
|||||||
Reference in New Issue
Block a user