Introduce FSOperationsHelper to mark files dirty

This commit is contained in:
Alexey Tsvetkov
2015-12-01 11:33:14 +03:00
parent 98e0905eb3
commit 87f09ab5b0
2 changed files with 83 additions and 35 deletions
@@ -0,0 +1,56 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.jps.build
import org.jetbrains.jps.ModuleChunk
import org.jetbrains.jps.incremental.CompileContext
import org.jetbrains.jps.incremental.FSOperations
import org.jetbrains.jps.incremental.fs.CompilationRound
import java.io.File
class FSOperationsHelper(private val compileContext: CompileContext, private val chunk: ModuleChunk) {
private var markedDirty = false
fun hasMarkedDirty(): Boolean = markedDirty
fun markChunk(recursively: Boolean = false, kotlinOnly: Boolean = true, excludeFiles: Set<File> = setOf()) {
fun shouldMark(file: File): Boolean {
if (kotlinOnly && !KotlinSourceFileCollector.isKotlinSourceFile(file)) return false
if (file in excludeFiles) return false
markedDirty = true
return true
}
if (recursively) {
FSOperations.markDirtyRecursively(compileContext, CompilationRound.NEXT, chunk, ::shouldMark)
}
else {
FSOperations.markDirty(compileContext, CompilationRound.NEXT, chunk, ::shouldMark)
}
}
fun markFiles(files: Iterable<File>, excludeFiles: Set<File> = setOf()) {
for (file in files) {
if (file in excludeFiles || !file.exists()) continue
FSOperations.markDirty(compileContext, CompilationRound.NEXT, file)
markedDirty = true
}
}
}
@@ -32,7 +32,6 @@ import org.jetbrains.jps.builders.java.dependencyView.Mappings
import org.jetbrains.jps.builders.storage.BuildDataPaths import org.jetbrains.jps.builders.storage.BuildDataPaths
import org.jetbrains.jps.incremental.* import org.jetbrains.jps.incremental.*
import org.jetbrains.jps.incremental.ModuleLevelBuilder.ExitCode.* import org.jetbrains.jps.incremental.ModuleLevelBuilder.ExitCode.*
import org.jetbrains.jps.incremental.fs.CompilationRound
import org.jetbrains.jps.incremental.java.JavaBuilder import org.jetbrains.jps.incremental.java.JavaBuilder
import org.jetbrains.jps.incremental.messages.BuildMessage import org.jetbrains.jps.incremental.messages.BuildMessage
import org.jetbrains.jps.incremental.messages.CompilerMessage import org.jetbrains.jps.incremental.messages.CompilerMessage
@@ -122,10 +121,14 @@ public class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR
): ModuleLevelBuilder.ExitCode { ): ModuleLevelBuilder.ExitCode {
LOG.debug("------------------------------------------") LOG.debug("------------------------------------------")
val messageCollector = MessageCollectorAdapter(context) val messageCollector = MessageCollectorAdapter(context)
val fsOperations = FSOperationsHelper(context, chunk)
try { try {
val exitCode = doBuild(chunk, context, dirtyFilesHolder, messageCollector, outputConsumer) val exitCode = doBuild(chunk, context, dirtyFilesHolder, messageCollector, outputConsumer, fsOperations)
LOG.debug("Build result: " + exitCode) LOG.debug("Build result: " + exitCode)
if (exitCode == OK && fsOperations.hasMarkedDirty()) return ADDITIONAL_PASS_REQUIRED
return exitCode return exitCode
} }
catch (e: StopBuildException) { catch (e: StopBuildException) {
@@ -148,7 +151,9 @@ public class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR
chunk: ModuleChunk, chunk: ModuleChunk,
context: CompileContext, context: CompileContext,
dirtyFilesHolder: DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget>, dirtyFilesHolder: DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget>,
messageCollector: MessageCollectorAdapter, outputConsumer: ModuleLevelBuilder.OutputConsumer messageCollector: MessageCollectorAdapter,
outputConsumer: OutputConsumer,
fsOperations: FSOperationsHelper
): ModuleLevelBuilder.ExitCode { ): ModuleLevelBuilder.ExitCode {
// Workaround for Android Studio // Workaround for Android Studio
if (!JavaBuilder.IS_ENABLED[context, true] && !JpsUtils.isJsKotlinModule(chunk.representativeTarget())) { if (!JavaBuilder.IS_ENABLED[context, true] && !JpsUtils.isJsKotlinModule(chunk.representativeTarget())) {
@@ -163,9 +168,9 @@ public class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR
if (!isFullRebuild && if (!isFullRebuild &&
targets.any { hasKotlin(it, dataManager.dataPaths) } && targets.any { hasKotlin(it, dataManager.dataPaths) } &&
shouldRebuildBecauseVersionChanged(context, dataManager, targets) shouldRebuildBecauseVersionChanged(context, dataManager, targets, fsOperations)
) { ) {
FSOperations.markDirtyRecursively(context, CompilationRound.NEXT, chunk) { KotlinSourceFileCollector.isKotlinSourceFile(it) } fsOperations.markChunk(recursively = true)
val targetsWithDependents = getIncrementalCaches(chunk, context).keys val targetsWithDependents = getIncrementalCaches(chunk, context).keys
targetsWithDependents.forEach { clearHasKotlin(it, dataManager.dataPaths) } targetsWithDependents.forEach { clearHasKotlin(it, dataManager.dataPaths) }
return CHUNK_REBUILD_REQUIRED return CHUNK_REBUILD_REQUIRED
@@ -243,53 +248,41 @@ public class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR
} }
val caches = filesToCompile.keySet().map { incrementalCaches[it]!! } val caches = filesToCompile.keySet().map { incrementalCaches[it]!! }
processChanges(context, chunk, filesToCompile.values(), allCompiledFiles, dataManager, caches, changesInfo) processChanges(filesToCompile.values(), allCompiledFiles, dataManager, caches, changesInfo, fsOperations)
return ADDITIONAL_PASS_REQUIRED return ADDITIONAL_PASS_REQUIRED
} }
private fun processChanges( private fun processChanges(
context: CompileContext,
chunk: ModuleChunk,
compiledFiles: Collection<File>, compiledFiles: Collection<File>,
allCompiledFiles: MutableSet<File>, allCompiledFiles: MutableSet<File>,
dataManager: BuildDataManager, dataManager: BuildDataManager,
caches: List<IncrementalCacheImpl>, caches: List<IncrementalCacheImpl>,
compilationResult: CompilationResult compilationResult: CompilationResult,
fsOperations: FSOperationsHelper
) { ) {
fun recompileInlined() {
for (cache in caches) {
val filesToReinline = cache.getFilesToReinline()
filesToReinline.forEach {
FSOperations.markDirty(context, CompilationRound.NEXT, it)
}
}
}
fun CompilationResult.doProcessChanges() { fun CompilationResult.doProcessChanges() {
fun isKotlin(file: File) = KotlinSourceFileCollector.isKotlinSourceFile(file)
fun isNotCompiled(file: File) = file !in allCompiledFiles
LOG.debug("compilationResult = $this") LOG.debug("compilationResult = $this")
when { when {
inlineAdded -> { inlineAdded -> {
allCompiledFiles.clear() allCompiledFiles.clear()
FSOperations.markDirtyRecursively(context, CompilationRound.NEXT, chunk, ::isKotlin) fsOperations.markChunk(recursively = true)
return return
} }
constantsChanged -> { constantsChanged -> {
FSOperations.markDirtyRecursively(context, CompilationRound.NEXT, chunk, ::isNotCompiled) fsOperations.markChunk(recursively = true, kotlinOnly = false, excludeFiles = allCompiledFiles)
return return
} }
protoChanged -> { protoChanged -> {
FSOperations.markDirty(context, CompilationRound.NEXT, chunk, { isKotlin(it) && isNotCompiled(it) }) fsOperations.markChunk(excludeFiles = allCompiledFiles)
} }
} }
if (inlineChanged) { if (inlineChanged) {
recompileInlined() for (cache in caches) {
fsOperations.markFiles(cache.getFilesToReinline())
}
} }
} }
@@ -312,10 +305,7 @@ public class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR
.toList() .toList()
LOG.debug("Mark dirty files: $files") LOG.debug("Mark dirty files: $files")
fsOperations.markFiles(files)
files.forEach {
FSOperations.markDirty(context, CompilationRound.NEXT, it)
}
} }
LOG.debug("End of processing changes") LOG.debug("End of processing changes")
@@ -331,8 +321,12 @@ public class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR
} }
} }
private fun shouldRebuildBecauseVersionChanged(
private fun shouldRebuildBecauseVersionChanged(context: CompileContext, dataManager: BuildDataManager, targets: MutableSet<ModuleBuildTarget>): Boolean { context: CompileContext,
dataManager: BuildDataManager,
targets: MutableSet<ModuleBuildTarget>,
fsOperations: FSOperationsHelper
): Boolean {
val cacheVersionsProvider = CacheVersionProvider(dataManager.dataPaths) val cacheVersionsProvider = CacheVersionProvider(dataManager.dataPaths)
val allVersions = cacheVersionsProvider.allVersions(targets) val allVersions = cacheVersionsProvider.allVersions(targets)
val actions = allVersions.map { it.checkVersion() }.toSet().sorted() val actions = allVersions.map { it.checkVersion() }.toSet().sorted()
@@ -348,9 +342,7 @@ public class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR
for (sourceRoot in sourceRoots) { for (sourceRoot in sourceRoots) {
val ktFiles = sourceRoot.file.walk().filter { KotlinSourceFileCollector.isKotlinSourceFile(it) } val ktFiles = sourceRoot.file.walk().filter { KotlinSourceFileCollector.isKotlinSourceFile(it) }
ktFiles.forEach { kt -> fsOperations.markFiles(ktFiles.asIterable())
FSOperations.markDirty(context, CompilationRound.NEXT, kt)
}
} }
for (target in allTargets) { for (target in allTargets) {