From 1be9e047977c034071d31c28714c2e977b107c36 Mon Sep 17 00:00:00 2001 From: Sergey Igushkin Date: Fri, 29 Dec 2017 18:59:34 +0300 Subject: [PATCH] Move conditional task caching setup into the task constructors; Add 'kotlin.caching.enabled' flag to switch the caching for all tasks; Rename and change semantics of cache support checks: make two instead of one, `isBuildCacheSupported` and `isBuildCacheEnabledForKotlin`; Remove FileOptionKind entries that are redundant at the moment; Improvements in BuildCacheIT.kt and other refactoring suggestions from the review https://upsource.jetbrains.com/kotlin/review/KOTLIN-CR-1647 --- .../gradle/plugin/KotlinGradleSubplugin.kt | 15 +++++-- .../jetbrains/kotlin/gradle/BuildCacheIT.kt | 43 +++++++++---------- .../testProject/buildCacheSimple/build.gradle | 21 +++++++++ .../buildCacheSimple/src/main/kotlin/foo.kt | 3 ++ .../src/main/kotlin/fooUsage.kt | 5 +++ .../gradle/internal/AndroidSubplugin.kt | 8 ++-- .../internal/AnnotationProcessingManager.kt | 6 +-- .../internal/Kapt3KotlinGradleSubplugin.kt | 26 +++-------- .../kotlin/gradle/internal/KaptTask.kt | 10 +++++ .../kotlin/gradle/internal/subpluginUtils.kt | 4 +- .../kotlin/gradle/plugin/KotlinJsDcePlugin.kt | 10 +---- .../kotlin/gradle/plugin/KotlinPlugin.kt | 27 ++---------- .../kotlin/gradle/tasks/CacheableTasks.kt | 33 +++++++------- .../kotlin/gradle/tasks/KotlinJsDce.kt | 4 ++ .../jetbrains/kotlin/gradle/tasks/Tasks.kt | 9 +++- .../kotlin/gradle/tasks/TasksProvider.kt | 3 -- 16 files changed, 121 insertions(+), 106 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/buildCacheSimple/build.gradle create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/buildCacheSimple/src/main/kotlin/foo.kt create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/buildCacheSimple/src/main/kotlin/fooUsage.kt diff --git a/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleSubplugin.kt index d077a6a3234..64907fb18b6 100644 --- a/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleSubplugin.kt @@ -21,22 +21,29 @@ import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.compile.AbstractCompile import java.io.File -open class SubpluginOption(val key: String, open val value: String) +open class SubpluginOption(val key: String, val value: String) class FilesSubpluginOption( key: String, - val kind: FileOptionKind, val files: List, + val kind: FilesOptionKind = FilesOptionKind.INTERNAL, value: String = files.joinToString(File.pathSeparator) { it.canonicalPath }) : SubpluginOption(key, value) -class WrapperSubpluginOption( +class CompositeSubpluginOption( key: String, value: String, val originalOptions: List) : SubpluginOption(key, value) -enum class FileOptionKind { INPUT_FILES, CLASSPATH_INPUT, OUTPUT_FILES, OUTPUT_DIRS, INTERNAL } +/** Defines how the files option should be handled with regard to Gradle model */ +enum class FilesOptionKind { + /** The files option is an implementation detail and should not be treated as an input or an output. */ + INTERNAL + + // More options might be added when use cases appear for them, + // such as output directories, inputs or classpath options. +} interface KotlinGradleSubplugin { fun isApplicable(project: Project, task: AbstractCompile): Boolean diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BuildCacheIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BuildCacheIT.kt index 507581cbb8e..28da245e8b8 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BuildCacheIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BuildCacheIT.kt @@ -16,12 +16,9 @@ package org.jetbrains.kotlin.gradle -import org.jetbrains.kotlin.gradle.util.checkBytecodeContains import org.jetbrains.kotlin.gradle.util.modify import org.junit.Test import java.io.File -import java.nio.file.Files -import kotlin.test.assertEquals class BuildCacheIT : BaseGradleIT() { override fun defaultBuildOptions(): BuildOptions = @@ -32,7 +29,7 @@ class BuildCacheIT : BaseGradleIT() { } @Test - fun noCacheWithGradlePre43() = with(Project("simpleProject", "4.2")) { + fun testNoCacheWithGradlePre43() = with(Project("simpleProject", "4.2")) { // Check that even with the build cache enabled, the Kotlin tasks are not cacheable with Gradle < 4.3: val optionsWithCache = defaultBuildOptions().copy(withBuildCache = true) @@ -47,6 +44,21 @@ class BuildCacheIT : BaseGradleIT() { } } + @Test + fun testKotlinCachingEnabledFlag() = with(Project("simpleProject", GRADLE_VERSION)) { + prepareLocalBuildCache() + + build("assemble") { + assertSuccessful() + assertContains("Packing task ':compileKotlin'") + } + + build("clean", "assemble", "-Dkotlin.caching.enabled=false") { + assertSuccessful() + assertNotContains(":compileKotlin FROM-CACHE") + } + } + @Test fun testCacheHitAfterClean() = with(Project("simpleProject", GRADLE_VERSION)) { prepareLocalBuildCache() @@ -99,20 +111,9 @@ class BuildCacheIT : BaseGradleIT() { } @Test - fun testCorrectBuildAfterCacheHit() = with(Project("simpleProject", GRADLE_VERSION)) { + fun testCorrectBuildAfterCacheHit() = with(Project("buildCacheSimple", GRADLE_VERSION)) { prepareLocalBuildCache() - val fooKt = File(projectDir, "src/main/kotlin/foo/foo.kt").apply { - parentFile.mkdirs() - writeText("package foo; fun foo(i: Int): Int = 1") - } - - // bar.kt references foo.kt; we expect it to recompile during the first build after a cache hit. - File(projectDir, "src/main/kotlin/bar/bar.kt").apply { - parentFile.mkdirs() - writeText("package bar; import foo.*; fun bar() = foo(1)") - } - // First build, should be stored into the build cache: build("assemble") { assertSuccessful() @@ -125,13 +126,11 @@ class BuildCacheIT : BaseGradleIT() { assertContains(":compileKotlin FROM-CACHE") } - // Change the return type Int to String, so that bar.kt should be recompiled, and check that: - fooKt.modify { it.replace("Int = 1", "String = \"abc\"") } + // Change the return type of foo() from Int to String in foo.kt, and check that fooUsage.kt is recompiled as well: + File(projectDir, "src/main/kotlin/foo.kt").modify { it.replace("Int = 1", "String = \"abc\"") } build("assemble") { assertSuccessful() - checkBytecodeContains( - File(projectDir, "build/classes/kotlin/main/bar/BarKt.class"), - "INVOKESTATIC foo/FooKt.foo (I)Ljava/lang/String;") + assertCompiledKotlinSources(relativize(allKotlinFiles)) } } @@ -166,7 +165,7 @@ class BuildCacheIT : BaseGradleIT() { } } -fun BaseGradleIT.Project.prepareLocalBuildCache(directory: File = Files.createTempDirectory("GradleTestBuildCache").toFile()): File { +fun BaseGradleIT.Project.prepareLocalBuildCache(directory: File = File(projectDir.parentFile, "buildCache").apply { mkdir() }): File { if (!projectDir.exists()) { setupWorkingDir() } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/buildCacheSimple/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/buildCacheSimple/build.gradle new file mode 100644 index 00000000000..5cda9ec552d --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/buildCacheSimple/build.gradle @@ -0,0 +1,21 @@ +buildscript { + repositories { + mavenLocal() + mavenCentral() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + } +} + +apply plugin: "kotlin" +apply plugin: 'java' + +repositories { + mavenLocal() + mavenCentral() +} + +dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/buildCacheSimple/src/main/kotlin/foo.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/buildCacheSimple/src/main/kotlin/foo.kt new file mode 100644 index 00000000000..2e9f281f701 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/buildCacheSimple/src/main/kotlin/foo.kt @@ -0,0 +1,3 @@ +package foo + +fun foo(i: Int): Int = 1 \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/buildCacheSimple/src/main/kotlin/fooUsage.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/buildCacheSimple/src/main/kotlin/fooUsage.kt new file mode 100644 index 00000000000..78b0b2888db --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/buildCacheSimple/src/main/kotlin/fooUsage.kt @@ -0,0 +1,5 @@ +package bar + +import foo.* + +fun bar() = foo(1) \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AndroidSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AndroidSubplugin.kt index 4d6139d654e..cda43e5fe16 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AndroidSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AndroidSubplugin.kt @@ -118,10 +118,10 @@ class AndroidSubplugin : KotlinGradleSubplugin { fun addVariant(sourceSet: AndroidSourceSet) { val optionValue = sourceSet.name + ';' + sourceSet.res.srcDirs.joinToString(";") { it.absolutePath } - pluginOptions += WrapperSubpluginOption("variant", optionValue, listOf( + pluginOptions += CompositeSubpluginOption("variant", optionValue, listOf( SubpluginOption("sourceSetName", sourceSet.name), //use the INTERNAL option kind since the resources are tracked as sources (see below) - FilesSubpluginOption("resDirs", FileOptionKind.INTERNAL, sourceSet.res.srcDirs.toList()) + FilesSubpluginOption("resDirs", sourceSet.res.srcDirs.toList()) )) kotlinCompile.source(project.files(getLayoutDirectories(sourceSet.res.srcDirs))) } @@ -170,10 +170,10 @@ class AndroidSubplugin : KotlinGradleSubplugin { append(';') resDirectories.joinTo(this, separator = ";") { it.canonicalPath } } - pluginOptions += WrapperSubpluginOption("variant", optionValue, listOf( + pluginOptions += CompositeSubpluginOption("variant", optionValue, listOf( SubpluginOption("variantName", name), // use INTERNAL option kind since the resources are tracked as sources (see below) - FilesSubpluginOption("resDirs", FileOptionKind.INTERNAL, resDirectories))) + FilesSubpluginOption("resDirs", resDirectories))) kotlinCompile.source(project.files(getLayoutDirectories(resDirectories))) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AnnotationProcessingManager.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AnnotationProcessingManager.kt index abb358d407d..3588544fe8e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AnnotationProcessingManager.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/AnnotationProcessingManager.kt @@ -36,7 +36,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider import org.jetbrains.kotlin.gradle.tasks.kapt.generateAnnotationProcessorWrapper import org.jetbrains.kotlin.gradle.tasks.kapt.generateKotlinAptAnnotation -import org.jetbrains.kotlin.gradle.tasks.shouldEnableGradleCache +import org.jetbrains.kotlin.gradle.tasks.isBuildCacheSupported import java.io.File import java.io.IOException import java.util.zip.ZipFile @@ -80,7 +80,7 @@ internal fun Project.initKapt( // moveGeneratedJavaFilesToCorrespondingDirectories(kaptManager.aptOutputDir) // } - if (shouldEnableGradleCache()) { + if (isBuildCacheSupported()) { // Since Kapt1 is about to be dropped, disable the cache for it: kotlinAfterJavaTask.outputs.doNotCacheIf("Caching is not supported with deprecated Kapt1") { true } } @@ -110,7 +110,7 @@ internal fun Project.initKapt( kotlinTask.kaptOptions.annotationsFile = kaptManager.getAnnotationFile() - if (shouldEnableGradleCache()) { + if (isBuildCacheSupported()) { // Since Kapt1 is about to be dropped, disable the cache for it: kotlinTask.outputs.doNotCacheIf("Caching is not supported with deprecated Kapt1") { true } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt index 5c20765299d..0d1fc0ecb83 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/Kapt3KotlinGradleSubplugin.kt @@ -35,8 +35,6 @@ import java.io.File import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.getKaptGeneratedSourcesDir import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.getKaptGeneratedClassesDir import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.getKaptGeneratedKotlinSourcesDir -import org.jetbrains.kotlin.gradle.tasks.shouldEnableGradleCache -import org.jetbrains.kotlin.gradle.tasks.useBuildCacheIfSupported import java.io.ByteArrayOutputStream import java.io.ObjectOutputStream import java.util.* @@ -210,14 +208,14 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { pluginOptions += SubpluginOption("aptMode", aptMode) disableAnnotationProcessingInJavaTask() - kaptClasspath.forEach { pluginOptions += FilesSubpluginOption("apclasspath", FileOptionKind.INTERNAL, listOf(it)) } + kaptClasspath.forEach { pluginOptions += FilesSubpluginOption("apclasspath", listOf(it)) } javaCompile.source(generatedFilesDir) - pluginOptions += FilesSubpluginOption("sources", FileOptionKind.INTERNAL, listOf(generatedFilesDir)) - pluginOptions += FilesSubpluginOption("classes", FileOptionKind.INTERNAL, listOf(getKaptGeneratedClassesDir(project, sourceSetName))) + pluginOptions += FilesSubpluginOption("sources", listOf(generatedFilesDir)) + pluginOptions += FilesSubpluginOption("classes", listOf(getKaptGeneratedClassesDir(project, sourceSetName))) - pluginOptions += FilesSubpluginOption("incrementalData", FileOptionKind.INTERNAL, listOf(getKaptIncrementalDataDir())) + pluginOptions += FilesSubpluginOption("incrementalData", listOf(getKaptIncrementalDataDir())) val annotationProcessors = kaptExtension.processors if (annotationProcessors.isNotEmpty()) { @@ -235,9 +233,9 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { val apOptions = (kaptExtension.getAdditionalArguments(project, kaptVariantData?.variantData, androidPlugin) + androidOptions) .map { SubpluginOption(it.key, it.value) } + - FilesSubpluginOption("kapt.kotlin.generated", FileOptionKind.INTERNAL, listOf(kotlinSourcesOutputDir)) + FilesSubpluginOption("kapt.kotlin.generated", listOf(kotlinSourcesOutputDir)) - pluginOptions += WrapperSubpluginOption("apoptions", encodeList(apOptions.associate { it.key to it.value }), apOptions) + pluginOptions += CompositeSubpluginOption("apoptions", encodeList(apOptions.associate { it.key to it.value }), apOptions) pluginOptions += SubpluginOption("javacArguments", encodeList(kaptExtension.getJavacOptions())) @@ -284,7 +282,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { pluginOptions += SubpluginOption("useLightAnalysis", "${kaptExtension.useLightAnalysis}") pluginOptions += SubpluginOption("correctErrorTypes", "${kaptExtension.correctErrorTypes}") - pluginOptions += FilesSubpluginOption("stubs", FileOptionKind.INTERNAL, listOf(getKaptStubsDir())) + pluginOptions += FilesSubpluginOption("stubs", listOf(getKaptStubsDir())) if (project.hasProperty(VERBOSE_OPTION_NAME) && project.property(VERBOSE_OPTION_NAME) == "true") { pluginOptions += SubpluginOption("verbose", "true") @@ -296,14 +294,6 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { getKaptTaskName("kapt"), KaptTask::class.java) - kaptTask.useBuildCacheIfSupported() - - if (shouldEnableGradleCache()) { - val reason = "Caching is disabled by default for kapt because of arbitrary behavior of external " + - "annotation processors. You can enable it by adding 'kapt.useBuildCache = true' to the build script." - kaptTask.outputs.doNotCacheIf(reason) { !kaptTask.useBuildCache } - } - kaptTask.useBuildCache = kaptExtension.useBuildCache kaptTask.kotlinCompileTask = kotlinCompile @@ -342,8 +332,6 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { getKaptTaskName("kaptGenerateStubs"), KaptGenerateStubsTask::class.java) - kaptTask.useBuildCacheIfSupported() - kaptTask.sourceSetName = sourceSetName kaptTask.kotlinCompileTask = kotlinCompile kotlinToKaptGenerateStubsTasksMap[kotlinCompile] = kaptTask diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KaptTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KaptTask.kt index ad18886241a..7bd2e6c4994 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KaptTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/KaptTask.kt @@ -16,6 +16,16 @@ import java.io.File @CacheableTask open class KaptTask : ConventionTask(), CompilerArgumentAware { + init { + cacheOnlyIfEnabledForKotlin() + + if (isBuildCacheSupported()) { + val reason = "Caching is disabled by default for kapt because of arbitrary behavior of external " + + "annotation processors. You can enable it by adding 'kapt.useBuildCache = true' to the build script." + outputs.cacheIf(reason) { useBuildCache } + } + } + @get:Internal internal val pluginOptions = CompilerPluginOptions() diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/subpluginUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/subpluginUtils.kt index efae5dc60eb..23359e37cb5 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/subpluginUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/subpluginUtils.kt @@ -17,7 +17,7 @@ package org.jetbrains.kotlin.gradle.internal import org.jetbrains.kotlin.gradle.plugin.SubpluginOption -import org.jetbrains.kotlin.gradle.plugin.WrapperSubpluginOption +import org.jetbrains.kotlin.gradle.plugin.CompositeSubpluginOption import java.io.ByteArrayOutputStream import java.io.ObjectOutputStream import java.util.* @@ -43,6 +43,6 @@ fun encodePluginOptions(options: Map>): String { fun wrapPluginOptions(options: List, newOptionName: String): List { val groupedOptions = options.groupBy { it.key }.mapValues { opt -> opt.value.map { it.value } } val encodedOptions = encodePluginOptions(groupedOptions) - val singleOption = WrapperSubpluginOption(newOptionName, encodedOptions, options) + val singleOption = CompositeSubpluginOption(newOptionName, encodedOptions, options) return listOf(singleOption) } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinJsDcePlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinJsDcePlugin.kt index 7aa72f38f6c..c223f9da342 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinJsDcePlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinJsDcePlugin.kt @@ -18,15 +18,10 @@ package org.jetbrains.kotlin.gradle.plugin import org.gradle.api.Plugin import org.gradle.api.Project -import org.gradle.api.Task -import org.gradle.api.file.FileTree -import org.gradle.api.internal.file.UnionFileCollection -import org.gradle.api.internal.file.UnionFileTree import org.gradle.api.plugins.JavaPluginConvention import org.gradle.api.tasks.SourceSet import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile import org.jetbrains.kotlin.gradle.tasks.KotlinJsDce -import org.jetbrains.kotlin.gradle.tasks.useBuildCacheIfSupported import java.io.File class KotlinJsDcePlugin : Plugin { @@ -46,18 +41,15 @@ class KotlinJsDcePlugin : Plugin { project.tasks.findByName("build")!!.dependsOn(it) } - dceTask.useBuildCacheIfSupported() - project.afterEvaluate { val outputDir = File(File(project.buildDir, DEFAULT_OUT_DIR), sourceSet.name) val configuration = project.configurations.findByName(sourceSet.compileConfigurationName)!! - val dceInputTree = project.fileTree(kotlinTask.outputFile) with (dceTask) { classpath = configuration destinationDir = dceTask.dceOptions.outputDirectory?.let { File(it) } ?: outputDir - source(dceInputTree) + source(kotlinTask.outputFile) } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt index fa00ba92c6a..88cb9be513d 100755 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt @@ -689,8 +689,8 @@ internal fun configureJavaTask(kotlinTask: KotlinCompile, javaTask: AbstractComp // Make Gradle check if the javaTask is up-to-date based on the Kotlin classes javaTask.inputsCompatible.run { - if (shouldEnableGradleCache()) { - dir(kotlinTask.destinationDir).withNormalizer(ClasspathNormalizer::class.java) + if (isBuildCacheSupported()) { + dir(kotlinTask.destinationDir).withNormalizer(CompileClasspathNormalizer::class.java) } else { dirCompatible(kotlinTask.destinationDir) @@ -839,30 +839,11 @@ internal class SubpluginEnvironment( internal fun Task.registerSubpluginOptionAsInput(subpluginId: String, option: SubpluginOption) { when (option) { - is WrapperSubpluginOption -> { + is CompositeSubpluginOption -> { val subpluginIdWithWrapperKey = "$subpluginId.${option.key}" option.originalOptions.forEach { registerSubpluginOptionAsInput(subpluginIdWithWrapperKey, it) } } - is FilesSubpluginOption -> { - when (option.kind) { - FileOptionKind.INTERNAL -> Unit - FileOptionKind.OUTPUT_FILES -> outputsCompatible.filesCompatible(*option.files.toTypedArray()) - FileOptionKind.OUTPUT_DIRS -> option.files.forEach { outputsCompatible.dirCompatible(it) } - FileOptionKind.INPUT_FILES, FileOptionKind.CLASSPATH_INPUT -> { - if (!shouldEnableGradleCache()) { - // Normalization makes no sense when we don't mean to use the cache, - // and moreover, Gradle lacks some of the APIs in the earlier versions. - inputsCompatible.filesCompatible(option.files) - } - else { - if (option.kind == FileOptionKind.CLASSPATH_INPUT) - inputs.files(option.files).withNormalizer(ClasspathNormalizer::class.java) - else - inputs.files(option.files).withPathSensitivity(PathSensitivity.RELATIVE) - } - } - } - } + is FilesSubpluginOption -> Unit else -> { // Since there might be multiple subplugin options with the same key, // use the properties count to resolve duplication: diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/CacheableTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/CacheableTasks.kt index bac2d4b41ad..2c4ada39612 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/CacheableTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/CacheableTasks.kt @@ -18,21 +18,24 @@ package org.jetbrains.kotlin.gradle.tasks import org.gradle.api.Task import org.gradle.util.GradleVersion +import org.jetbrains.kotlin.gradle.utils.outputsCompatible + +internal fun isBuildCacheSupported(): Boolean = + gradleVersion >= GradleVersion.version("4.3") + +internal fun isBuildCacheEnabledForKotlin(): Boolean = + isBuildCacheSupported() && + System.getProperty(KOTLIN_CACHING_ENABLED_PROPERTY)?.toBoolean() ?: true + +internal fun T.cacheOnlyIfEnabledForKotlin() { + // The `cacheIf` method may be missing if the Gradle version is too low: + try { + outputsCompatible.cacheIf { isBuildCacheEnabledForKotlin() } + } + catch (_: NoSuchMethodError) { + } +} private val gradleVersion = GradleVersion.current() -internal fun shouldEnableGradleCache(): Boolean = - gradleVersion >= GradleVersion.version("4.3") - -internal fun T.useBuildCacheIfSupported() { - when { - gradleVersion >= GradleVersion.version("3.4") -> - outputs.cacheIf("Gradle version is at least 4.3") { shouldEnableGradleCache() } - - // There was no 'cacheIf' method accepting a reason string before 3.4: - gradleVersion >= GradleVersion.version("3.0") -> outputs.cacheIf { false } - - // Before 3.0, there was no build cache at all, no need to restrict anything - else -> Unit - } -} \ No newline at end of file +private const val KOTLIN_CACHING_ENABLED_PROPERTY = "kotlin.caching.enabled" diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJsDce.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJsDce.kt index 66605d74f36..f9154b7e38a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJsDce.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJsDce.kt @@ -35,6 +35,10 @@ import java.io.File @CacheableTask open class KotlinJsDce : AbstractKotlinCompileTool(), KotlinJsDce { + init { + cacheOnlyIfEnabledForKotlin() + } + override fun createCompilerArgs(): K2JSDceArguments = K2JSDceArguments() override fun setupCompilerArgs(args: K2JSDceArguments, defaultsOnly: Boolean) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt index 3b42df36a1f..1a40b593a0c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt @@ -80,6 +80,11 @@ abstract class AbstractKotlinCompileTool() : AbstractCo } abstract class AbstractKotlinCompile() : AbstractKotlinCompileTool() { + + init { + cacheOnlyIfEnabledForKotlin() + } + @get:LocalState internal val taskBuildDirectory: File get() = File(File(project.buildDir, KOTLIN_BUILD_DIR_NAME), name).apply { mkdirs() } @@ -412,11 +417,11 @@ open class KotlinCompile : AbstractKotlinCompile(), Kotl kaptAnnotationsFileUpdater = AnnotationFileUpdaterImpl(kaptAnnotationsFile) } - addPluginArgument(ANNOTATIONS_PLUGIN_NAME, FilesSubpluginOption("output", FileOptionKind.INTERNAL, listOf(kaptAnnotationsFile))) + addPluginArgument(ANNOTATIONS_PLUGIN_NAME, FilesSubpluginOption("output", listOf(kaptAnnotationsFile))) } if (kaptOptions.generateStubs) { - addPluginArgument(ANNOTATIONS_PLUGIN_NAME, FilesSubpluginOption("stubs", FileOptionKind.INTERNAL, listOf(destinationDir))) + addPluginArgument(ANNOTATIONS_PLUGIN_NAME, FilesSubpluginOption("stubs", listOf(destinationDir))) } if (kaptOptions.supportInheritedAnnotations) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksProvider.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksProvider.kt index ad0e1bc1223..93d47370b87 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksProvider.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksProvider.kt @@ -24,19 +24,16 @@ import org.jetbrains.kotlin.gradle.plugin.mapKotlinTaskProperties internal open class KotlinTasksProvider { fun createKotlinJVMTask(project: Project, name: String, sourceSetName: String): KotlinCompile = project.tasks.create(name, KotlinCompile::class.java).apply { - useBuildCacheIfSupported() configure(project, sourceSetName) } fun createKotlinJSTask(project: Project, name: String, sourceSetName: String): Kotlin2JsCompile = project.tasks.create(name, Kotlin2JsCompile::class.java).apply { - useBuildCacheIfSupported() configure(project, sourceSetName) } fun createKotlinCommonTask(project: Project, name: String, sourceSetName: String): KotlinCompileCommon = project.tasks.create(name, KotlinCompileCommon::class.java).apply { - useBuildCacheIfSupported() configure(project, sourceSetName) }