diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/NativeDownloadAndPlatformLibsIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/NativeDownloadAndPlatformLibsIT.kt index ecb0490f9903a..5b7fcf3a2f5d9 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/NativeDownloadAndPlatformLibsIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/NativeDownloadAndPlatformLibsIT.kt @@ -127,6 +127,33 @@ class NativeDownloadAndPlatformLibsIT : KGPBaseTest() { } } + @DisplayName("Toolchain leaves a distribution installed by the legacy downloader alone (KT-86251)") + @GradleTest + fun testToolchainDoesNotReinstallOverLegacyInstallation(gradleVersion: GradleVersion) { + platformLibrariesProject("linuxX64", gradleVersion = gradleVersion) { + val konanDataDir = workingDir.resolve(".konan") + + // this path has to write 'provisioned.ok' as well, that is the marker the toolchain looks for + build("tasks", buildOptions = defaultBuildOptions.copy(konanDataDir = konanDataDir)) { + assertOutputContains("Unpack Kotlin/Native compiler to ") + } + + // the toolchain has to leave that installation alone. Unpacking on top of it happens in place, so + // anything reading the distribution at the same time sees half-written files. + build( + "downloadKotlinNativeDistribution", + buildOptions = defaultBuildOptions.copy( + konanDataDir = konanDataDir, + freeArgs = listOf("-Pkotlin.native.toolchain.enabled=true"), + ), + ) { + assertTasksExecuted(":downloadKotlinNativeDistribution") + assertOutputDoesNotContain("Native bundle files will be overwritten") + assertOutputDoesNotContain("Moving Kotlin/Native bundle from") + } + } + } + @DisplayName("K/N distribution with platform libraries generation") @GradleTest fun testLibrariesGeneration(gradleVersion: GradleVersion) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerDownloader.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerDownloader.kt index 2f76a32f19f62..f3524744553b9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerDownloader.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerDownloader.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.gradle.report.GradleBuildMetricsReporter import org.jetbrains.kotlin.gradle.targets.native.internal.NativeDistributionTypeProvider import org.jetbrains.kotlin.gradle.targets.native.internal.PlatformLibrariesGenerator import org.jetbrains.kotlin.gradle.targets.native.konanPropertiesBuildService +import org.jetbrains.kotlin.gradle.targets.native.toolchain.NativeVersionValueSource import org.jetbrains.kotlin.internal.compilerRunner.native.nativeCompilerClasspath import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.KonanTarget @@ -202,13 +203,24 @@ class NativeCompilerDownloader( it.into(tmpDir) } val compilerTmp = tmpDir.resolve(dependencyNameWithOsAndVersion) - if (!compilerTmp.renameTo(compilerDirectory)) { - project.copy { - it.from(compilerTmp) - it.into(compilerDirectory) + val installed = when { + compilerTmp.renameTo(compilerDirectory) -> true + !compilerDirectory.exists() -> { + project.copy { + it.from(compilerTmp) + it.into(compilerDirectory) + } + true } + // another build got there first, copying on top would rewrite files it is reading (KT-86251) + else -> false } logger.debug("Moved Kotlin/Native compiler from $tmpDir to $compilerDirectory") + if (installed) { + // without the marker a toolchain build sharing this konan data dir unpacks the archive over the + // distribution again (KT-86251). Keep it the last thing written. + compilerDirectory.resolve(NativeVersionValueSource.MARKER_FILE).createNewFile() + } } finally { tmpDir.deleteRecursively() }