Track changes for jar files for non-Android Gradle projects
This commit is contained in:
+2
-1
@@ -22,7 +22,8 @@ data class IncrementalModuleEntry(
|
|||||||
class IncrementalModuleInfo(
|
class IncrementalModuleInfo(
|
||||||
val projectRoot: File,
|
val projectRoot: File,
|
||||||
val dirToModule: Map<File, IncrementalModuleEntry>,
|
val dirToModule: Map<File, IncrementalModuleEntry>,
|
||||||
val nameToModules: Map<String, Set<IncrementalModuleEntry>>
|
val nameToModules: Map<String, Set<IncrementalModuleEntry>>,
|
||||||
|
val jarToClassListFile: Map<File, File>
|
||||||
) : Serializable {
|
) : Serializable {
|
||||||
companion object {
|
companion object {
|
||||||
private const val serialVersionUID = 0L
|
private const val serialVersionUID = 0L
|
||||||
|
|||||||
@@ -48,8 +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.EmptyModulesApiHistory
|
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistoryJvm
|
||||||
import org.jetbrains.kotlin.incremental.multiproject.ModulesApiHistoryImpl
|
|
||||||
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
|
||||||
import org.jetbrains.kotlin.progress.CompilationCanceledStatus
|
import org.jetbrains.kotlin.progress.CompilationCanceledStatus
|
||||||
@@ -524,9 +523,7 @@ class CompileServiceImpl(
|
|||||||
workingDir,
|
workingDir,
|
||||||
enabled = true)
|
enabled = true)
|
||||||
|
|
||||||
val modulesApiHistory = incrementalCompilationOptions.run {
|
val modulesApiHistory = ModulesApiHistoryJvm(incrementalCompilationOptions.modulesInfo)
|
||||||
ModulesApiHistoryImpl(modulesInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
val compiler = IncrementalJvmCompilerRunner(
|
val compiler = IncrementalJvmCompilerRunner(
|
||||||
workingDir,
|
workingDir,
|
||||||
|
|||||||
+26
-11
@@ -21,10 +21,8 @@ object EmptyModulesApiHistory : ModulesApiHistory {
|
|||||||
Either.Error("Multi-module IC is not configured")
|
Either.Error("Multi-module IC is not configured")
|
||||||
}
|
}
|
||||||
|
|
||||||
class ModulesApiHistoryImpl(
|
open class ModulesApiHistoryJvm(protected val modulesInfo: IncrementalModuleInfo) : ModulesApiHistory {
|
||||||
private val modulesInfo: IncrementalModuleInfo
|
protected val projectRootPath: Path = Paths.get(modulesInfo.projectRoot.absolutePath)
|
||||||
) : ModulesApiHistory {
|
|
||||||
private val projectRootPath = Paths.get(modulesInfo.projectRoot.absolutePath)
|
|
||||||
private val dirToHistoryFileCache = HashMap<File, File?>()
|
private val dirToHistoryFileCache = HashMap<File, File?>()
|
||||||
|
|
||||||
override fun historyFilesForChangedFiles(changedFiles: Set<File>): Either<Set<File>> {
|
override fun historyFilesForChangedFiles(changedFiles: Set<File>): Either<Set<File>> {
|
||||||
@@ -46,9 +44,9 @@ class ModulesApiHistoryImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (jar in jarFiles) {
|
for (jar in jarFiles) {
|
||||||
val historyEither = getBuildHistoryForJar(jar)
|
val historyEither = getBuildHistoryFilesForJar(jar)
|
||||||
when (historyEither) {
|
when (historyEither) {
|
||||||
is Either.Success<File> -> result.add(historyEither.value)
|
is Either.Success<Set<File>> -> result.addAll(historyEither.value)
|
||||||
is Either.Error -> return historyEither
|
is Either.Error -> return historyEither
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -78,9 +76,26 @@ class ModulesApiHistoryImpl(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getBuildHistoryForJar(jar: File): Either<File> =
|
protected open fun getBuildHistoryFilesForJar(jar: File): Either<Set<File>> {
|
||||||
Either.Error("Cannot get changes for jar $jar")
|
val classListFile = modulesInfo.jarToClassListFile[jar] ?: return Either.Error("Unknown jar: $jar")
|
||||||
|
if (!classListFile.isFile) return Either.Error("Class list file does not exist $classListFile")
|
||||||
|
|
||||||
private fun Path.isParentOf(path: Path) = path.startsWith(this)
|
val classFiles = try {
|
||||||
private fun Path.isParentOf(file: File) = this.isParentOf(Paths.get(file.absolutePath))
|
classListFile.readText().split(File.pathSeparator).map(::File)
|
||||||
}
|
} catch (t: Throwable) {
|
||||||
|
return Either.Error("Could not read class list for $jar from $classListFile: $t")
|
||||||
|
}
|
||||||
|
|
||||||
|
val classFileDirs = classFiles.groupBy { it.parentFile }
|
||||||
|
val result = HashSet<File>()
|
||||||
|
for ((dir, files) in classFileDirs) {
|
||||||
|
val buildHistory = getBuildHistoryForDir(dir)
|
||||||
|
?: return Either.Error("Could not get build history for class files: ${files.joinToString()}")
|
||||||
|
result.add(buildHistory)
|
||||||
|
}
|
||||||
|
return Either.Success(result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Path.isParentOf(path: Path) = path.startsWith(this)
|
||||||
|
private fun Path.isParentOf(file: File) = this.isParentOf(Paths.get(file.absolutePath))
|
||||||
+10
-10
@@ -25,14 +25,14 @@ internal open class GradleCompilerEnvironment(
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal class GradleIncrementalCompilerEnvironment(
|
internal class GradleIncrementalCompilerEnvironment(
|
||||||
compilerClasspath: List<File>,
|
compilerClasspath: List<File>,
|
||||||
val changedFiles: ChangedFiles,
|
val changedFiles: ChangedFiles,
|
||||||
val workingDir: File,
|
val workingDir: File,
|
||||||
messageCollector: GradleMessageCollector,
|
messageCollector: GradleMessageCollector,
|
||||||
outputItemsCollector: OutputItemsCollector,
|
outputItemsCollector: OutputItemsCollector,
|
||||||
compilerArgs: CommonCompilerArguments,
|
compilerArgs: CommonCompilerArguments,
|
||||||
val buildHistoryFile: File,
|
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()
|
||||||
) : GradleCompilerEnvironment(compilerClasspath, messageCollector, outputItemsCollector, compilerArgs)
|
) : GradleCompilerEnvironment(compilerClasspath, messageCollector, outputItemsCollector, compilerArgs)
|
||||||
|
|||||||
+15
-6
@@ -35,6 +35,7 @@ import org.jetbrains.kotlin.daemon.common.*
|
|||||||
import org.jetbrains.kotlin.daemon.common.IncrementalModuleEntry
|
import org.jetbrains.kotlin.daemon.common.IncrementalModuleEntry
|
||||||
import org.jetbrains.kotlin.daemon.common.IncrementalModuleInfo
|
import org.jetbrains.kotlin.daemon.common.IncrementalModuleInfo
|
||||||
import org.jetbrains.kotlin.gradle.plugin.kotlinDebug
|
import org.jetbrains.kotlin.gradle.plugin.kotlinDebug
|
||||||
|
import org.jetbrains.kotlin.gradle.tasks.InspectClassesForMultiModuleIC
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
import org.jetbrains.kotlin.incremental.*
|
import org.jetbrains.kotlin.incremental.*
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
@@ -356,17 +357,25 @@ internal class GradleCompilerRunner(private val project: Project) : KotlinCompil
|
|||||||
|
|
||||||
val dirToModule = HashMap<File, IncrementalModuleEntry>()
|
val dirToModule = HashMap<File, IncrementalModuleEntry>()
|
||||||
val nameToModules = HashMap<String, HashSet<IncrementalModuleEntry>>()
|
val nameToModules = HashMap<String, HashSet<IncrementalModuleEntry>>()
|
||||||
|
val jarToClassListFile = HashMap<File, File>()
|
||||||
|
|
||||||
for (project in gradle.rootProject.allprojects) {
|
for (project in gradle.rootProject.allprojects) {
|
||||||
for (task in project.tasks.withType(KotlinCompile::class.java)) {
|
for (task in project.tasks) {
|
||||||
val module = IncrementalModuleEntry(project.path, task.moduleName, project.buildDir, task.buildHistoryFile)
|
when (task) {
|
||||||
dirToModule[task.destinationDir] = module
|
is KotlinCompile -> {
|
||||||
task.javaOutputDir?.let { dirToModule[it] = module }
|
val module = IncrementalModuleEntry(project.path, task.moduleName, project.buildDir, task.buildHistoryFile)
|
||||||
nameToModules.getOrPut(module.name) { HashSet() }.add(module)
|
dirToModule[task.destinationDir] = module
|
||||||
|
task.javaOutputDir?.let { dirToModule[it] = module }
|
||||||
|
nameToModules.getOrPut(module.name) { HashSet() }.add(module)
|
||||||
|
}
|
||||||
|
is InspectClassesForMultiModuleIC -> {
|
||||||
|
jarToClassListFile[File(task.archivePath)] = task.classesListFile
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return IncrementalModuleInfo(gradle.rootProject.projectDir, dirToModule, nameToModules)
|
return IncrementalModuleInfo(gradle.rootProject.projectDir, dirToModule, nameToModules, jarToClassListFile)
|
||||||
.also {
|
.also {
|
||||||
cachedGradle = WeakReference(gradle)
|
cachedGradle = WeakReference(gradle)
|
||||||
cachedModulesInfo = it
|
cachedModulesInfo = it
|
||||||
|
|||||||
+20
@@ -23,6 +23,7 @@ import org.gradle.api.plugins.JavaPluginConvention
|
|||||||
import org.gradle.api.tasks.*
|
import org.gradle.api.tasks.*
|
||||||
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.gradle.jvm.tasks.Jar
|
||||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl
|
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl
|
||||||
import org.jetbrains.kotlin.gradle.internal.*
|
import org.jetbrains.kotlin.gradle.internal.*
|
||||||
@@ -358,6 +359,7 @@ internal abstract class AbstractKotlinPlugin(
|
|||||||
|
|
||||||
configureSourceSetDefaults(project, javaBasePlugin, javaPluginConvention)
|
configureSourceSetDefaults(project, javaBasePlugin, javaPluginConvention)
|
||||||
configureDefaultVersionsResolutionStrategy(project)
|
configureDefaultVersionsResolutionStrategy(project)
|
||||||
|
configureClassInspectionForIC(project)
|
||||||
}
|
}
|
||||||
|
|
||||||
open protected fun configureSourceSetDefaults(
|
open protected fun configureSourceSetDefaults(
|
||||||
@@ -390,6 +392,24 @@ internal abstract class AbstractKotlinPlugin(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun configureClassInspectionForIC(project: Project) {
|
||||||
|
val classesTask = project.tasks.findByName(JavaPlugin.CLASSES_TASK_NAME)
|
||||||
|
val jarTask = project.tasks.findByName(JavaPlugin.JAR_TASK_NAME)
|
||||||
|
|
||||||
|
if (classesTask == null || jarTask !is Jar) {
|
||||||
|
project.logger.info(
|
||||||
|
"Could not configure class inspection task " +
|
||||||
|
"(classes task = ${classesTask?.javaClass?.canonicalName}, " +
|
||||||
|
"jar task = ${classesTask?.javaClass?.canonicalName}"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val inspectTask = project.tasks.create("inspectClassesForKotlinIC", InspectClassesForMultiModuleIC::class.java)
|
||||||
|
inspectTask.jarTask = jarTask
|
||||||
|
inspectTask.dependsOn(classesTask)
|
||||||
|
jarTask.dependsOn(inspectTask)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal open class KotlinPlugin(
|
internal open class KotlinPlugin(
|
||||||
|
|||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.gradle.tasks
|
||||||
|
|
||||||
|
import org.gradle.api.DefaultTask
|
||||||
|
import org.gradle.api.file.FileCollection
|
||||||
|
import org.gradle.api.tasks.*
|
||||||
|
import org.gradle.jvm.tasks.Jar
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.inputsCompatible
|
||||||
|
import org.jetbrains.kotlin.incremental.isClassFile
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
internal open class InspectClassesForMultiModuleIC : DefaultTask() {
|
||||||
|
@get:Internal
|
||||||
|
lateinit var jarTask: Jar
|
||||||
|
|
||||||
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
|
@get:OutputFile
|
||||||
|
internal val classesListFile: File
|
||||||
|
get() = File(File(project.buildDir, KOTLIN_BUILD_DIR_NAME), "${sanitizeFileName(jarTask.archiveName)}-classes.txt")
|
||||||
|
|
||||||
|
@Suppress("MemberVisibilityCanBePrivate")
|
||||||
|
@get:InputFiles
|
||||||
|
internal val classFiles: FileCollection
|
||||||
|
get() = jarTask.inputsCompatible.files.filter { it.isClassFile() }
|
||||||
|
|
||||||
|
@get:Input
|
||||||
|
internal val archivePath: String
|
||||||
|
get() = jarTask.archivePath.canonicalPath
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
fun run() {
|
||||||
|
classesListFile.parentFile.mkdirs()
|
||||||
|
val paths = classFiles.map { it.canonicalPath }.sorted()
|
||||||
|
val text = paths.joinToString(File.pathSeparator)
|
||||||
|
classesListFile.writeText(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun sanitizeFileName(candidate: String): String =
|
||||||
|
candidate.filter { it.isLetterOrDigit() }
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user