KotlinCompile: Set up artifact transform to take classpath snapshot
This commit sets up the artifact transform only. The actual classpath
snapshotting and computation of classpath changes will be done later.
Bug: KT-45777
Test: Existing IncrementalCompilationClasspathSnapshotJvmMultiProjectIT
and IncrementalJavaChangeClasspathSnapshotIT
This commit is contained in:
committed by
nataliya.valtman
parent
5517aa36e1
commit
c8b3b6df9c
+15
-3
@@ -223,6 +223,8 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
|
||||
|
||||
private fun Kapt3SubpluginContext.getKaptIncrementalDataDir() = temporaryKaptDirectory("incrementalData")
|
||||
|
||||
private fun Kapt3SubpluginContext.getKaptClasspathSnapshotDir() = temporaryKaptDirectory("classpath-snapshot")
|
||||
|
||||
private fun Kapt3SubpluginContext.getKaptIncrementalAnnotationProcessingCache() = temporaryKaptDirectory("incApCache")
|
||||
|
||||
private fun Kapt3SubpluginContext.temporaryKaptDirectory(
|
||||
@@ -645,10 +647,20 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
|
||||
}
|
||||
|
||||
private fun Kapt3SubpluginContext.createKaptGenerateStubsTask(): TaskProvider<KaptGenerateStubsTask> {
|
||||
val properties = PropertiesProvider(project)
|
||||
val kaptTaskName = getKaptTaskName("kaptGenerateStubs")
|
||||
val kaptTaskProvider = project.registerTask<KaptGenerateStubsTask>(kaptTaskName)
|
||||
|
||||
val kaptTaskProvider = project.registerTask<KaptGenerateStubsTask>(kaptTaskName) { kaptTask ->
|
||||
KaptGenerateStubsTask.Configurator(kotlinCompile.get(), kotlinCompilation).configure(kaptTask)
|
||||
val configurator = KaptGenerateStubsTask.Configurator(
|
||||
kotlinCompile,
|
||||
kotlinCompilation,
|
||||
properties,
|
||||
getKaptClasspathSnapshotDir()
|
||||
)
|
||||
configurator.runAtConfigurationTime(kaptTaskProvider, project)
|
||||
|
||||
kaptTaskProvider.configure { kaptTask ->
|
||||
configurator.configure(kaptTask)
|
||||
|
||||
kaptTask.stubsDir.set(getKaptStubsDir())
|
||||
kaptTask.destinationDirectory.set(getKaptIncrementalDataDir())
|
||||
@@ -656,7 +668,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
|
||||
|
||||
kaptTask.kaptClasspath.from(kaptClasspathConfigurations)
|
||||
|
||||
PropertiesProvider(project).mapKotlinTaskProperties(kaptTask)
|
||||
properties.mapKotlinTaskProperties(kaptTask)
|
||||
|
||||
if (!includeCompileClasspath) {
|
||||
kaptTask.onlyIf {
|
||||
|
||||
+15
-4
@@ -17,15 +17,17 @@
|
||||
package org.jetbrains.kotlin.gradle.internal
|
||||
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.Directory
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.*
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
|
||||
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
|
||||
import org.jetbrains.kotlin.gradle.tasks.*
|
||||
import org.jetbrains.kotlin.gradle.tasks.FilteringSourceRootsContainer
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import org.jetbrains.kotlin.gradle.tasks.SourceRoots
|
||||
import org.jetbrains.kotlin.gradle.utils.isParentOf
|
||||
import org.jetbrains.kotlin.incremental.classpathAsList
|
||||
@@ -36,11 +38,20 @@ import java.util.concurrent.Callable
|
||||
@CacheableTask
|
||||
abstract class KaptGenerateStubsTask : KotlinCompile(KotlinJvmOptionsImpl()) {
|
||||
|
||||
class Configurator(private val kotlinCompileTask: KotlinCompile, kotlinCompilation: KotlinCompilationData<*>) :
|
||||
AbstractKotlinCompile.Configurator<KaptGenerateStubsTask>(kotlinCompilation) {
|
||||
internal class Configurator(
|
||||
private val kotlinCompileTaskProvider: TaskProvider<KotlinCompile>,
|
||||
kotlinCompilation: KotlinCompilationData<*>,
|
||||
properties: PropertiesProvider,
|
||||
private val classpathSnapshotDir: File
|
||||
) : KotlinCompile.Configurator<KaptGenerateStubsTask>(kotlinCompilation, properties) {
|
||||
|
||||
override fun getClasspathSnapshotDir(task: KaptGenerateStubsTask): Provider<Directory> =
|
||||
task.project.objects.directoryProperty().dir(classpathSnapshotDir.path)
|
||||
|
||||
override fun configure(task: KaptGenerateStubsTask) {
|
||||
super.configure(task)
|
||||
|
||||
val kotlinCompileTask = kotlinCompileTaskProvider.get()
|
||||
val providerFactory = kotlinCompileTask.project.providers
|
||||
task.useModuleDetection.value(kotlinCompileTask.useModuleDetection).disallowChanges()
|
||||
task.moduleName.value(kotlinCompileTask.moduleName).disallowChanges()
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.internal.transforms
|
||||
|
||||
import org.gradle.api.artifacts.transform.*
|
||||
import org.gradle.api.file.FileSystemLocation
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.Classpath
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile.Companion.CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE
|
||||
|
||||
/** Transform to create a snapshot ([CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE]) of a classpath entry (directory or jar). */
|
||||
@CacheableTransform
|
||||
abstract class ClasspathEntrySnapshotTransform : TransformAction<TransformParameters.None> {
|
||||
|
||||
@get:Classpath
|
||||
@get:InputArtifact
|
||||
abstract val inputArtifact: Provider<FileSystemLocation>
|
||||
|
||||
override fun transform(outputs: TransformOutputs) {
|
||||
val classpathEntry = inputArtifact.get().asFile
|
||||
val snapshotFile = outputs.file(CLASSPATH_ENTRY_SNAPSHOT_FILE_NAME)
|
||||
|
||||
// TODO WORK-IN-PROGRESS
|
||||
val snapshot = "[Place holder - actual snapshot will be inserted in an upcoming change]"
|
||||
snapshotFile.writeText(snapshot)
|
||||
}
|
||||
}
|
||||
|
||||
const val CLASSPATH_ENTRY_SNAPSHOT_FILE_NAME = "classpath-entry-snapshot.bin"
|
||||
+1
-1
@@ -37,7 +37,7 @@ internal fun PropertiesProvider.mapKotlinTaskProperties(task: AbstractKotlinComp
|
||||
usePreciseJavaTracking?.let {
|
||||
task.usePreciseJavaTracking = it
|
||||
}
|
||||
task.useClasspathSnapshot.value(useClasspathSnapshot).disallowChanges()
|
||||
task.classpathSnapshotProperties.useClasspathSnapshot.value(useClasspathSnapshot).disallowChanges()
|
||||
useFir?.let {
|
||||
if (it == true) {
|
||||
task.kotlinOptions.useFir = true
|
||||
|
||||
+125
-7
@@ -10,6 +10,7 @@ import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.file.*
|
||||
import org.gradle.api.invocation.Gradle
|
||||
import org.gradle.api.attributes.Attribute
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.api.provider.ListProperty
|
||||
@@ -43,6 +44,8 @@ import org.jetbrains.kotlin.gradle.internal.*
|
||||
import org.jetbrains.kotlin.gradle.internal.tasks.TaskConfigurator
|
||||
import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState
|
||||
import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles
|
||||
import org.jetbrains.kotlin.gradle.internal.transforms.CLASSPATH_ENTRY_SNAPSHOT_FILE_NAME
|
||||
import org.jetbrains.kotlin.gradle.internal.transforms.ClasspathEntrySnapshotTransform
|
||||
import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger
|
||||
import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector
|
||||
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
|
||||
@@ -193,13 +196,17 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> : AbstractKotl
|
||||
project.plugins.any { it is KotlinPlatformPluginBase || it is KotlinMultiplatformPluginWrapper || it is KotlinPm20PluginWrapper }
|
||||
}
|
||||
).disallowChanges()
|
||||
task.taskBuildDirectory.value(
|
||||
project.layout.buildDirectory.dir("$KOTLIN_BUILD_DIR_NAME/${task.name}")
|
||||
).disallowChanges()
|
||||
task.taskBuildDirectory.value(getKotlinBuildDir(task)).disallowChanges()
|
||||
task.localStateDirectories.from(task.taskBuildDirectory).disallowChanges()
|
||||
|
||||
PropertiesProvider(task.project).mapKotlinDaemonProperties(task)
|
||||
}
|
||||
|
||||
private fun getKotlinBuildDir(task: T): Provider<Directory> =
|
||||
task.project.layout.buildDirectory.dir("$KOTLIN_BUILD_DIR_NAME/${task.name}")
|
||||
|
||||
protected open fun getClasspathSnapshotDir(task: T): Provider<Directory> =
|
||||
task.project.layout.buildDirectory.dir("$KOTLIN_BUILD_DIR_NAME/classpath-snapshot/${task.name}")
|
||||
}
|
||||
|
||||
init {
|
||||
@@ -432,8 +439,53 @@ abstract class KotlinCompile @Inject constructor(
|
||||
KotlinJvmCompile,
|
||||
UsesKotlinJavaToolchain {
|
||||
|
||||
class Configurator(kotlinCompilation: KotlinCompilationData<*>) : AbstractKotlinCompile.Configurator<KotlinCompile>(kotlinCompilation) {
|
||||
override fun configure(task: KotlinCompile) {
|
||||
internal open class Configurator<T : KotlinCompile>(
|
||||
kotlinCompilation: KotlinCompilationData<*>,
|
||||
private val properties: PropertiesProvider
|
||||
) : AbstractKotlinCompile.Configurator<T>(kotlinCompilation) {
|
||||
|
||||
companion object {
|
||||
private const val TRANSFORMS_REGISTERED = "_kgp_internal_kotlin_compile_transforms_registered"
|
||||
|
||||
val ARTIFACT_TYPE_ATTRIBUTE: Attribute<String> = Attribute.of("artifactType", String::class.java)
|
||||
private const val DIRECTORY_ARTIFACT_TYPE = "directory"
|
||||
private const val JAR_ARTIFACT_TYPE = "jar"
|
||||
const val CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE = "classpath-entry-snapshot"
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares for configuration of the task. This method must be called during build configuration, not during task configuration
|
||||
* (which typically happens after build configuration). The reason is that some actions must be performed early (e.g., creating
|
||||
* configurations should be done early to avoid issues with composite builds (https://issuetracker.google.com/183952598)).
|
||||
*/
|
||||
fun runAtConfigurationTime(taskProvider: TaskProvider<T>, project: Project) {
|
||||
if (properties.useClasspathSnapshot) {
|
||||
registerTransformsOnce(project)
|
||||
project.configurations.create(classpathSnapshotConfigurationName(taskProvider.name)).apply {
|
||||
project.dependencies.add(name, project.files(project.provider { taskProvider.get().classpath }))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun registerTransformsOnce(project: Project) {
|
||||
if (project.extensions.extraProperties.has(TRANSFORMS_REGISTERED)) {
|
||||
return
|
||||
}
|
||||
project.extensions.extraProperties[TRANSFORMS_REGISTERED] = true
|
||||
|
||||
project.dependencies.registerTransform(ClasspathEntrySnapshotTransform::class.java) {
|
||||
it.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, JAR_ARTIFACT_TYPE)
|
||||
it.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE)
|
||||
}
|
||||
project.dependencies.registerTransform(ClasspathEntrySnapshotTransform::class.java) {
|
||||
it.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, DIRECTORY_ARTIFACT_TYPE)
|
||||
it.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE)
|
||||
}
|
||||
}
|
||||
|
||||
private fun classpathSnapshotConfigurationName(taskName: String) = "_kgp_internal_${taskName}_classpath_snapshot"
|
||||
|
||||
override fun configure(task: T) {
|
||||
super.configure(task)
|
||||
|
||||
val compileJavaTaskProvider = when (compilation) {
|
||||
@@ -451,6 +503,16 @@ abstract class KotlinCompile @Inject constructor(
|
||||
compileJavaTaskProvider.map { it.name }
|
||||
)
|
||||
}
|
||||
|
||||
if (properties.useClasspathSnapshot) {
|
||||
val classpathSnapshot = task.project.configurations.getByName(classpathSnapshotConfigurationName(task.name))
|
||||
task.classpathSnapshotProperties.classpathSnapshot.from(
|
||||
classpathSnapshot.incoming.artifactView {
|
||||
it.attributes.attribute(ARTIFACT_TYPE_ATTRIBUTE, CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE)
|
||||
}.files
|
||||
)
|
||||
task.classpathSnapshotProperties.classpathSnapshotDir.value(getClasspathSnapshotDir(task)).disallowChanges()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,8 +543,22 @@ abstract class KotlinCompile @Inject constructor(
|
||||
logger.kotlinDebug { "Set $this.usePreciseJavaTracking=$value" }
|
||||
}
|
||||
|
||||
@get:Input
|
||||
abstract val useClasspathSnapshot: Property<Boolean>
|
||||
@get:Nested
|
||||
abstract val classpathSnapshotProperties: ClasspathSnapshotProperties
|
||||
|
||||
/** Properties related to the `kotlin.incremental.useClasspathSnapshot` feature. */
|
||||
abstract class ClasspathSnapshotProperties {
|
||||
@get:Input
|
||||
abstract val useClasspathSnapshot: Property<Boolean>
|
||||
|
||||
@get:Classpath
|
||||
@get:Optional // Set if useClasspathSnapshot == true
|
||||
abstract val classpathSnapshot: ConfigurableFileCollection
|
||||
|
||||
@get:OutputDirectory
|
||||
@get:Optional // Set if useClasspathSnapshot == true
|
||||
abstract val classpathSnapshotDir: DirectoryProperty
|
||||
}
|
||||
|
||||
@get:Internal
|
||||
internal val defaultKotlinJavaToolchain: Provider<DefaultKotlinJavaToolchain> = objects
|
||||
@@ -551,6 +627,9 @@ abstract class KotlinCompile @Inject constructor(
|
||||
val outputItemCollector = OutputItemsCollectorImpl()
|
||||
val compilerRunner = compilerRunner.get()
|
||||
|
||||
if (classpathSnapshotProperties.useClasspathSnapshot.get()) {
|
||||
getClasspathChanges()
|
||||
}
|
||||
val icEnv = if (isIncrementalCompilationEnabled()) {
|
||||
logger.info(USING_JVM_INCREMENTAL_COMPILATION_MESSAGE)
|
||||
IncrementalCompilationEnvironment(
|
||||
@@ -578,6 +657,12 @@ abstract class KotlinCompile @Inject constructor(
|
||||
environment,
|
||||
defaultKotlinJavaToolchain.get().providedJvm.get().javaHome
|
||||
)
|
||||
|
||||
with(classpathSnapshotProperties) {
|
||||
if (useClasspathSnapshot.get()) {
|
||||
copyClasspathSnapshotFilesToDir(classpathSnapshot.files.toList(), classpathSnapshotDir.get().asFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun validateKotlinAndJavaHasSameTargetCompatibility(args: K2JVMCompilerArguments) {
|
||||
@@ -636,6 +721,39 @@ abstract class KotlinCompile @Inject constructor(
|
||||
sourceRootsContainer.add(*sources)
|
||||
return super.source(*sources)
|
||||
}
|
||||
|
||||
private fun getClasspathChanges() {
|
||||
// TODO WORK-IN-PROGRESS
|
||||
val currentClasspathSnapshotFiles = classpathSnapshotProperties.classpathSnapshot.files.toList()
|
||||
val previousClasspathSnapshotFiles = getClasspathSnapshotFilesInDir(classpathSnapshotProperties.classpathSnapshotDir.get().asFile)
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies classpath snapshot files to the given directory.
|
||||
*
|
||||
* To preserve their order, we put them in subdirectories with names being their indices in the original list, as shown below:
|
||||
* classpathSnapshotDir/0/snapshotFileName
|
||||
* classpathSnapshotDir/1/snapshotFileName
|
||||
* ...
|
||||
* classpathSnapshotDir/N-1/snapshotFileName
|
||||
*/
|
||||
private fun copyClasspathSnapshotFilesToDir(classpathSnapshotFiles: List<File>, classpathSnapshotDir: File) {
|
||||
classpathSnapshotDir.deleteRecursively()
|
||||
classpathSnapshotDir.mkdirs()
|
||||
for ((index, file) in classpathSnapshotFiles.withIndex()) {
|
||||
file.copyTo(File("$classpathSnapshotDir/$index/$CLASSPATH_ENTRY_SNAPSHOT_FILE_NAME"), overwrite = true)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all classpath snapshot files in the given directory, sorted by their original indices (the subdirectories' names).
|
||||
*
|
||||
* See [copyClasspathSnapshotFilesToDir] for the structure of the classpath snapshot directory.
|
||||
*/
|
||||
private fun getClasspathSnapshotFilesInDir(classpathSnapshotDir: File): List<File> {
|
||||
val subDirs = classpathSnapshotDir.listFiles() ?: return emptyList()
|
||||
return subDirs.toList().sortedBy { it.name.toInt() }.map { File(it, CLASSPATH_ENTRY_SNAPSHOT_FILE_NAME) }
|
||||
}
|
||||
}
|
||||
|
||||
@CacheableTask
|
||||
|
||||
+11
-5
@@ -21,7 +21,6 @@ import org.gradle.api.Task
|
||||
import org.gradle.api.UnknownTaskException
|
||||
import org.gradle.api.tasks.TaskCollection
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
||||
import org.jetbrains.kotlin.gradle.plugin.mapKotlinTaskProperties
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
|
||||
@@ -89,12 +88,19 @@ internal open class KotlinTasksProvider {
|
||||
): TaskProvider<out KotlinCompile> {
|
||||
val properties = PropertiesProvider(project)
|
||||
val taskClass = taskOrWorkersTask<KotlinCompile, KotlinCompileWithWorkers>(properties)
|
||||
val result = project.registerTask(name, taskClass, constructorArgs = listOf(compilation.kotlinOptions)) {
|
||||
val kotlinCompile = project.registerTask(name, taskClass, constructorArgs = listOf(compilation.kotlinOptions))
|
||||
|
||||
val configurator = KotlinCompile.Configurator<KotlinCompile>(compilation, properties)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
configurator.runAtConfigurationTime(kotlinCompile as TaskProvider<KotlinCompile>, project)
|
||||
|
||||
kotlinCompile.configure {
|
||||
configureAction(it)
|
||||
KotlinCompile.Configurator(compilation).configure(it)
|
||||
configurator.configure(it)
|
||||
}
|
||||
configure(result, project, properties, compilation)
|
||||
return result
|
||||
configure(kotlinCompile, project, properties, compilation)
|
||||
|
||||
return kotlinCompile
|
||||
}
|
||||
|
||||
fun registerKotlinJSTask(
|
||||
|
||||
Reference in New Issue
Block a user