Refactoring: extract interface AnnotationFileUpdater

This commit is contained in:
Alexey Tsvetkov
2016-11-24 17:25:30 +03:00
parent fdd3bc31f1
commit 599f11b431
3 changed files with 64 additions and 61 deletions
@@ -16,64 +16,10 @@
package org.jetbrains.kotlin.annotation
import org.gradle.api.logging.Logging
import org.jetbrains.kotlin.gradle.plugin.kotlinDebug
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import java.io.File
import java.util.*
/**
* Annotation file is generated by collecting annotated elements of generated files.
* When compiling incrementally, the compiler generates only subset of all classes,
* so after compilation annotation file contains only a subset of annotated elements,
* which breaks the build.
*
* The workaround is to:
* 1. backup old file before incremental compilation;
* 2. after each iteration of IC:
* 2.1 remove classes corresponding to dirty source files
* 2.2 add annotations from newly generated annotations file
*/
internal class AnnotationFileUpdater(private val generatedAnnotationFile: File) {
private val logger = Logging.getLogger(this.javaClass)
private val lastSuccessfullyUpdatedFile = File.createTempFile("kapt-annotations-copy", "tmp")
interface AnnotationFileUpdater {
fun updateAnnotations(outdatedClasses: Iterable<JvmClassName>)
fun revert()
}
init {
if (generatedAnnotationFile.exists()) {
generatedAnnotationFile.copyTo(lastSuccessfullyUpdatedFile, overwrite = true)
}
else {
lastSuccessfullyUpdatedFile.writeText("")
}
}
fun updateAnnotations(outdatedClasses: Iterable<JvmClassName>) {
val outdatedClassesFqNames = outdatedClasses.mapTo(HashSet<String>()) { it.fqNameForClassNameWithoutDollars.asString() }
val annotationsProvider = MutableKotlinAnnotationProvider().apply {
addAnnotationsFrom(lastSuccessfullyUpdatedFile)
removeClasses(outdatedClassesFqNames)
logger.kotlinDebug { "Removed annotation entries for fq-names [${outdatedClassesFqNames.joinToString()}]" }
if (generatedAnnotationFile.exists()) {
addAnnotationsFrom(generatedAnnotationFile)
logger.kotlinDebug { "Added annotation entries from $generatedAnnotationFile" }
}
}
generatedAnnotationFile.delete()
generatedAnnotationFile.bufferedWriter().use { writer ->
annotationsProvider.writeAnnotations(CompactAnnotationWriter(writer))
logger.kotlinDebug { "Written updated annotations to $generatedAnnotationFile" }
}
generatedAnnotationFile.copyTo(lastSuccessfullyUpdatedFile, overwrite = true)
}
fun revert() {
lastSuccessfullyUpdatedFile.copyTo(generatedAnnotationFile, overwrite = true)
}
fun dispose() {
lastSuccessfullyUpdatedFile.delete()
}
}
@@ -0,0 +1,58 @@
package org.jetbrains.kotlin.annotation
import org.gradle.api.logging.Logging
import org.jetbrains.kotlin.gradle.plugin.kotlinDebug
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import java.io.File
/**
* Annotation file is generated by collecting annotated elements of generated files.
* When compiling incrementally, the compiler generates only subset of all classes,
* so after compilation annotation file contains only a subset of annotated elements,
* which breaks the build.
*
* The workaround is to:
* 1. backup old file before incremental compilation;
* 2. after each iteration of IC:
* 2.1 remove classes corresponding to dirty source files
* 2.2 add annotations from newly generated annotations file
*/
internal class AnnotationFileUpdaterImpl(private val generatedAnnotationFile: File) : AnnotationFileUpdater {
private val logger = Logging.getLogger(this.javaClass)
private val lastSuccessfullyUpdatedFile = File.createTempFile("kapt-annotations-copy", "tmp")
init {
if (generatedAnnotationFile.exists()) {
generatedAnnotationFile.copyTo(lastSuccessfullyUpdatedFile, overwrite = true)
}
else {
lastSuccessfullyUpdatedFile.writeText("")
}
}
override fun updateAnnotations(outdatedClasses: Iterable<JvmClassName>) {
val outdatedClassesFqNames = outdatedClasses.mapTo(java.util.HashSet<String>()) { it.fqNameForClassNameWithoutDollars.asString() }
val annotationsProvider = MutableKotlinAnnotationProvider().apply {
addAnnotationsFrom(lastSuccessfullyUpdatedFile)
removeClasses(outdatedClassesFqNames)
logger.kotlinDebug { "Removed annotation entries for fq-names [${outdatedClassesFqNames.joinToString()}]" }
if (generatedAnnotationFile.exists()) {
addAnnotationsFrom(generatedAnnotationFile)
logger.kotlinDebug { "Added annotation entries from $generatedAnnotationFile" }
}
}
generatedAnnotationFile.delete()
generatedAnnotationFile.bufferedWriter().use { writer ->
annotationsProvider.writeAnnotations(CompactAnnotationWriter(writer))
logger.kotlinDebug { "Written updated annotations to $generatedAnnotationFile" }
}
generatedAnnotationFile.copyTo(lastSuccessfullyUpdatedFile, overwrite = true)
}
override fun revert() {
lastSuccessfullyUpdatedFile.copyTo(generatedAnnotationFile, overwrite = true)
}
}
@@ -27,6 +27,7 @@ import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.compile.AbstractCompile
import org.gradle.api.tasks.incremental.IncrementalTaskInputs
import org.jetbrains.kotlin.annotation.AnnotationFileUpdater
import org.jetbrains.kotlin.annotation.AnnotationFileUpdaterImpl
import org.jetbrains.kotlin.cli.common.CLICompiler
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
@@ -40,7 +41,6 @@ import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.compilerRunner.ArgumentUtils
import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner
import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl
import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.plugin.CoroutineSupport
import org.jetbrains.kotlin.gradle.plugin.kotlinDebug
@@ -51,7 +51,6 @@ import org.jetbrains.kotlin.incremental.multiproject.ArtifactDifferenceRegistryP
import org.jetbrains.kotlin.utils.LibraryUtils
import java.io.File
import java.util.*
import kotlin.concurrent.thread
import kotlin.properties.Delegates
const val ANNOTATIONS_PLUGIN_NAME = "org.jetbrains.kotlin.kapt"
@@ -254,7 +253,7 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
private fun handleKaptProperties() {
kaptOptions.annotationsFile?.let { kaptAnnotationsFile ->
if (incremental) {
kaptAnnotationsFileUpdater = AnnotationFileUpdater(kaptAnnotationsFile)
kaptAnnotationsFileUpdater = AnnotationFileUpdaterImpl(kaptAnnotationsFile)
}
pluginOptions.addPluginArgument(ANNOTATIONS_PLUGIN_NAME, "output", kaptAnnotationsFile.canonicalPath)