Implement module detection for Gradle IC with Android
#KT-22431 fixed
This commit is contained in:
+11
-2
@@ -65,7 +65,7 @@ class IncrementalCompilationOptions(
|
|||||||
* Directories that should be cleared when IC decides to rebuild
|
* Directories that should be cleared when IC decides to rebuild
|
||||||
*/
|
*/
|
||||||
val localStateDirs: List<File>,
|
val localStateDirs: List<File>,
|
||||||
val buildHistoryFile: File,
|
val multiModuleICSettings: MultiModuleICSettings,
|
||||||
val modulesInfo: IncrementalModuleInfo
|
val modulesInfo: IncrementalModuleInfo
|
||||||
) : CompilationOptions(compilerMode, targetPlatform, reportCategories, reportSeverity, requestedCompilationResults) {
|
) : CompilationOptions(compilerMode, targetPlatform, reportCategories, reportSeverity, requestedCompilationResults) {
|
||||||
companion object {
|
companion object {
|
||||||
@@ -81,13 +81,22 @@ class IncrementalCompilationOptions(
|
|||||||
"workingDir=$workingDir, " +
|
"workingDir=$workingDir, " +
|
||||||
"customCacheVersionFileName='$customCacheVersionFileName', " +
|
"customCacheVersionFileName='$customCacheVersionFileName', " +
|
||||||
"customCacheVersion=$customCacheVersion, " +
|
"customCacheVersion=$customCacheVersion, " +
|
||||||
"buildHistoryFile=$buildHistoryFile, " +
|
"multiModuleICSettings=$multiModuleICSettings, " +
|
||||||
"usePreciseJavaTracking=$usePreciseJavaTracking" +
|
"usePreciseJavaTracking=$usePreciseJavaTracking" +
|
||||||
"localStateDirs=$localStateDirs" +
|
"localStateDirs=$localStateDirs" +
|
||||||
")"
|
")"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class MultiModuleICSettings(
|
||||||
|
val buildHistoryFile: File,
|
||||||
|
val useModuleDetection: Boolean
|
||||||
|
) : Serializable {
|
||||||
|
companion object {
|
||||||
|
const val serialVersionUID: Long = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum class CompilerMode : Serializable {
|
enum class CompilerMode : Serializable {
|
||||||
NON_INCREMENTAL_COMPILER,
|
NON_INCREMENTAL_COMPILER,
|
||||||
INCREMENTAL_COMPILER,
|
INCREMENTAL_COMPILER,
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ import org.jetbrains.kotlin.daemon.report.RemoteICReporter
|
|||||||
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.parsing.classesFqNames
|
import org.jetbrains.kotlin.incremental.parsing.classesFqNames
|
||||||
|
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistoryAndroid
|
||||||
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistoryJvm
|
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistoryJvm
|
||||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
|
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
|
||||||
import org.jetbrains.kotlin.modules.Module
|
import org.jetbrains.kotlin.modules.Module
|
||||||
@@ -523,14 +524,20 @@ class CompileServiceImpl(
|
|||||||
workingDir,
|
workingDir,
|
||||||
enabled = true)
|
enabled = true)
|
||||||
|
|
||||||
val modulesApiHistory = ModulesApiHistoryJvm(incrementalCompilationOptions.modulesInfo)
|
val modulesApiHistory = incrementalCompilationOptions.run {
|
||||||
|
if (!multiModuleICSettings.useModuleDetection) {
|
||||||
|
ModulesApiHistoryJvm(modulesInfo)
|
||||||
|
} else {
|
||||||
|
ModulesApiHistoryAndroid(modulesInfo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val compiler = IncrementalJvmCompilerRunner(
|
val compiler = IncrementalJvmCompilerRunner(
|
||||||
workingDir,
|
workingDir,
|
||||||
javaSourceRoots,
|
javaSourceRoots,
|
||||||
versions,
|
versions,
|
||||||
reporter, annotationFileUpdater,
|
reporter, annotationFileUpdater,
|
||||||
buildHistoryFile = incrementalCompilationOptions.buildHistoryFile,
|
buildHistoryFile = incrementalCompilationOptions.multiModuleICSettings.buildHistoryFile,
|
||||||
localStateDirs = incrementalCompilationOptions.localStateDirs,
|
localStateDirs = incrementalCompilationOptions.localStateDirs,
|
||||||
usePreciseJavaTracking = incrementalCompilationOptions.usePreciseJavaTracking,
|
usePreciseJavaTracking = incrementalCompilationOptions.usePreciseJavaTracking,
|
||||||
modulesApiHistory = modulesApiHistory
|
modulesApiHistory = modulesApiHistory
|
||||||
|
|||||||
+38
@@ -97,5 +97,43 @@ open class ModulesApiHistoryJvm(protected val modulesInfo: IncrementalModuleInfo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ModulesApiHistoryAndroid(modulesInfo: IncrementalModuleInfo) : ModulesApiHistoryJvm(modulesInfo) {
|
||||||
|
override fun getBuildHistoryFilesForJar(jar: File): Either<Set<File>> {
|
||||||
|
// Module detection is expensive, so we don't don it for jars outside of project dir
|
||||||
|
if (!projectRootPath.isParentOf(jar)) return Either.Error("Non-project jar is modified $jar")
|
||||||
|
|
||||||
|
val jarPath = Paths.get(jar.absolutePath)
|
||||||
|
val possibleModules = getPossibleModuleNamesFromJar(jarPath)
|
||||||
|
.flatMapTo(HashSet()) { modulesInfo.nameToModules[it] ?: emptySet() }
|
||||||
|
|
||||||
|
val modules = possibleModules.filter { Paths.get(it.buildDir.absolutePath).isParentOf(jarPath) }
|
||||||
|
if (modules.isEmpty()) return Either.Error("Unknown module for $jar (candidates: ${possibleModules.joinToString()})")
|
||||||
|
|
||||||
|
val result = modules.mapTo(HashSet()) { it.buildHistoryFile }
|
||||||
|
return Either.Success(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getPossibleModuleNamesFromJar(path: Path): Collection<String> {
|
||||||
|
val result = HashSet<String>()
|
||||||
|
|
||||||
|
try {
|
||||||
|
ZipFile(path.toFile()).use { zip ->
|
||||||
|
val entries = zip.entries()
|
||||||
|
while (entries.hasMoreElements()) {
|
||||||
|
val entry = entries.nextElement()
|
||||||
|
val name = entry.name
|
||||||
|
if (name.endsWith(".kotlin_module", ignoreCase = true)) {
|
||||||
|
result.add(File(name).nameWithoutExtension)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun Path.isParentOf(path: Path) = path.startsWith(this)
|
private fun Path.isParentOf(path: Path) = path.startsWith(this)
|
||||||
private fun Path.isParentOf(file: File) = this.isParentOf(Paths.get(file.absolutePath))
|
private fun Path.isParentOf(file: File) = this.isParentOf(Paths.get(file.absolutePath))
|
||||||
+19
@@ -157,6 +157,25 @@ fun getSomething() = 10
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testMultiModuleIC() {
|
||||||
|
val project = Project("AndroidProject", gradleVersion)
|
||||||
|
val options = defaultBuildOptions().copy(incremental = true)
|
||||||
|
|
||||||
|
project.build("assembleDebug", options = options) {
|
||||||
|
assertSuccessful()
|
||||||
|
}
|
||||||
|
|
||||||
|
val libUtilKt = project.projectDir.getFileByName("libUtil.kt")
|
||||||
|
libUtilKt.modify { it.replace("fun libUtil(): String", "fun libUtil(): CharSequence") }
|
||||||
|
|
||||||
|
project.build("assembleDebug", options = options) {
|
||||||
|
assertSuccessful()
|
||||||
|
val affectedSources = project.projectDir.getFilesByNames("libUtil.kt", "MainActivity2.kt")
|
||||||
|
assertCompiledKotlinSources(project.relativize(affectedSources), weakTesting = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testIncrementalBuildWithNoChanges() {
|
fun testIncrementalBuildWithNoChanges() {
|
||||||
val project = Project("AndroidIncrementalSingleModuleProject", gradleVersion)
|
val project = Project("AndroidIncrementalSingleModuleProject", gradleVersion)
|
||||||
|
|||||||
-31
@@ -9,18 +9,6 @@ import org.junit.Test
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class IncrementalCompilationMultiProjectIT : BaseGradleIT() {
|
class IncrementalCompilationMultiProjectIT : BaseGradleIT() {
|
||||||
companion object {
|
|
||||||
private val ANDROID_GRADLE_PLUGIN_VERSION = "1.5.+"
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun androidBuildOptions() =
|
|
||||||
BuildOptions(
|
|
||||||
withDaemon = true,
|
|
||||||
androidHome = KotlinTestUtils.findAndroidSdk(),
|
|
||||||
androidGradlePluginVersion = ANDROID_GRADLE_PLUGIN_VERSION,
|
|
||||||
incremental = true
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun defaultBuildOptions(): BuildOptions =
|
override fun defaultBuildOptions(): BuildOptions =
|
||||||
super.defaultBuildOptions().copy(withDaemon = true, incremental = true)
|
super.defaultBuildOptions().copy(withDaemon = true, incremental = true)
|
||||||
|
|
||||||
@@ -201,25 +189,6 @@ open class A {
|
|||||||
assertCompiledKotlinSources(relativePaths, weakTesting = false)
|
assertCompiledKotlinSources(relativePaths, weakTesting = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testAndroid() {
|
|
||||||
val project = Project("AndroidProject", GradleVersionRequired.Exact("2.10"))
|
|
||||||
val options = androidBuildOptions()
|
|
||||||
|
|
||||||
project.build("assembleDebug", options = options) {
|
|
||||||
assertSuccessful()
|
|
||||||
}
|
|
||||||
|
|
||||||
val libUtilKt = project.projectDir.getFileByName("libUtil.kt")
|
|
||||||
libUtilKt.modify { it.replace("fun libUtil(): String", "fun libUtil(): None") }
|
|
||||||
|
|
||||||
project.build("assembleDebug", options = options) {
|
|
||||||
assertSuccessful()
|
|
||||||
val affectedSources = project.projectDir.getFilesByNames("libUtil.kt", "MainActivity2.kt")
|
|
||||||
assertCompiledKotlinSources(project.relativize(affectedSources), weakTesting = false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class IncrementalJavaChangeDefaultIT : IncrementalCompilationJavaChangesBase(usePreciseJavaTracking = null) {
|
class IncrementalJavaChangeDefaultIT : IncrementalCompilationJavaChangesBase(usePreciseJavaTracking = null) {
|
||||||
|
|||||||
+3
-2
@@ -3,6 +3,7 @@ package org.jetbrains.kotlin.compilerRunner
|
|||||||
import org.jetbrains.kotlin.annotation.AnnotationFileUpdater
|
import org.jetbrains.kotlin.annotation.AnnotationFileUpdater
|
||||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||||
import org.jetbrains.kotlin.config.Services
|
import org.jetbrains.kotlin.config.Services
|
||||||
|
import org.jetbrains.kotlin.daemon.common.MultiModuleICSettings
|
||||||
import org.jetbrains.kotlin.gradle.tasks.GradleMessageCollector
|
import org.jetbrains.kotlin.gradle.tasks.GradleMessageCollector
|
||||||
import org.jetbrains.kotlin.gradle.tasks.findToolsJar
|
import org.jetbrains.kotlin.gradle.tasks.findToolsJar
|
||||||
import org.jetbrains.kotlin.incremental.ChangedFiles
|
import org.jetbrains.kotlin.incremental.ChangedFiles
|
||||||
@@ -31,8 +32,8 @@ internal class GradleIncrementalCompilerEnvironment(
|
|||||||
messageCollector: GradleMessageCollector,
|
messageCollector: GradleMessageCollector,
|
||||||
outputItemsCollector: OutputItemsCollector,
|
outputItemsCollector: OutputItemsCollector,
|
||||||
compilerArgs: CommonCompilerArguments,
|
compilerArgs: CommonCompilerArguments,
|
||||||
val buildHistoryFile: File,
|
|
||||||
val kaptAnnotationsFileUpdater: AnnotationFileUpdater? = null,
|
val kaptAnnotationsFileUpdater: AnnotationFileUpdater? = null,
|
||||||
val usePreciseJavaTracking: Boolean = false,
|
val usePreciseJavaTracking: Boolean = false,
|
||||||
val localStateDirs: List<File> = emptyList()
|
val localStateDirs: List<File> = emptyList(),
|
||||||
|
val multiModuleICSettings: MultiModuleICSettings
|
||||||
) : GradleCompilerEnvironment(compilerClasspath, messageCollector, outputItemsCollector, compilerArgs)
|
) : GradleCompilerEnvironment(compilerClasspath, messageCollector, outputItemsCollector, compilerArgs)
|
||||||
|
|||||||
+1
-1
@@ -275,7 +275,7 @@ internal class GradleCompilerRunner(private val project: Project) : KotlinCompil
|
|||||||
targetPlatform = targetPlatform,
|
targetPlatform = targetPlatform,
|
||||||
usePreciseJavaTracking = environment.usePreciseJavaTracking,
|
usePreciseJavaTracking = environment.usePreciseJavaTracking,
|
||||||
localStateDirs = environment.localStateDirs,
|
localStateDirs = environment.localStateDirs,
|
||||||
buildHistoryFile = environment.buildHistoryFile,
|
multiModuleICSettings = environment.multiModuleICSettings,
|
||||||
modulesInfo = buildModulesInfo(project.gradle)
|
modulesInfo = buildModulesInfo(project.gradle)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+12
-5
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation
|
|||||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||||
import org.jetbrains.kotlin.compilerRunner.*
|
import org.jetbrains.kotlin.compilerRunner.*
|
||||||
|
import org.jetbrains.kotlin.daemon.common.MultiModuleICSettings
|
||||||
import org.jetbrains.kotlin.gradle.dsl.*
|
import org.jetbrains.kotlin.gradle.dsl.*
|
||||||
import org.jetbrains.kotlin.gradle.internal.CompilerArgumentAwareWithInput
|
import org.jetbrains.kotlin.gradle.internal.CompilerArgumentAwareWithInput
|
||||||
import org.jetbrains.kotlin.gradle.internal.prepareCompilerArguments
|
import org.jetbrains.kotlin.gradle.internal.prepareCompilerArguments
|
||||||
@@ -99,6 +100,13 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
|
|||||||
@get:Internal
|
@get:Internal
|
||||||
internal val buildHistoryFile: File get() = File(taskBuildDirectory, "build-history.bin")
|
internal val buildHistoryFile: File get() = File(taskBuildDirectory, "build-history.bin")
|
||||||
|
|
||||||
|
@get:Input
|
||||||
|
internal var useModuleDetection: Boolean = false
|
||||||
|
|
||||||
|
@get:Internal
|
||||||
|
protected val multiModuleICSettings: MultiModuleICSettings
|
||||||
|
get() = MultiModuleICSettings(buildHistoryFile, useModuleDetection)
|
||||||
|
|
||||||
@get:Internal
|
@get:Internal
|
||||||
internal val pluginOptions = CompilerPluginOptions()
|
internal val pluginOptions = CompilerPluginOptions()
|
||||||
|
|
||||||
@@ -353,11 +361,10 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
|
|||||||
computedCompilerClasspath,
|
computedCompilerClasspath,
|
||||||
if (hasFilesInTaskBuildDirectory()) changedFiles else ChangedFiles.Unknown(),
|
if (hasFilesInTaskBuildDirectory()) changedFiles else ChangedFiles.Unknown(),
|
||||||
taskBuildDirectory,
|
taskBuildDirectory,
|
||||||
messageCollector, outputItemCollector, args,
|
messageCollector, outputItemCollector, args, kaptAnnotationsFileUpdater,
|
||||||
buildHistoryFile = buildHistoryFile,
|
|
||||||
kaptAnnotationsFileUpdater = kaptAnnotationsFileUpdater,
|
|
||||||
usePreciseJavaTracking = usePreciseJavaTracking,
|
usePreciseJavaTracking = usePreciseJavaTracking,
|
||||||
localStateDirs = outputDirectories
|
localStateDirs = outputDirectories,
|
||||||
|
multiModuleICSettings = multiModuleICSettings
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -509,7 +516,7 @@ open class Kotlin2JsCompile() : AbstractKotlinCompile<K2JSCompilerArguments>(),
|
|||||||
if (hasFilesInTaskBuildDirectory()) changedFiles else ChangedFiles.Unknown(),
|
if (hasFilesInTaskBuildDirectory()) changedFiles else ChangedFiles.Unknown(),
|
||||||
taskBuildDirectory,
|
taskBuildDirectory,
|
||||||
messageCollector, outputItemCollector, args,
|
messageCollector, outputItemCollector, args,
|
||||||
buildHistoryFile = buildHistoryFile
|
multiModuleICSettings = multiModuleICSettings
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
|
|||||||
+17
-8
@@ -22,25 +22,29 @@ import org.jetbrains.kotlin.gradle.plugin.TaskToFriendTaskMapper
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.mapKotlinTaskProperties
|
import org.jetbrains.kotlin.gradle.plugin.mapKotlinTaskProperties
|
||||||
|
|
||||||
internal open class KotlinTasksProvider {
|
internal open class KotlinTasksProvider {
|
||||||
fun createKotlinJVMTask(project: Project, name: String, sourceSetName: String): KotlinCompile =
|
open fun createKotlinJVMTask(project: Project, name: String, sourceSetName: String): KotlinCompile =
|
||||||
project.tasks.create(name, KotlinCompile::class.java).apply {
|
project.tasks.create(name, KotlinCompile::class.java).apply {
|
||||||
configure(project, sourceSetName)
|
configure(this, project, sourceSetName)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createKotlinJSTask(project: Project, name: String, sourceSetName: String): Kotlin2JsCompile =
|
fun createKotlinJSTask(project: Project, name: String, sourceSetName: String): Kotlin2JsCompile =
|
||||||
project.tasks.create(name, Kotlin2JsCompile::class.java).apply {
|
project.tasks.create(name, Kotlin2JsCompile::class.java).apply {
|
||||||
configure(project, sourceSetName)
|
configure(this, project, sourceSetName)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createKotlinCommonTask(project: Project, name: String, sourceSetName: String): KotlinCompileCommon =
|
fun createKotlinCommonTask(project: Project, name: String, sourceSetName: String): KotlinCompileCommon =
|
||||||
project.tasks.create(name, KotlinCompileCommon::class.java).apply {
|
project.tasks.create(name, KotlinCompileCommon::class.java).apply {
|
||||||
configure(project, sourceSetName)
|
configure(this, project, sourceSetName)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun AbstractKotlinCompile<*>.configure(project: Project, sourceSetName: String) {
|
open fun configure(
|
||||||
this.sourceSetName = sourceSetName
|
kotlinTask: AbstractKotlinCompile<*>,
|
||||||
this.friendTaskName = taskToFriendTaskMapper[this]
|
project: Project,
|
||||||
mapKotlinTaskProperties(project, this)
|
sourceSetName: String
|
||||||
|
) {
|
||||||
|
kotlinTask.sourceSetName = sourceSetName
|
||||||
|
kotlinTask.friendTaskName = taskToFriendTaskMapper[kotlinTask]
|
||||||
|
mapKotlinTaskProperties(project, kotlinTask)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open val taskToFriendTaskMapper: TaskToFriendTaskMapper =
|
protected open val taskToFriendTaskMapper: TaskToFriendTaskMapper =
|
||||||
@@ -60,4 +64,9 @@ internal class Kotlin2JsTasksProvider : KotlinTasksProvider() {
|
|||||||
internal class AndroidTasksProvider : KotlinTasksProvider() {
|
internal class AndroidTasksProvider : KotlinTasksProvider() {
|
||||||
override val taskToFriendTaskMapper: TaskToFriendTaskMapper =
|
override val taskToFriendTaskMapper: TaskToFriendTaskMapper =
|
||||||
RegexTaskToFriendTaskMapper.Android()
|
RegexTaskToFriendTaskMapper.Android()
|
||||||
|
|
||||||
|
override fun configure(kotlinTask: AbstractKotlinCompile<*>, project: Project, sourceSetName: String) {
|
||||||
|
super.configure(kotlinTask, project, sourceSetName)
|
||||||
|
kotlinTask.useModuleDetection = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user