Refactoring: introduce class ChangedFiles

This commit is contained in:
Alexey Tsvetkov
2016-10-03 19:06:55 +03:00
parent e9d4d85af2
commit b4c17dabf4
2 changed files with 48 additions and 35 deletions
@@ -0,0 +1,22 @@
package org.jetbrains.kotlin.gradle.tasks
import org.gradle.api.tasks.incremental.IncrementalTaskInputs
import java.io.File
import java.util.*
internal sealed class ChangedFiles {
class Known(val modified: List<File>, val removed: List<File>) : ChangedFiles()
class Unknown : ChangedFiles()
}
internal fun ChangedFiles(taskInputs: IncrementalTaskInputs): ChangedFiles {
if (!taskInputs.isIncremental) return ChangedFiles.Unknown()
val modified = ArrayList<File>()
val removed = ArrayList<File>()
taskInputs.outOfDate { modified.add(it.file) }
taskInputs.removed { removed.add(it.file) }
return ChangedFiles.Known(modified, removed)
}
@@ -77,31 +77,29 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractCo
@TaskAction @TaskAction
fun execute(inputs: IncrementalTaskInputs): Unit { fun execute(inputs: IncrementalTaskInputs): Unit {
logger.kotlinDebug("all sources ${getSource().joinToString { it.path }}") val allKotlinSources = getKotlinSources()
logger.kotlinDebug("is incremental == ${inputs.isIncremental}") logger.kotlinDebug { "all kotlin sources: ${filesToString(allKotlinSources)}" }
val modified = arrayListOf<File>()
val removed = arrayListOf<File>() if (allKotlinSources.isEmpty()) {
if (inputs.isIncremental) {
inputs.outOfDate { modified.add(it.file) }
inputs.removed { removed.add(it.file) }
}
logger.kotlinDebug("modified ${modified.joinToString { it.path }}")
logger.kotlinDebug("removed ${removed.joinToString { it.path }}")
val sources = getKotlinSources()
if (sources.isEmpty()) {
logger.kotlinDebug { "No Kotlin files found, skipping Kotlin compiler task" } logger.kotlinDebug { "No Kotlin files found, skipping Kotlin compiler task" }
return return
} }
val args = populateCompilerArguments() val args = populateCompilerArguments()
compilerCalled = true compilerCalled = true
callCompiler(args, sources, inputs.isIncremental, modified, removed) callCompiler(args, allKotlinSources, ChangedFiles(inputs))
} }
private fun getKotlinSources(): List<File> = (getSource() as Iterable<File>).filter { it.isKotlinFile() } private fun getKotlinSources(): List<File> = (getSource() as Iterable<File>).filter(File::isKotlinFile)
protected abstract fun callCompiler(args: T, allKotlinSources: List<File>, isIncremental: Boolean, modified: List<File>, removed: List<File>) internal abstract fun callCompiler(args: T, allKotlinSources: List<File>, changedFiles: ChangedFiles)
internal fun relativePathOrCanonical(file: File): String =
file.relativeToOrNull(project.rootProject.projectDir)?.path
?: file.canonicalPath
internal fun filesToString(files: Iterable<File>) =
"[" + files.map { relativePathOrCanonical(it) }.sorted().joinToString(separator = ", \n") + "]"
} }
open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), KotlinJvmCompile { open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), KotlinJvmCompile {
@@ -175,9 +173,8 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
return args return args
} }
override fun callCompiler(args: K2JVMCompilerArguments, allKotlinSources: List<File>, isIncrementalRequested: Boolean, modified: List<File>, removed: List<File>) { override fun callCompiler(args: K2JVMCompilerArguments, allKotlinSources: List<File>, changedFiles: ChangedFiles) {
val outputDir = destinationDir val outputDir = destinationDir
var currentRemoved = removed.filter { it.isKotlinFile() }
val logAction = { logStr: String -> logger.kotlinInfo(logStr) } val logAction = { logStr: String -> logger.kotlinInfo(logStr) }
val relativePathOrCanonical = { file: File -> relativePathOrCanonical(file) } val relativePathOrCanonical = { file: File -> relativePathOrCanonical(file) }
@@ -221,7 +218,7 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
return ChangesEither.Known(symbols, fqNames) return ChangesEither.Known(symbols, fqNames)
} }
fun calculateSourcesToCompile(javaFilesProcessor: ChangedJavaFilesProcessor, caches: IncrementalCachesManager, lastBuildInfo: BuildInfo?): Pair<Set<File>, Boolean> { fun calculateSourcesToCompile(javaFilesProcessor: ChangedJavaFilesProcessor, caches: IncrementalCachesManager, lastBuildInfo: BuildInfo?, changedFiles: ChangedFiles): Pair<Set<File>, Boolean> {
fun rebuild(reason: String): Pair<Set<File>, Boolean> { fun rebuild(reason: String): Pair<Set<File>, Boolean> {
logger.kotlinInfo("Non-incremental compilation will be performed: $reason") logger.kotlinInfo("Non-incremental compilation will be performed: $reason")
caches.clean() caches.clean()
@@ -230,15 +227,15 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
} }
if (!incremental) return rebuild("incremental compilation is not enabled") if (!incremental) return rebuild("incremental compilation is not enabled")
if (!isIncrementalRequested) return rebuild("inputs' changes are unknown (first or clean build)") if (changedFiles !is ChangedFiles.Known) return rebuild("inputs' changes are unknown (first or clean build)")
val removedClassFiles = removed.filter(File::isClassFile) val removedClassFiles = changedFiles.removed.filter(File::isClassFile)
if (removedClassFiles.any()) return rebuild("Removed class files: ${filesToString(removedClassFiles)}") if (removedClassFiles.any()) return rebuild("Removed class files: ${filesToString(removedClassFiles)}")
val modifiedClassFiles = modified.filter(File::isClassFile) val modifiedClassFiles = changedFiles.modified.filter(File::isClassFile)
if (modifiedClassFiles.any()) return rebuild("Modified class files: ${filesToString(modifiedClassFiles)}") if (modifiedClassFiles.any()) return rebuild("Modified class files: ${filesToString(modifiedClassFiles)}")
val modifiedClasspathEntries = modified.filter { it in classpath } val modifiedClasspathEntries = changedFiles.modified.filter { it in classpath }
val classpathChanges = getClasspathChanges(modifiedClasspathEntries, lastBuildInfo) val classpathChanges = getClasspathChanges(modifiedClasspathEntries, lastBuildInfo)
if (classpathChanges is ChangesEither.Unknown) { if (classpathChanges is ChangesEither.Unknown) {
return rebuild("could not get changes from modified classpath entries: ${filesToString(modifiedClasspathEntries)}") return rebuild("could not get changes from modified classpath entries: ${filesToString(modifiedClasspathEntries)}")
@@ -247,15 +244,15 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
throw AssertionError("Unknown implementation of ChangesEither: ${classpathChanges.javaClass}") throw AssertionError("Unknown implementation of ChangesEither: ${classpathChanges.javaClass}")
} }
val javaFilesDiff = FileCollectionDiff( val javaFilesDiff = FileCollectionDiff(
newOrModified = modified.filter { it.isJavaFile() }, newOrModified = changedFiles.modified.filter(File::isJavaFile),
removed = removed.filter { it.isJavaFile() }) removed = changedFiles.removed.filter(File::isJavaFile))
val javaFilesChanges = javaFilesProcessor.process(javaFilesDiff) val javaFilesChanges = javaFilesProcessor.process(javaFilesDiff)
val affectedJavaSymbols = when (javaFilesChanges) { val affectedJavaSymbols = when (javaFilesChanges) {
is ChangesEither.Known -> javaFilesChanges.lookupSymbols is ChangesEither.Known -> javaFilesChanges.lookupSymbols
is ChangesEither.Unknown -> return rebuild("Could not get changes for java files") is ChangesEither.Unknown -> return rebuild("Could not get changes for java files")
} }
val dirtyFiles = modified.filter { it.isKotlinFile() }.toMutableSet() val dirtyFiles = changedFiles.modified.filter(File::isKotlinFile).toMutableSet()
val lookupSymbols = HashSet<LookupSymbol>() val lookupSymbols = HashSet<LookupSymbol>()
lookupSymbols.addAll(affectedJavaSymbols) lookupSymbols.addAll(affectedJavaSymbols)
lookupSymbols.addAll(classpathChanges.lookupSymbols) lookupSymbols.addAll(classpathChanges.lookupSymbols)
@@ -299,8 +296,9 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
val caches = IncrementalCachesManager(targetId, cacheDirectory, outputDir) val caches = IncrementalCachesManager(targetId, cacheDirectory, outputDir)
// TODO: decide what to do if no files are considered dirty - rebuild or skip the module // TODO: decide what to do if no files are considered dirty - rebuild or skip the module
var (sourcesToCompile, isIncrementalDecided) = calculateSourcesToCompile(javaFilesProcessor, caches, lastBuildInfo) var (sourcesToCompile, isIncrementalDecided) = calculateSourcesToCompile(javaFilesProcessor, caches, lastBuildInfo, changedFiles)
compileIncrementally(allGeneratedFiles, args, caches, currentRemoved, isIncrementalDecided, javaFilesProcessor, logAction, lookupTracker, outputDir, relativePathOrCanonical, allKotlinSources, sourcesToCompile, targetId) val currentRemoved = (changedFiles as? ChangedFiles.Known)?.removed?.filter(File::isKotlinFile) ?: emptyList()
compileIncrementally(args, caches, currentRemoved, isIncrementalDecided, javaFilesProcessor, logAction, lookupTracker, outputDir, relativePathOrCanonical, allKotlinSources, sourcesToCompile, targetId)
} }
private fun compileIncrementally( private fun compileIncrementally(
@@ -424,13 +422,6 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
processCompilerExitCode(exitCode) processCompilerExitCode(exitCode)
} }
private fun relativePathOrCanonical(file: File): String =
file.relativeToOrNull(project.rootProject.projectDir)?.path
?: file.canonicalPath
private fun filesToString(files: Iterable<File>) =
"[" + files.map { relativePathOrCanonical(it) }.sorted().joinToString(separator = ", \n") + "]"
private fun cleanupOnError() { private fun cleanupOnError() {
logger.kotlinInfo("deleting $destinationDir on error") logger.kotlinInfo("deleting $destinationDir on error")
destinationDir.deleteRecursively() destinationDir.deleteRecursively()
@@ -639,7 +630,7 @@ open class Kotlin2JsCompile() : AbstractKotlinCompile<K2JSCompilerArguments>(),
return args return args
} }
override fun callCompiler(args: K2JSCompilerArguments, allKotlinSources: List<File>, isIncremental: Boolean, modified: List<File>, removed: List<File>) { override fun callCompiler(args: K2JSCompilerArguments, allKotlinSources: List<File>, changedFiles: ChangedFiles) {
val messageCollector = GradleMessageCollector(logger) val messageCollector = GradleMessageCollector(logger)
logger.debug("Calling compiler") logger.debug("Calling compiler")
destinationDir.mkdirs() destinationDir.mkdirs()