Rebuild on cache corrupted exception

#KT-14055 fixed
This commit is contained in:
Alexey Tsvetkov
2016-10-04 00:20:33 +03:00
parent fafde1e948
commit 0d1c803f71
11 changed files with 171 additions and 56 deletions
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.com.intellij.openapi.vfs.impl.ZipHandler
import org.jetbrains.kotlin.com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem import org.jetbrains.kotlin.com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
import org.jetbrains.kotlin.gradle.tasks.ArtifactDifferenceRegistry import org.jetbrains.kotlin.gradle.tasks.ArtifactDifferenceRegistry
import org.jetbrains.kotlin.gradle.tasks.ArtifactDifferenceRegistryProvider
import org.jetbrains.kotlin.gradle.tasks.incremental.BuildCacheStorage import org.jetbrains.kotlin.gradle.tasks.incremental.BuildCacheStorage
import java.io.File import java.io.File
@@ -76,8 +77,8 @@ internal class KotlinGradleBuildServices private constructor(gradle: Gradle): Bu
private val workingDir = File(gradle.rootProject.buildDir, "kotlin-build").apply { mkdirs() } private val workingDir = File(gradle.rootProject.buildDir, "kotlin-build").apply { mkdirs() }
private val buildCacheStorage = BuildCacheStorage(workingDir) private val buildCacheStorage = BuildCacheStorage(workingDir)
internal val artifactDifferenceRegistry: ArtifactDifferenceRegistry internal val artifactDifferenceRegistryProvider: ArtifactDifferenceRegistryProvider
get() = buildCacheStorage.artifactDifferenceRegistry get() = buildCacheStorage
// There is function with the same name in BuildAdapter, // There is function with the same name in BuildAdapter,
// but it is called before any plugin can attach build listener // but it is called before any plugin can attach build listener
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.gradle.internal.Kapt2KotlinGradleSubplugin
import org.jetbrains.kotlin.gradle.internal.initKapt import org.jetbrains.kotlin.gradle.internal.initKapt
import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper
import org.jetbrains.kotlin.gradle.tasks.* import org.jetbrains.kotlin.gradle.tasks.*
import org.jetbrains.kotlin.gradle.tasks.incremental.android.ArtifactDifferenceRegistryAndroidWrapper import org.jetbrains.kotlin.gradle.tasks.incremental.android.ArtifactDifferenceRegistryProviderAndroidWrapper
import org.jetbrains.kotlin.gradle.tasks.incremental.configureMultiProjectIncrementalCompilation import org.jetbrains.kotlin.gradle.tasks.incremental.configureMultiProjectIncrementalCompilation
import java.io.File import java.io.File
import java.net.URL import java.net.URL
@@ -97,7 +97,7 @@ internal class Kotlin2JvmSourceSetProcessor(
tasksProvider: KotlinTasksProvider, tasksProvider: KotlinTasksProvider,
kotlinSourceSetProvider: KotlinSourceSetProvider, kotlinSourceSetProvider: KotlinSourceSetProvider,
private val kotlinPluginVersion: String, private val kotlinPluginVersion: String,
private val artifactDifferenceRegistry: ArtifactDifferenceRegistry private val kotlinGradleBuildServices: KotlinGradleBuildServices
) : KotlinSourceSetProcessor<KotlinCompile>( ) : KotlinSourceSetProcessor<KotlinCompile>(
project, javaBasePlugin, sourceSet, tasksProvider, kotlinSourceSetProvider, project, javaBasePlugin, sourceSet, tasksProvider, kotlinSourceSetProvider,
dslExtensionName = KOTLIN_DSL_NAME, dslExtensionName = KOTLIN_DSL_NAME,
@@ -143,7 +143,8 @@ internal class Kotlin2JvmSourceSetProcessor(
createSyncOutputTask(project, kotlinTask, javaTask, kotlinAfterJavaTask, sourceSetName) createSyncOutputTask(project, kotlinTask, javaTask, kotlinAfterJavaTask, sourceSetName)
val artifactFile = project.tryGetSingleArtifact() val artifactFile = project.tryGetSingleArtifact()
configureMultiProjectIncrementalCompilation(project, kotlinTask, javaTask, kotlinAfterJavaTask, configureMultiProjectIncrementalCompilation(project, kotlinTask, javaTask, kotlinAfterJavaTask,
artifactDifferenceRegistry, artifactFile) kotlinGradleBuildServices.artifactDifferenceRegistryProvider,
artifactFile)
} }
} }
} }
@@ -237,10 +238,10 @@ internal open class KotlinPlugin(
tasksProvider: KotlinTasksProvider, tasksProvider: KotlinTasksProvider,
kotlinSourceSetProvider: KotlinSourceSetProvider, kotlinSourceSetProvider: KotlinSourceSetProvider,
kotlinPluginVersion: String, kotlinPluginVersion: String,
private val artifactDifferenceRegistry: ArtifactDifferenceRegistry private val kotlinGradleBuildServices: KotlinGradleBuildServices
) : AbstractKotlinPlugin(tasksProvider, kotlinSourceSetProvider, kotlinPluginVersion) { ) : AbstractKotlinPlugin(tasksProvider, kotlinSourceSetProvider, kotlinPluginVersion) {
override fun buildSourceSetProcessor(project: Project, javaBasePlugin: JavaBasePlugin, sourceSet: SourceSet, kotlinPluginVersion: String) = override fun buildSourceSetProcessor(project: Project, javaBasePlugin: JavaBasePlugin, sourceSet: SourceSet, kotlinPluginVersion: String) =
Kotlin2JvmSourceSetProcessor(project, javaBasePlugin, sourceSet, tasksProvider, kotlinSourceSetProvider, kotlinPluginVersion, artifactDifferenceRegistry) Kotlin2JvmSourceSetProcessor(project, javaBasePlugin, sourceSet, tasksProvider, kotlinSourceSetProvider, kotlinPluginVersion, kotlinGradleBuildServices)
override fun apply(project: Project) { override fun apply(project: Project) {
project.createKaptExtension() project.createKaptExtension()
@@ -262,7 +263,7 @@ internal open class KotlinAndroidPlugin(
val tasksProvider: KotlinTasksProvider, val tasksProvider: KotlinTasksProvider,
private val kotlinSourceSetProvider: KotlinSourceSetProvider, private val kotlinSourceSetProvider: KotlinSourceSetProvider,
private val kotlinPluginVersion: String, private val kotlinPluginVersion: String,
private val artifactDifferenceRegistry: ArtifactDifferenceRegistry private val kotlinGradleBuildServices: KotlinGradleBuildServices
) : Plugin<Project> { ) : Plugin<Project> {
private val log = Logging.getLogger(this.javaClass) private val log = Logging.getLogger(this.javaClass)
@@ -385,9 +386,9 @@ internal open class KotlinAndroidPlugin(
if ((kotlinAfterJavaTask ?: kotlinTask).incremental) { if ((kotlinAfterJavaTask ?: kotlinTask).incremental) {
val jarToAarMapping = AndroidGradleWrapper.getJarToAarMapping(variantData) val jarToAarMapping = AndroidGradleWrapper.getJarToAarMapping(variantData)
val artifactFile = project.tryGetSingleArtifact(variantData) val artifactFile = project.tryGetSingleArtifact(variantData)
val artifactDifferenceRegistryWrapper = ArtifactDifferenceRegistryAndroidWrapper(artifactDifferenceRegistry, jarToAarMapping) val artifactDifferenceRegistryProvider = ArtifactDifferenceRegistryProviderAndroidWrapper(kotlinGradleBuildServices.artifactDifferenceRegistryProvider, jarToAarMapping)
configureMultiProjectIncrementalCompilation(project, kotlinTask, javaTask, kotlinAfterJavaTask, configureMultiProjectIncrementalCompilation(project, kotlinTask, javaTask, kotlinAfterJavaTask,
artifactDifferenceRegistryWrapper, artifactFile) artifactDifferenceRegistryProvider, artifactFile)
} }
} }
} }
@@ -30,14 +30,12 @@ abstract class KotlinBasePluginWrapper(protected val fileResolver: FileResolver)
open class KotlinPluginWrapper @Inject constructor(fileResolver: FileResolver): KotlinBasePluginWrapper(fileResolver) { open class KotlinPluginWrapper @Inject constructor(fileResolver: FileResolver): KotlinBasePluginWrapper(fileResolver) {
override fun getPlugin(kotlinGradleBuildServices: KotlinGradleBuildServices) = override fun getPlugin(kotlinGradleBuildServices: KotlinGradleBuildServices) =
KotlinPlugin(KotlinTasksProvider(), KotlinSourceSetProviderImpl(fileResolver), kotlinPluginVersion, KotlinPlugin(KotlinTasksProvider(), KotlinSourceSetProviderImpl(fileResolver), kotlinPluginVersion, kotlinGradleBuildServices)
kotlinGradleBuildServices.artifactDifferenceRegistry)
} }
open class KotlinAndroidPluginWrapper @Inject constructor(fileResolver: FileResolver): KotlinBasePluginWrapper(fileResolver) { open class KotlinAndroidPluginWrapper @Inject constructor(fileResolver: FileResolver): KotlinBasePluginWrapper(fileResolver) {
override fun getPlugin(kotlinGradleBuildServices: KotlinGradleBuildServices) = override fun getPlugin(kotlinGradleBuildServices: KotlinGradleBuildServices) =
KotlinAndroidPlugin(AndroidTasksProvider(), KotlinSourceSetProviderImpl(fileResolver), kotlinPluginVersion, KotlinAndroidPlugin(AndroidTasksProvider(), KotlinSourceSetProviderImpl(fileResolver), kotlinPluginVersion, kotlinGradleBuildServices)
kotlinGradleBuildServices.artifactDifferenceRegistry)
} }
open class Kotlin2JsPluginWrapper @Inject constructor(fileResolver: FileResolver): KotlinBasePluginWrapper(fileResolver) { open class Kotlin2JsPluginWrapper @Inject constructor(fileResolver: FileResolver): KotlinBasePluginWrapper(fileResolver) {
@@ -1,12 +1,30 @@
package org.jetbrains.kotlin.gradle.tasks package org.jetbrains.kotlin.gradle.tasks
import org.jetbrains.kotlin.incremental.DirtyData import org.jetbrains.kotlin.incremental.DirtyData
import org.jetbrains.kotlin.incremental.IncReporter
import java.io.File import java.io.File
internal interface ArtifactDifferenceRegistry { internal interface ArtifactDifferenceRegistry {
operator fun get(artifact: File): Iterable<ArtifactDifference>? operator fun get(artifact: File): Iterable<ArtifactDifference>?
fun add(artifact: File, difference: ArtifactDifference) fun add(artifact: File, difference: ArtifactDifference)
fun remove(artifact: File) fun remove(artifact: File)
fun flush(memoryCachesOnly: Boolean)
} }
internal class ArtifactDifference(val buildTS: Long, val dirtyData: DirtyData) internal class ArtifactDifference(val buildTS: Long, val dirtyData: DirtyData)
internal interface ArtifactDifferenceRegistryProvider {
fun <T> withRegistry(
report: (String) -> Unit,
fn: (ArtifactDifferenceRegistry) -> T
): T?
fun <T> withRegistry(
reporter: IncReporter,
fn: (ArtifactDifferenceRegistry) -> T
): T? {
return withRegistry({reporter.report {it}}, fn)
}
fun clean()
}
@@ -15,13 +15,15 @@ internal class IncrementalCachesManager (
private var lookupCacheOpen = false private var lookupCacheOpen = false
val incrementalCache: GradleIncrementalCacheImpl by lazy { val incrementalCache: GradleIncrementalCacheImpl by lazy {
val cache = GradleIncrementalCacheImpl(targetDataRoot = incrementalCacheDir.apply { mkdirs() }, targetOutputDir = outputDir, target = targetId)
incrementalCacheOpen = true incrementalCacheOpen = true
GradleIncrementalCacheImpl(targetDataRoot = incrementalCacheDir.apply { mkdirs() }, targetOutputDir = outputDir, target = targetId) cache
} }
val lookupCache: LookupStorage by lazy { val lookupCache: LookupStorage by lazy {
val cache = LookupStorage(lookupCacheDir.apply { mkdirs() })
lookupCacheOpen = true lookupCacheOpen = true
LookupStorage(lookupCacheDir.apply { mkdirs() }) cache
} }
fun clean() { fun clean() {
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil
import org.jetbrains.kotlin.cli.js.K2JSCompiler import org.jetbrains.kotlin.cli.js.K2JSCompiler
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.com.intellij.openapi.util.io.FileUtil import org.jetbrains.kotlin.com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.com.intellij.util.io.PersistentEnumeratorBase
import org.jetbrains.kotlin.compilerRunner.ArgumentUtils import org.jetbrains.kotlin.compilerRunner.ArgumentUtils
import org.jetbrains.kotlin.compilerRunner.OutputItemsCollector import org.jetbrains.kotlin.compilerRunner.OutputItemsCollector
import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl
@@ -31,7 +32,6 @@ import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.incremental.* import org.jetbrains.kotlin.incremental.*
import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.incremental.components.SourceRetentionAnnotationHandler import org.jetbrains.kotlin.incremental.components.SourceRetentionAnnotationHandler
import org.jetbrains.kotlin.incremental.snapshots.FileCollectionDiff
import org.jetbrains.kotlin.modules.TargetId import org.jetbrains.kotlin.modules.TargetId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.progress.CompilationCanceledStatus import org.jetbrains.kotlin.progress.CompilationCanceledStatus
@@ -134,7 +134,7 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
internal val kaptOptions = KaptOptions() internal val kaptOptions = KaptOptions()
internal val pluginOptions = CompilerPluginOptions() internal val pluginOptions = CompilerPluginOptions()
internal var artifactDifferenceRegistry: ArtifactDifferenceRegistry? = null internal var artifactDifferenceRegistryProvider: ArtifactDifferenceRegistryProvider? = null
internal var artifactFile: File? = null internal var artifactFile: File? = null
// created only if kapt2 is active // created only if kapt2 is active
internal var sourceAnnotationsRegistry: SourceAnnotationsRegistry? = null internal var sourceAnnotationsRegistry: SourceAnnotationsRegistry? = null
@@ -177,30 +177,42 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
logger.warn(USING_EXPERIMENTAL_INCREMENTAL_MESSAGE) logger.warn(USING_EXPERIMENTAL_INCREMENTAL_MESSAGE)
anyClassesCompiled = false anyClassesCompiled = false
val javaFilesProcessor = ChangedJavaFilesProcessor()
val targetId = TargetId(name = args.moduleName, type = "java-production") val targetId = TargetId(name = args.moduleName, type = "java-production")
val lookupTracker = LookupTrackerImpl(LookupTracker.DO_NOTHING)
val lastBuildInfo = BuildInfo.read(lastBuildInfoFile) val lastBuildInfo = BuildInfo.read(lastBuildInfoFile)
val caches = IncrementalCachesManager(targetId, cacheDirectory, outputDir)
val reporter = GradleIncReporter(project.rootProject.projectDir) val reporter = GradleIncReporter(project.rootProject.projectDir)
var caches = IncrementalCachesManager(targetId, cacheDirectory, outputDir)
reporter.report { "Last Kotlin Build info for task $path -- $lastBuildInfo" } reporter.report { "Last Kotlin Build info for task $path -- $lastBuildInfo" }
val compilationMode = calculateSourcesToCompile(javaFilesProcessor, try {
caches, val javaFilesProcessor = ChangedJavaFilesProcessor()
lastBuildInfo, val compilationMode = calculateSourcesToCompile(javaFilesProcessor,
changedFiles, caches,
classpath.toList(), lastBuildInfo,
dirtySourcesSinceLastTimeFile, changedFiles,
artifactDifferenceRegistry, classpath.toList(),
reporter) dirtySourcesSinceLastTimeFile,
compileIncrementally(args, caches, javaFilesProcessor, lookupTracker, outputDir, allKotlinSources, targetId, compilationMode, reporter) artifactDifferenceRegistryProvider,
reporter)
compileIncrementally(args, caches, javaFilesProcessor, outputDir, allKotlinSources, targetId, compilationMode, reporter)
}
catch (e: PersistentEnumeratorBase.CorruptedException) {
caches.clean()
artifactDifferenceRegistryProvider?.clean()
reporter.report { "Caches are corrupted. Rebuilding. $e" }
// try to rebuild
val javaFilesProcessor = ChangedJavaFilesProcessor()
caches = IncrementalCachesManager(targetId, cacheDirectory, outputDir)
val compilationMode = CompilationMode.Rebuild()
compileIncrementally(args, caches, javaFilesProcessor, outputDir, allKotlinSources, targetId, compilationMode, reporter)
}
} }
private fun compileIncrementally( private fun compileIncrementally(
args: K2JVMCompilerArguments, args: K2JVMCompilerArguments,
caches: IncrementalCachesManager, caches: IncrementalCachesManager,
javaFilesProcessor: ChangedJavaFilesProcessor, javaFilesProcessor: ChangedJavaFilesProcessor,
lookupTracker: LookupTrackerImpl,
outputDir: File, outputDir: File,
allKotlinSources: List<File>, allKotlinSources: List<File>,
targetId: TargetId, targetId: TargetId,
@@ -234,6 +246,7 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
var exitCode = ExitCode.OK var exitCode = ExitCode.OK
while (dirtySources.any()) { while (dirtySources.any()) {
val lookupTracker = LookupTrackerImpl(LookupTracker.DO_NOTHING)
val outdatedClasses = caches.incrementalCache.classesBySources(dirtySources) val outdatedClasses = caches.incrementalCache.classesBySources(dirtySources)
caches.incrementalCache.markOutputClassesDirty(dirtySources) caches.incrementalCache.markOutputClassesDirty(dirtySources)
caches.incrementalCache.removeClassfilesBySources(dirtySources) caches.incrementalCache.removeClassfilesBySources(dirtySources)
@@ -269,7 +282,11 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
val generatedJavaFilesDiff = caches.incrementalCache.compareAndUpdateFileSnapshots(generatedJavaFiles) val generatedJavaFilesDiff = caches.incrementalCache.compareAndUpdateFileSnapshots(generatedJavaFiles)
if (compilationMode is CompilationMode.Rebuild) { if (compilationMode is CompilationMode.Rebuild) {
artifactFile?.let { artifactDifferenceRegistry?.remove(it) } artifactFile?.let { artifactFile ->
artifactDifferenceRegistryProvider?.withRegistry(reporter) { registry ->
registry.remove(artifactFile)
}
}
break break
} }
@@ -304,10 +321,12 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
if (exitCode == ExitCode.OK && compilationMode is CompilationMode.Incremental) { if (exitCode == ExitCode.OK && compilationMode is CompilationMode.Incremental) {
buildDirtyLookupSymbols.addAll(javaFilesProcessor.allChangedSymbols) buildDirtyLookupSymbols.addAll(javaFilesProcessor.allChangedSymbols)
} }
if (artifactFile != null && artifactDifferenceRegistry != null) { if (artifactFile != null && artifactDifferenceRegistryProvider != null) {
val dirtyData = DirtyData(buildDirtyLookupSymbols, buildDirtyFqNames) val dirtyData = DirtyData(buildDirtyLookupSymbols, buildDirtyFqNames)
val artifactDifference = ArtifactDifference(currentBuildInfo.startTS, dirtyData) val artifactDifference = ArtifactDifference(currentBuildInfo.startTS, dirtyData)
artifactDifferenceRegistry!!.add(artifactFile!!, artifactDifference) artifactDifferenceRegistryProvider!!.withRegistry(reporter) {registry ->
registry.add(artifactFile!!, artifactDifference)
}
reporter.report { reporter.report {
val dirtySymbolsSorted = buildDirtyLookupSymbols.map { it.scope + "#" + it.name }.sorted() val dirtySymbolsSorted = buildDirtyLookupSymbols.map { it.scope + "#" + it.name }.sorted()
"Added artifact difference for $artifactFile (ts: ${currentBuildInfo.startTS}): " + "Added artifact difference for $artifactFile (ts: ${currentBuildInfo.startTS}): " +
@@ -315,6 +334,9 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
} }
} }
artifactDifferenceRegistryProvider?.withRegistry(reporter) {
it.flush(memoryCachesOnly = true)
}
caches.close(flush = true) caches.close(flush = true)
reporter.report { "flushed incremental caches" } reporter.report { "flushed incremental caches" }
processCompilerExitCode(exitCode) processCompilerExitCode(exitCode)
@@ -3,14 +3,16 @@ package org.jetbrains.kotlin.gradle.tasks.incremental
import org.gradle.api.logging.Logging import org.gradle.api.logging.Logging
import org.jetbrains.kotlin.gradle.plugin.kotlinDebug import org.jetbrains.kotlin.gradle.plugin.kotlinDebug
import org.jetbrains.kotlin.gradle.tasks.ArtifactDifferenceRegistry import org.jetbrains.kotlin.gradle.tasks.ArtifactDifferenceRegistry
import org.jetbrains.kotlin.gradle.tasks.ArtifactDifferenceRegistryProvider
import org.jetbrains.kotlin.incremental.CacheVersion import org.jetbrains.kotlin.incremental.CacheVersion
import org.jetbrains.kotlin.incremental.stackTraceStr
import org.jetbrains.kotlin.incremental.storage.BasicMapsOwner import org.jetbrains.kotlin.incremental.storage.BasicMapsOwner
import java.io.File import java.io.File
/** /**
* "Global" cache holder. Should be created once per root project. * "Global" cache holder. Should be created once per root project.
*/ */
internal class BuildCacheStorage(workingDir: File) : BasicMapsOwner() { internal class BuildCacheStorage(workingDir: File) : BasicMapsOwner(), ArtifactDifferenceRegistryProvider {
companion object { companion object {
private val OWN_VERSION = 0 private val OWN_VERSION = 0
private val ARTIFACT_DIFFERENCE = "artifact-difference" private val ARTIFACT_DIFFERENCE = "artifact-difference"
@@ -28,23 +30,56 @@ internal class BuildCacheStorage(workingDir: File) : BasicMapsOwner() {
// assume it's always enabled for simplicity (if IC is not enabled, just don't write to cache) // assume it's always enabled for simplicity (if IC is not enabled, just don't write to cache)
isEnabled = { true }) isEnabled = { true })
internal val artifactDifferenceRegistry: ArtifactDifferenceRegistry @Volatile
private var artifactDifferenceRegistry: ArtifactDifferenceRegistryImpl? = null
private val String.storageFile: File private val String.storageFile: File
get() = File(cachesDir, this + "." + CACHE_EXTENSION) get() = File(cachesDir, this + "." + CACHE_EXTENSION)
init { @Synchronized
if (version.checkVersion() != CacheVersion.Action.DO_NOTHING) { override fun <T> withRegistry(report: (String)->Unit, fn: (ArtifactDifferenceRegistry)->T): T? {
log.kotlinDebug { "Cache version is not up-to-date. Removing $cachesDir" } try {
cachesDir.deleteRecursively() if (artifactDifferenceRegistry == null) {
cachesDir.mkdirs() artifactDifferenceRegistry = registerMap(ArtifactDifferenceRegistryImpl(ARTIFACT_DIFFERENCE.storageFile))
}
return fn(artifactDifferenceRegistry!!)
}
catch (e1: Throwable) {
report("Error accessing artifact file difference registry: ${e1.stackTraceStr}}")
report("Cleaning artifact difference storage and trying again")
clean()
try {
artifactDifferenceRegistry = registerMap(ArtifactDifferenceRegistryImpl(ARTIFACT_DIFFERENCE.storageFile))
return fn(artifactDifferenceRegistry!!)
}
catch (e2: Throwable) {
report("Second error accessing artifact file difference registry: ${e2.stackTraceStr}}")
}
} }
artifactDifferenceRegistry = registerMap(ArtifactDifferenceRegistryImpl(ARTIFACT_DIFFERENCE.storageFile)) return null
} }
init {
if (version.checkVersion() != CacheVersion.Action.DO_NOTHING) {
log.kotlinDebug { "Cache version is not up-to-date" }
clean()
}
}
@Synchronized
override fun clean() { override fun clean() {
super.clean() try {
close()
}
catch (e: Throwable) {
log.kotlinDebug { "Exception while closing caches: ${e.stackTraceStr}" }
}
cachesDir.deleteRecursively()
cachesDir.mkdirs()
versionFile.delete() versionFile.delete()
} }
@@ -52,4 +87,4 @@ internal class BuildCacheStorage(workingDir: File) : BasicMapsOwner() {
super.close() super.close()
version.saveIfNeeded() version.saveIfNeeded()
} }
} }
@@ -18,14 +18,31 @@ package org.jetbrains.kotlin.gradle.tasks.incremental.android
import org.jetbrains.kotlin.gradle.tasks.ArtifactDifference import org.jetbrains.kotlin.gradle.tasks.ArtifactDifference
import org.jetbrains.kotlin.gradle.tasks.ArtifactDifferenceRegistry import org.jetbrains.kotlin.gradle.tasks.ArtifactDifferenceRegistry
import org.jetbrains.kotlin.gradle.tasks.ArtifactDifferenceRegistryProvider
import java.io.File import java.io.File
internal class ArtifactDifferenceRegistryProviderAndroidWrapper(
private val provider: ArtifactDifferenceRegistryProvider,
private val jarToAarMapping: Map<File, File>
) : ArtifactDifferenceRegistryProvider {
override fun <T> withRegistry(report: (String)->Unit, fn: (ArtifactDifferenceRegistry)->T): T? {
return provider.withRegistry(report) { originalRegistry ->
val wrapped = ArtifactDifferenceRegistryAndroidWrapper(originalRegistry, jarToAarMapping)
fn(wrapped)
}
}
override fun clean() {
provider.clean()
}
}
// When lib is compiled, changes are associated with .aar files. // When lib is compiled, changes are associated with .aar files.
// However when app is compiled, there is just .jar in classpath. // However when app is compiled, there is just .jar in classpath.
internal class ArtifactDifferenceRegistryAndroidWrapper( private class ArtifactDifferenceRegistryAndroidWrapper(
private val registry: ArtifactDifferenceRegistry, private val registry: ArtifactDifferenceRegistry,
private val jarToAarMapping: Map<File, File> private val jarToAarMapping: Map<File, File>
): ArtifactDifferenceRegistry by registry { ) : ArtifactDifferenceRegistry by registry {
override fun get(artifact: File): Iterable<ArtifactDifference>? { override fun get(artifact: File): Iterable<ArtifactDifference>? {
val mappedFile = jarToAarMapping[artifact] ?: return null val mappedFile = jarToAarMapping[artifact] ?: return null
return registry[mappedFile] return registry[mappedFile]
@@ -2,11 +2,13 @@ package org.jetbrains.kotlin.gradle.tasks.incremental
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.Task import org.gradle.api.Task
import org.gradle.api.logging.Logger
import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.api.tasks.compile.AbstractCompile
import org.gradle.api.tasks.compile.JavaCompile import org.gradle.api.tasks.compile.JavaCompile
import org.jetbrains.kotlin.com.intellij.openapi.util.io.FileUtil import org.jetbrains.kotlin.com.intellij.openapi.util.io.FileUtil
import org.jetbrains.kotlin.gradle.plugin.kotlinDebug import org.jetbrains.kotlin.gradle.plugin.kotlinDebug
import org.jetbrains.kotlin.gradle.tasks.ArtifactDifferenceRegistry import org.jetbrains.kotlin.gradle.tasks.ArtifactDifferenceRegistry
import org.jetbrains.kotlin.gradle.tasks.ArtifactDifferenceRegistryProvider
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import java.io.File import java.io.File
@@ -15,17 +17,21 @@ internal fun configureMultiProjectIncrementalCompilation(
kotlinTask: KotlinCompile, kotlinTask: KotlinCompile,
javaTask: AbstractCompile, javaTask: AbstractCompile,
kotlinAfterJavaTask: KotlinCompile?, kotlinAfterJavaTask: KotlinCompile?,
artifactDifferenceRegistry: ArtifactDifferenceRegistry, artifactDifferenceRegistryProvider: ArtifactDifferenceRegistryProvider,
artifactFile: File? artifactFile: File?
) { ) {
val log = kotlinTask.logger val log: Logger = kotlinTask.logger
log.kotlinDebug { "Configuring multi-project incremental compilation for project ${project.path}" } log.kotlinDebug { "Configuring multi-project incremental compilation for project ${project.path}" }
fun cannotPerformMultiProjectIC(reason: String) { fun cannotPerformMultiProjectIC(reason: String) {
log.kotlinDebug { log.kotlinDebug {
"Multi-project kotlin incremental compilation won't be performed for projects that depend on ${project.path}: $reason" "Multi-project kotlin incremental compilation won't be performed for projects that depend on ${project.path}: $reason"
} }
artifactFile?.let { artifactDifferenceRegistry.remove(it) } if (artifactFile != null) {
artifactDifferenceRegistryProvider.withRegistry({log.kotlinDebug {it}}) {
it.remove(artifactFile)
}
}
} }
fun isUnknownTaskOutputtingToJavaDestination(task: Task): Boolean { fun isUnknownTaskOutputtingToJavaDestination(task: Task): Boolean {
@@ -46,6 +52,6 @@ internal fun configureMultiProjectIncrementalCompilation(
} }
val kotlinCompile = kotlinAfterJavaTask ?: kotlinTask val kotlinCompile = kotlinAfterJavaTask ?: kotlinTask
kotlinCompile.artifactDifferenceRegistry = artifactDifferenceRegistry kotlinCompile.artifactDifferenceRegistryProvider = artifactDifferenceRegistryProvider
kotlinCompile.artifactFile = artifactFile kotlinCompile.artifactFile = artifactFile
} }
@@ -18,7 +18,7 @@ internal fun calculateSourcesToCompile(
changedFiles: ChangedFiles, changedFiles: ChangedFiles,
classpath: Iterable<File>, classpath: Iterable<File>,
dirtySourcesSinceLastTimeFile: File, dirtySourcesSinceLastTimeFile: File,
artifactDifferenceRegistry: ArtifactDifferenceRegistry?, artifactDifferenceRegistryProvider: ArtifactDifferenceRegistryProvider?,
reporter: IncReporter reporter: IncReporter
): CompilationMode { ): CompilationMode {
fun rebuild(reason: ()->String): CompilationMode { fun rebuild(reason: ()->String): CompilationMode {
@@ -38,7 +38,7 @@ internal fun calculateSourcesToCompile(
val classpathSet = classpath.toHashSet() val classpathSet = classpath.toHashSet()
val modifiedClasspathEntries = changedFiles.modified.filter { it in classpathSet } val modifiedClasspathEntries = changedFiles.modified.filter { it in classpathSet }
val classpathChanges = getClasspathChanges(modifiedClasspathEntries, lastBuildInfo, artifactDifferenceRegistry, reporter) val classpathChanges = getClasspathChanges(modifiedClasspathEntries, lastBuildInfo, artifactDifferenceRegistryProvider, reporter)
if (classpathChanges is ChangesEither.Unknown) { if (classpathChanges is ChangesEither.Unknown) {
return rebuild { "could not get changes from modified classpath entries: ${reporter.pathsAsString(modifiedClasspathEntries)}" } return rebuild { "could not get changes from modified classpath entries: ${reporter.pathsAsString(modifiedClasspathEntries)}" }
} }
@@ -89,14 +89,14 @@ internal fun calculateSourcesToCompile(
private fun getClasspathChanges( private fun getClasspathChanges(
modifiedClasspath: List<File>, modifiedClasspath: List<File>,
lastBuildInfo: BuildInfo?, lastBuildInfo: BuildInfo?,
artifactDifferenceRegistry: ArtifactDifferenceRegistry?, artifactDifferenceRegistryProvider: ArtifactDifferenceRegistryProvider?,
reporter: IncReporter reporter: IncReporter
): ChangesEither { ): ChangesEither {
if (modifiedClasspath.isEmpty()) { if (modifiedClasspath.isEmpty()) {
reporter.report { "No classpath changes" } reporter.report { "No classpath changes" }
return ChangesEither.Known() return ChangesEither.Known()
} }
if (artifactDifferenceRegistry == null) { if (artifactDifferenceRegistryProvider == null) {
reporter.report { "No artifact history provider" } reporter.report { "No artifact history provider" }
return ChangesEither.Unknown() return ChangesEither.Unknown()
} }
@@ -110,7 +110,9 @@ private fun getClasspathChanges(
val symbols = HashSet<LookupSymbol>() val symbols = HashSet<LookupSymbol>()
val fqNames = HashSet<FqName>() val fqNames = HashSet<FqName>()
for (file in modifiedClasspath) { for (file in modifiedClasspath) {
val diffs = artifactDifferenceRegistry[file] val diffs = artifactDifferenceRegistryProvider.withRegistry(reporter) { artifactDifferenceRegistry ->
artifactDifferenceRegistry[file]
}
if (diffs == null) { if (diffs == null) {
reporter.report { "Could not get changes for file: $file" } reporter.report { "Could not get changes for file: $file" }
return ChangesEither.Unknown() return ChangesEither.Unknown()
@@ -0,0 +1,13 @@
package org.jetbrains.kotlin.incremental
import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream
import java.io.PrintStream
internal val Throwable.stackTraceStr: String
get() {
val byteOutputStream = ByteOutputStream()
val printStream = PrintStream(byteOutputStream)
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
(this as? java.lang.Throwable)?.printStackTrace(printStream)
return byteOutputStream.toString()
}