From d46ad6c0ad275933ee7a5b7a377e0284e367e697 Mon Sep 17 00:00:00 2001 From: Yahor Berdnikau Date: Thu, 18 Mar 2021 17:41:46 +0100 Subject: [PATCH] Fix kapt creates output directories on configuration phase. Gradle will create such directories itself. Also it should fix build cache issue with kapt tasks - build cache was disabled due to the 'overlapping outputs'. ^KT-45532 Fixed --- buildSrc/src/main/kotlin/tasks.kt | 1 + .../jetbrains/kotlin/gradle/Kapt3AndroidIT.kt | 13 +++++ .../kapt/Kapt3KotlinGradleSubplugin.kt | 25 +++++----- .../internal/kapt/KaptGenerateStubsTask.kt | 11 +++-- .../kotlin/gradle/internal/kapt/KaptTask.kt | 47 ++++++++++--------- .../internal/kapt/KaptWithKotlincTask.kt | 8 +++- .../internal/kapt/KaptWithoutKotlincTask.kt | 13 +++-- 7 files changed, 72 insertions(+), 46 deletions(-) diff --git a/buildSrc/src/main/kotlin/tasks.kt b/buildSrc/src/main/kotlin/tasks.kt index 0dcd51280bb..38c9c8c80fe 100644 --- a/buildSrc/src/main/kotlin/tasks.kt +++ b/buildSrc/src/main/kotlin/tasks.kt @@ -28,6 +28,7 @@ val kotlinGradlePluginAndItsRequired = arrayOf( ":kotlin-noarg", ":kotlin-sam-with-receiver", ":kotlin-android-extensions", + ":kotlin-android-extensions-runtime", ":kotlin-parcelize-compiler", ":kotlin-build-common", ":kotlin-compiler-embeddable", diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3AndroidIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3AndroidIT.kt index 4bdedd6b7dc..e75c5736976 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3AndroidIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kapt3AndroidIT.kt @@ -273,6 +273,19 @@ abstract class Kapt3AndroidIT : Kapt3BaseIT() { } } + // KT-45532 + @Test + open fun kaptTasksShouldNotCreateOutputsOnConfigurationPhase() { + Project( + "android-dagger", + directoryPrefix = "kapt2" + ).build("--dry-run", "assembleDebug") { + assertSuccessful() + assertNoSuchFile("app/build/tmp") + assertNoSuchFile("app/build/generated") + } + } + private fun setupDataBinding(project: Project) { project.setupWorkingDir() diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt index eb48eab1225..18dc98db610 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt @@ -198,17 +198,13 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To private fun Kapt3SubpluginContext.getKaptStubsDir() = temporaryKaptDirectory("stubs") - private fun Kapt3SubpluginContext.getKaptIncrementalDataDir() = temporaryKaptDirectory("incrementalData", doMkDirs = false) + private fun Kapt3SubpluginContext.getKaptIncrementalDataDir() = temporaryKaptDirectory("incrementalData") private fun Kapt3SubpluginContext.getKaptIncrementalAnnotationProcessingCache() = temporaryKaptDirectory("incApCache") - private fun Kapt3SubpluginContext.temporaryKaptDirectory(name: String, doMkDirs: Boolean = true): File { - val dir = File(project.buildDir, "tmp/kapt3/$name/$sourceSetName") - if (doMkDirs) { - dir.mkdirs() - } - return dir - } + private fun Kapt3SubpluginContext.temporaryKaptDirectory( + name: String + ) = project.buildDir.resolve("tmp/kapt3/$name/$sourceSetName") internal inner class Kapt3SubpluginContext( val project: Project, @@ -328,8 +324,6 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To pluginOptions += SubpluginOption("processors", annotationProcessors) } - kotlinSourcesOutputDir.mkdirs() - val apOptions = getAPOptions().get() pluginOptions += CompositeSubpluginOption( @@ -476,7 +470,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To kaptTask.kotlinCompileTask = kotlinCompilation.compileKotlinTaskProvider.get() as KotlinCompile - kaptTask.stubsDir = getKaptStubsDir() + kaptTask.stubsDir.set(getKaptStubsDir()) kaptTask.destinationDir = sourcesOutputDir kaptTask.kotlinSourcesDestinationDir = kotlinSourcesOutputDir @@ -486,7 +480,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To kaptTask.isIncremental = project.isIncrementalKapt() if (kaptTask.isIncremental) { - kaptTask.incAptCache = getKaptIncrementalAnnotationProcessingCache() + kaptTask.incAptCache.set(getKaptIncrementalAnnotationProcessingCache()) kaptTask.localState.register(kaptTask.incAptCache) kaptTask.classpathStructure = classStructureIfIncremental!!.incoming.artifactView { viewConfig -> @@ -496,7 +490,10 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To if (kaptTask is KaptWithKotlincTask) { kaptTask.pluginOptions.addPluginArgument( getCompilerPluginId(), - SubpluginOption("incrementalCache", kaptTask.incAptCache!!.absolutePath) + SubpluginOption( + "incrementalCache", + lazy { kaptTask.incAptCache.asFile.get().absolutePath } + ) ) } } @@ -612,7 +609,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To val kaptTaskProvider = project.registerTask(kaptTaskName) { kaptTask -> kaptTask.kotlinCompileTask = kotlinCompile.get() - kaptTask.stubsDir = getKaptStubsDir() + kaptTask.stubsDir.set(getKaptStubsDir()) kaptTask.setDestinationDir { getKaptIncrementalDataDir() } kaptTask.mapClasspath { kaptTask.kotlinCompileTask.classpath } kaptTask.generatedSourcesDirs = listOf(sourcesOutputDir, kotlinSourcesOutputDir) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt index ac4a67b7cbc..5d5e7212eaf 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt @@ -17,7 +17,9 @@ package org.jetbrains.kotlin.gradle.internal import org.gradle.api.artifacts.Configuration +import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.FileCollection +import org.gradle.api.model.ObjectFactory import org.gradle.api.tasks.* import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions @@ -30,9 +32,12 @@ import org.jetbrains.kotlin.gradle.utils.isParentOf import org.jetbrains.kotlin.incremental.classpathAsList import org.jetbrains.kotlin.incremental.destinationAsFile import java.io.File +import javax.inject.Inject @CacheableTask -open class KaptGenerateStubsTask : KotlinCompile() { +open class KaptGenerateStubsTask @Inject constructor( + objectFactory: ObjectFactory +) : KotlinCompile() { override val sourceRootsContainer = FilteringSourceRootsContainer(emptyList(), { isSourceRootAllowed(it) }) override val kotlinOptions: KotlinJvmOptions = KotlinJvmOptionsImpl() @@ -42,7 +47,7 @@ open class KaptGenerateStubsTask : KotlinCompile() { internal lateinit var kotlinCompileTask: KotlinCompile @get:OutputDirectory - lateinit var stubsDir: File + val stubsDir: DirectoryProperty = objectFactory.directoryProperty() @get:Internal lateinit var generatedSourcesDirs: List @@ -82,7 +87,7 @@ open class KaptGenerateStubsTask : KotlinCompile() { private fun isSourceRootAllowed(source: File): Boolean = !destinationDir.isParentOf(source) && - !stubsDir.isParentOf(source) && + !stubsDir.asFile.get().isParentOf(source) && generatedSourcesDirs.none { it.isParentOf(source) } private val compileKotlinArgumentsContributor by project.provider { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt index 1a691be11ce..66f049e0561 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt @@ -1,8 +1,10 @@ package org.jetbrains.kotlin.gradle.internal import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.FileCollection import org.gradle.api.internal.ConventionTask +import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.ListProperty import org.gradle.api.tasks.* import org.gradle.api.tasks.incremental.IncrementalTaskInputs @@ -20,9 +22,12 @@ import org.jetbrains.kotlin.gradle.utils.getValue import org.jetbrains.kotlin.gradle.utils.isJavaFile import java.io.File import java.util.jar.JarFile +import javax.inject.Inject @CacheableTask -abstract class KaptTask : ConventionTask(), TaskWithLocalState { +abstract class KaptTask @Inject constructor( + objectFactory: ObjectFactory +): ConventionTask(), TaskWithLocalState { init { cacheOnlyIfEnabledForKotlin() @@ -30,14 +35,16 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { outputs.cacheIf(reason) { useBuildCache } } - override fun localStateDirectories(): FileCollection = objects.fileCollection().from(incAptCache) + override fun localStateDirectories(): FileCollection = objects + .fileCollection() + .from({ incAptCache.orNull }) @get:Internal @field:Transient internal lateinit var kotlinCompileTask: KotlinCompile @get:Internal - internal lateinit var stubsDir: File + internal val stubsDir: DirectoryProperty = objectFactory.directoryProperty() @get:Internal internal val objects = project.objects @@ -67,7 +74,7 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { * annotations are specified during task configuration. */ @get:Internal - var incAptCache: File? = null + val incAptCache: DirectoryProperty = objectFactory.directoryProperty() @get:OutputDirectory internal lateinit var classesDir: File @@ -121,23 +128,17 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { @get:InputFiles @get:PathSensitive(PathSensitivity.RELATIVE) - val source: Collection - get() { - val result = HashSet() - for (root in javaSourceRoots) { - root.walk().filterTo(result) { it.isJavaFile() } - } - return result + val source: FileCollection = objectFactory + .fileCollection() + .from( + { kotlinCompileTask.sourceRootsContainer.sourceRoots }, + stubsDir + ) + .asFileTree + .matching { + it.include("**/*.java") } - - // store the files before filtering, so that Gradle doesn't serialize the filtered collection for instant execution state and reuse it - private val unfilteredJavaSourceRoots by project.provider { - (kotlinCompileTask.sourceRootsContainer.sourceRoots + stubsDir) - } - - @get:Internal - protected val javaSourceRoots: Set - get() = unfilteredJavaSourceRoots.filterTo(HashSet(), ::isRootAllowed) + .filter(::isRootAllowed) @get:Internal override val metrics: BuildMetricsReporter = @@ -145,8 +146,8 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { private fun isRootAllowed(file: File): Boolean = file.exists() && - !isAncestor(destinationDir, file) && - !isAncestor(classesDir, file) + !isAncestor(destinationDir, file) && + !isAncestor(classesDir, file) //Have to avoid using FileUtil because it is required system property reading that is not allowed for configuration cache private fun isAncestor(dir: File, file: File): Boolean { @@ -224,7 +225,7 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { } private fun findClasspathChanges(inputs: IncrementalTaskInputs): KaptIncrementalChanges { - val incAptCacheDir = incAptCache!! + val incAptCacheDir = incAptCache.asFile.get() incAptCacheDir.mkdirs() val allDataFiles = classpathStructure!!.files diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithKotlincTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithKotlincTask.kt index e5724d1f295..f33bd97763c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithKotlincTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithKotlincTask.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle.internal import com.intellij.openapi.util.SystemInfo import org.gradle.api.GradleException import org.gradle.api.file.FileCollection +import org.gradle.api.model.ObjectFactory import org.gradle.api.tasks.Classpath import org.gradle.api.tasks.InputFiles import org.gradle.api.tasks.Internal @@ -27,8 +28,11 @@ import org.jetbrains.kotlin.gradle.utils.getValue import org.jetbrains.kotlin.gradle.utils.optionalProvider import org.jetbrains.kotlin.gradle.utils.toSortedPathsArray import java.io.File +import javax.inject.Inject -abstract class KaptWithKotlincTask : KaptTask(), CompilerArgumentAwareWithInput { +abstract class KaptWithKotlincTask @Inject constructor( + objectFactory: ObjectFactory +) : KaptTask(objectFactory), CompilerArgumentAwareWithInput { @get:Internal internal val pluginOptions = CompilerPluginOptions() @@ -107,7 +111,7 @@ abstract class KaptWithKotlincTask : KaptTask(), CompilerArgumentAwareWithInput< compilerRunner.runJvmCompilerAsync( sourcesToCompile = emptyList(), commonSources = emptyList(), - javaSourceRoots = javaSourceRoots, + javaSourceRoots = source.files, javaPackagePrefix = javaPackagePrefix, args = args, environment = environment diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt index 987d2a8f737..01b9932d0fa 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt @@ -6,6 +6,8 @@ package org.jetbrains.kotlin.gradle.internal import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.DirectoryProperty +import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.Property import org.gradle.api.tasks.* import org.gradle.api.tasks.incremental.IncrementalTaskInputs @@ -27,7 +29,10 @@ import java.net.URL import java.net.URLClassLoader import javax.inject.Inject -abstract class KaptWithoutKotlincTask @Inject constructor(private val workerExecutor: WorkerExecutor) : KaptTask() { +abstract class KaptWithoutKotlincTask @Inject constructor( + objectFactory: ObjectFactory, + private val workerExecutor: WorkerExecutor +) : KaptTask(objectFactory) { @get:InputFiles @get:Classpath @Suppress("unused") @@ -98,16 +103,16 @@ abstract class KaptWithoutKotlincTask @Inject constructor(private val workerExec val optionsForWorker = KaptOptionsForWorker( projectDir, compileClasspath, - javaSourceRoots.toList(), + source.files.toList(), changedFiles, compiledSources, - incAptCache, + incAptCache.orNull?.asFile, classpathChanges.toList(), destinationDir, classesDir, - stubsDir, + stubsDir.asFile.get(), kaptClasspath.files.toList(), annotationProcessorFqNames,