diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsIrBeIncrementalCompilationIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsIrBeIncrementalCompilationIT.kt index 8bf816d9c6b..1d2dd3f7f93 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsIrBeIncrementalCompilationIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/Kotlin2JsIrBeIncrementalCompilationIT.kt @@ -9,6 +9,7 @@ import org.gradle.util.GradleVersion import org.jetbrains.kotlin.gradle.plugin.KotlinJsCompilerType import org.jetbrains.kotlin.gradle.testbase.* import org.junit.jupiter.api.DisplayName +import java.io.File import kotlin.io.path.appendText import kotlin.io.path.readText import kotlin.io.path.writeText @@ -34,7 +35,7 @@ class Kotlin2JsIrBeIncrementalCompilationIT : KGPBaseTest() { project("kotlin-js-ir-ic-rebuild-after-error", gradleVersion) { fun readCacheFiles(): Map { val cacheFiles = mutableMapOf() - projectPath.resolve("app/build/klib/cache/").toFile().walk().forEach { cachedFile -> + projectPath.resolve("app/build/klib/cache/js/developmentExecutable").toFile().walk().forEach { cachedFile -> if (cachedFile.isFile) { cacheFiles[cachedFile.absolutePath] = cachedFile.readBytes().contentHashCode() } @@ -43,7 +44,7 @@ class Kotlin2JsIrBeIncrementalCompilationIT : KGPBaseTest() { } val srcFile = projectPath.resolve("app/src/main/kotlin/App.kt").toFile() - val guardFile = projectPath.resolve("app/build/klib/cache/cache.guard").toFile() + val guardFile = projectPath.resolve("app/build/klib/cache/js/developmentExecutable/cache.guard").toFile() val badCode = srcFile.readText() var successfulBuildCacheFiles = emptyMap() @@ -126,7 +127,7 @@ class Kotlin2JsIrBeIncrementalCompilationIT : KGPBaseTest() { fun testMultipleArtifacts(gradleVersion: GradleVersion) { project("kotlin-js-ir-ic-multiple-artifacts", gradleVersion) { build("compileDevelopmentExecutableKotlinJs") { - val cacheDir = projectPath.resolve("app/build/klib/cache/").toFile() + val cacheDir = projectPath.resolve("app/build/klib/cache/js/developmentExecutable").toFile() val cacheRootDirName = cacheDir.list()?.singleOrNull() assertTrue("Lib cache root dir should contain 1 element 'version.hash'") { cacheRootDirName?.startsWith("version.") ?: false @@ -213,7 +214,7 @@ class Kotlin2JsIrBeIncrementalCompilationIT : KGPBaseTest() { assertOutputContains(">>> TEST OUT: Hello, Gradle.") } - val cacheGuard = projectPath.resolve("build/klib/cache/cache.guard").toFile() + val cacheGuard = projectPath.resolve("build/klib/cache/js/developmentExecutable/cache.guard").toFile() assertFalse(cacheGuard.exists(), "Cache guard file should be removed after successful build") val srcFile = projectPath.resolve("src/main/kotlin/Main.kt").toFile() @@ -230,4 +231,52 @@ class Kotlin2JsIrBeIncrementalCompilationIT : KGPBaseTest() { assertFalse(cacheGuard.exists(), "Cache guard file should be removed after successful build") } } + + @DisplayName("Separate caches for different binaries") + @GradleTest + fun testSeparateCachesForDifferentBinaries(gradleVersion: GradleVersion) { + project("kotlin-js-ir-ic-multiple-artifacts", gradleVersion) { + val filesToModified = mutableMapOf() + + build("compileDevelopmentExecutableKotlinJs") { + val cacheDir = projectPath.resolve("app/build/klib/cache/js/developmentExecutable").toFile() + val cacheRootDirName = cacheDir.list()?.singleOrNull() + val cacheRootDir = cacheDir.resolve(cacheRootDirName!!) + + cacheRootDir.listFiles()!! + .forEach { + it.listFiles()!! + .filter { it.isFile } + .filter { it.name == "module.js" } + .forEach { + filesToModified[it] = it.lastModified() + } + + } + + assertTasksExecuted(":app:compileDevelopmentExecutableKotlinJs") + } + + build("compileTestDevelopmentExecutableKotlinJs") { + val cacheDir = projectPath.resolve("app/build/klib/cache/js/developmentExecutable").toFile() + val cacheRootDirName = cacheDir.list()?.singleOrNull() + val cacheRootDir = cacheDir.resolve(cacheRootDirName!!) + + val allUpToDate = cacheRootDir.listFiles()!! + .all { + it.listFiles()!! + .filter { it.isFile } + .filter { it.name == "module.js" } + .all { + filesToModified[it] == it.lastModified() + } + + } + + assertTrue { allUpToDate } + + assertTasksExecuted(":app:compileTestDevelopmentExecutableKotlinJs") + } + } + } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin-js-ir-ic-multiple-artifacts/app/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin-js-ir-ic-multiple-artifacts/app/build.gradle.kts index 78a4e60330b..97e6037c939 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin-js-ir-ic-multiple-artifacts/app/build.gradle.kts +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin-js-ir-ic-multiple-artifacts/app/build.gradle.kts @@ -4,6 +4,7 @@ plugins { dependencies { implementation(project(":lib")) + testImplementation(kotlin("test-js")) } kotlin { diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin-js-ir-ic-multiple-artifacts/app/src/test/kotlin/MyTest.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin-js-ir-ic-multiple-artifacts/app/src/test/kotlin/MyTest.kt new file mode 100644 index 00000000000..2c48dc8941c --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin-js-ir-ic-multiple-artifacts/app/src/test/kotlin/MyTest.kt @@ -0,0 +1,14 @@ +/* + * Copyright 2010-2023 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. + */ + +import kotlin.test.Test +import kotlin.test.assertEquals + +class MainTest { + @Test + fun testHello() { + assertEquals(true, true) + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt index 992dbbcd639..cad812e1e19 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode.DEVELOPMENT +import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode.PRODUCTION import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics import org.jetbrains.kotlin.statistics.metrics.StringMetrics @@ -50,15 +51,6 @@ abstract class KotlinJsIrLink @Inject constructor( return !entryModule.get().asFile.exists() } - @get:Internal - val platformType by lazy { - compilation.platformType - } - - @Transient - @get:Internal - internal lateinit var compilation: KotlinCompilation<*> - @Transient @get:Internal internal val propertiesProvider = PropertiesProvider(project) @@ -85,8 +77,6 @@ abstract class KotlinJsIrLink @Inject constructor( @get:Input internal abstract val modeProperty: Property - private val buildDir = project.buildDir - @get:SkipWhenEmpty @get:IgnoreEmptyDirectories @get:NormalizeLineEndings @@ -95,8 +85,12 @@ abstract class KotlinJsIrLink @Inject constructor( internal abstract val entryModule: DirectoryProperty @get:Internal - val rootCacheDirectory by lazy { - buildDir.resolve("klib/cache") + internal abstract val rootCacheDirectory: DirectoryProperty + + override fun cleanOutputsAndLocalState(reason: String?) { + if (!usingCacheDirectory()) { + super.cleanOutputsAndLocalState(reason) + } } override fun processArgs(args: K2JSCompilerArguments) { @@ -124,10 +118,13 @@ abstract class KotlinJsIrLink @Inject constructor( args.includes = entryModule.get().asFile.canonicalPath - if (incrementalJsIr && mode == DEVELOPMENT) { - args.cacheDirectory = rootCacheDirectory.also { it.mkdirs() }.absolutePath + if (usingCacheDirectory()) { + args.cacheDirectory = rootCacheDirectory.get().asFile.also { it.mkdirs() }.absolutePath } } + + private fun usingCacheDirectory() = + incrementalJsIr && modeProperty.get() == DEVELOPMENT } val KotlinPlatformType.fileExtension diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt index 01a42acd37f..af6570eacda 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt @@ -68,6 +68,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.cast import java.io.File import java.nio.file.Files.* import javax.inject.Inject +import org.jetbrains.kotlin.gradle.tasks.cleanOutputsAndLocalState as cleanOutputsAndLocalStateUtil const val KOTLIN_BUILD_DIR_NAME = "kotlin" const val USING_JVM_INCREMENTAL_COMPILATION_MESSAGE = "Using Kotlin/JVM incremental compilation" @@ -407,6 +408,10 @@ abstract class AbstractKotlinCompile @Inject constr buildMetricsService.orNull?.also { it.addTask(path, this.javaClass, buildMetrics) } } + protected open fun cleanOutputsAndLocalState(reason: String?) { + cleanOutputsAndLocalStateUtil(reason) + } + protected open fun skipCondition(): Boolean = sources.isEmpty @get:Internal diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinJsIrLinkConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinJsIrLinkConfig.kt index ac86f88a518..c37a1b99abe 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinJsIrLinkConfig.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinJsIrLinkConfig.kt @@ -34,7 +34,7 @@ internal open class KotlinJsIrLinkConfig( } } ).disallowChanges() - task.compilation = compilation + task.rootCacheDirectory.set(project.layout.buildDirectory.map { it.dir("klib/cache/js/${binary.name}") }) task.destinationDirectory.convention( project.layout.buildDirectory .dir(COMPILE_SYNC)