diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/GeneralNativeIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/GeneralNativeIT.kt index dd4cb868468..5804f5ba6db 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/GeneralNativeIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/native/GeneralNativeIT.kt @@ -24,11 +24,8 @@ import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.presetName -import org.junit.Assume -import org.junit.Ignore -import org.junit.Rule -import org.junit.Test -import org.junit.rules.ErrorCollector +import org.junit.* +import org.junit.rules.TemporaryFolder import java.io.File import java.util.* import kotlin.test.assertEquals @@ -1086,6 +1083,81 @@ class GeneralNativeIT : BaseGradleIT() { } } + @Test + fun `check offline mode is propagated to the compiler`() = with( + transformNativeTestProjectWithPluginDsl( + "executables", + directoryPrefix = "native-binaries" + ) + ) { + val buildOptions = defaultBuildOptions() + + val linkTask = ":linkDebugExecutableHost" + val compileTask = ":compileKotlinHost" + + build(linkTask, options = buildOptions) { + assertSuccessful() + } + + // Check that --offline works when all the dependencies are already downloaded: + val buildOptionsOffline = buildOptions.copy(freeCommandLineArgs = buildOptions.freeCommandLineArgs + "--offline") + + build("clean", linkTask, options = buildOptionsOffline) { + assertSuccessful() + withNativeCommandLineArguments(compileTask, linkTask) { + assertTrue(it.contains("-Xoverride-konan-properties=airplaneMode=true")) + } + } + + // Check that --offline fails when there are no downloaded dependencies: + val customKonanDataDir = tempDir.newFolder("konanOffline") + val buildOptionsOfflineWithCustomKonanDataDir = buildOptionsOffline.copy( + customEnvironmentVariables = buildOptionsOffline.customEnvironmentVariables + + ("KONAN_DATA_DIR" to customKonanDataDir.absolutePath) + ) + + build("clean", linkTask, options = buildOptionsOfflineWithCustomKonanDataDir) { + assertFailed() + assertTasksNotExecuted(listOf(linkTask)) + } + + checkNoDependenciesDownloaded(customKonanDataDir) + + // Check that the compiler is not extracted if it is not cached: + assertTrue(customKonanDataDir.deleteRecursively()) + build( + "clean", linkTask, "-Pkotlin.native.version=1.6.20-M1-9999", + options = buildOptionsOfflineWithCustomKonanDataDir + ) { + assertFailed() + assertTasksNotExecuted(listOf(linkTask, compileTask)) + } + + assertFalse(customKonanDataDir.exists()) + } + + private fun checkNoDependenciesDownloaded(customKonanDataDir: File) { + // Check that no files have actually been downloaded or extracted, + // except for maybe the compiler itself, which can be extracted from the Gradle cache + // (see NativeCompilerDownloader, it uses regular dependency resolution, + // so supports --offline properly by default). + val cacheDirName = "cache" + val dependenciesDirName = "dependencies" + + fun assertDirectoryHasNothingButMaybe(directory: File, vararg names: String) { + assertEquals(emptyList(), directory.listFiles().orEmpty().map { it.name } - names) + } + + assertDirectoryHasNothingButMaybe(File(customKonanDataDir, cacheDirName), ".lock") + assertDirectoryHasNothingButMaybe(File(customKonanDataDir, dependenciesDirName), ".extracted") + + val customKonanDataDirFiles = customKonanDataDir.listFiles().orEmpty().map { it.name } - setOf(cacheDirName, dependenciesDirName) + if (customKonanDataDirFiles.isNotEmpty()) { + assertEquals(1, customKonanDataDirFiles.size, message = customKonanDataDirFiles.toString()) + assertTrue(customKonanDataDirFiles.single().startsWith("kotlin-native-"), message = customKonanDataDirFiles.single()) + } + } + companion object { fun List.containsSequentially(vararg elements: String): Boolean { check(elements.isNotEmpty()) @@ -1158,5 +1230,15 @@ class GeneralNativeIT : BaseGradleIT() { toolName: String = "konanc", check: (Map) -> Unit ) = taskPaths.forEach { taskPath -> check(extractNativeCustomEnvironment(taskPath, toolName)) } + + @field:ClassRule + @JvmField + val tempDir = TemporaryFolder() + + @JvmStatic + @AfterClass + fun deleteTempDir() { + tempDir.delete() + } } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/KotlinToolRunner.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/KotlinToolRunner.kt index 49074724d84..c2dde3adb6f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/KotlinToolRunner.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/KotlinToolRunner.kt @@ -54,6 +54,9 @@ abstract class KotlinToolRunner( abstract val mustRunViaExec: Boolean open fun transformArgs(args: List): List = args + internal open val defaultArguments: List + get() = emptyList() + // for the purpose if there is a way to specify JVM args, for instance, straight in project configs open fun getCustomJvmArgs(): List = emptyList() @@ -77,8 +80,9 @@ abstract class KotlinToolRunner( fun run(args: List) { checkClasspath() + val argsWithDefault = args + defaultArguments - if (mustRunViaExec) runViaExec(args) else runInProcess(args) + if (mustRunViaExec) runViaExec(argsWithDefault) else runInProcess(argsWithDefault) } private fun runViaExec(args: List) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/nativeToolRunners.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/nativeToolRunners.kt index d1b70a33ad4..87ef98d9a87 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/nativeToolRunners.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/nativeToolRunners.kt @@ -175,6 +175,13 @@ internal class KotlinNativeCompilerRunner(project: Project) : KotlinNativeToolRu return listOf(toolName, "@${argFile.absolutePath}") } + + override val defaultArguments: List + get() = mutableListOf().apply { + if (project.gradle.startParameter.isOffline) { + add("-Xoverride-konan-properties=airplaneMode=true") + } + } } /** Platform libraries generation tool. Runs the cinterop tool under the hood. */