From 2ec6ab92b59e7cbcb4f75f00537c12412f398f6b Mon Sep 17 00:00:00 2001 From: Alexey Tsvetkov Date: Mon, 18 Mar 2019 21:45:24 +0300 Subject: [PATCH] Clear outputs before compiling with in-process/out-of-process execution mode Issue #KT-30492 Fixed --- .../kotlin/gradle/ExecutionStrategyIT.kt | 40 +++++++++++++++---- .../app/src/main/kotlin/classes.kt | 5 +++ .../kotlinBuiltins/app/src/main/kotlin/f.kt | 4 -- .../app/src/main/kotlin/main.kt | 2 +- .../GradleKotlinCompilerWork.kt | 14 +++++-- .../kotlin/gradle/tasks/tasksUtils.kt | 7 +++- 6 files changed, 54 insertions(+), 18 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinBuiltins/app/src/main/kotlin/classes.kt delete mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinBuiltins/app/src/main/kotlin/f.kt diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ExecutionStrategyIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ExecutionStrategyIT.kt index 1bf5dff99c1..19ac5d9ad89 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ExecutionStrategyIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ExecutionStrategyIT.kt @@ -1,5 +1,6 @@ package org.jetbrains.kotlin.gradle +import org.jetbrains.kotlin.gradle.util.checkedReplace import org.jetbrains.kotlin.gradle.util.getFileByName import org.jetbrains.kotlin.gradle.util.modify import org.junit.Test @@ -18,9 +19,29 @@ class ExecutionStrategyJsIT : ExecutionStrategyIT() { override fun CompiledProject.checkOutput() { assertFileExists("web/js/out.js") } + + override fun CompiledProject.checkOutputAfterChange() { + assertFileExists("web/js/out.js") + } } -open class ExecutionStrategyIT : BaseGradleIT() { +class ExecutionStrategyJvmIT : ExecutionStrategyIT() { + override fun CompiledProject.checkOutput() { + val classesDir = kotlinClassesDir(subproject = "app") + "foo/" + assertFileExists("${classesDir}MainKt.class") + assertFileExists("${classesDir}A.class") + assertFileExists("${classesDir}B.class") + } + + override fun CompiledProject.checkOutputAfterChange() { + val classesDir = kotlinClassesDir(subproject = "app") + "foo/" + assertFileExists("${classesDir}MainKt.class") + assertFileExists("${classesDir}A.class") + assertNoSuchFile("${classesDir}B.class") + } +} + +abstract class ExecutionStrategyIT : BaseGradleIT() { @Test fun testDaemon() { doTestExecutionStrategy("daemon") @@ -48,14 +69,18 @@ open class ExecutionStrategyIT : BaseGradleIT() { assertContains(finishMessage) checkOutput() assertNoWarnings() + assertFileExists(kotlinClassesDir(subproject = "app") + "foo/B.class") } - val fKt = project.projectDir.getFileByName("f.kt") - fKt.delete() + val classesKt = project.projectDir.getFileByName("classes.kt") + classesKt.modify { + it.checkedReplace("class B", "//class B") + } project.build("build", strategyCLIArg) { - assertFailed() + assertSuccessful() assertContains(finishMessage) - assert(output.contains("Unresolved reference: f", ignoreCase = true)) + checkOutputAfterChange() + assertNoWarnings() } } @@ -66,7 +91,6 @@ open class ExecutionStrategyIT : BaseGradleIT() { ) } - protected open fun CompiledProject.checkOutput() { - assertFileExists(kotlinClassesDir(subproject = "app") + "foo/MainKt.class") - } + protected abstract fun CompiledProject.checkOutput() + protected abstract fun CompiledProject.checkOutputAfterChange() } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinBuiltins/app/src/main/kotlin/classes.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinBuiltins/app/src/main/kotlin/classes.kt new file mode 100644 index 00000000000..78a93a022b6 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinBuiltins/app/src/main/kotlin/classes.kt @@ -0,0 +1,5 @@ +package foo + +class A + +class B \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinBuiltins/app/src/main/kotlin/f.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinBuiltins/app/src/main/kotlin/f.kt deleted file mode 100644 index a9b416ecab5..00000000000 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinBuiltins/app/src/main/kotlin/f.kt +++ /dev/null @@ -1,4 +0,0 @@ -package foo - -@Suppress("unused_parameter") -fun f(fn: (x: Int)->Unit) { } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinBuiltins/app/src/main/kotlin/main.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinBuiltins/app/src/main/kotlin/main.kt index a12a807ae44..2984dc942e6 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinBuiltins/app/src/main/kotlin/main.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlinBuiltins/app/src/main/kotlin/main.kt @@ -1,5 +1,5 @@ package foo fun main() { - f { it * 2 } + A() } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerWork.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerWork.kt index 953f8506ad8..40f94e20455 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerWork.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerWork.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskExecutionResults import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskLoggers import org.jetbrains.kotlin.gradle.report.BuildReportMode import org.jetbrains.kotlin.gradle.report.TaskExecutionResult +import org.jetbrains.kotlin.gradle.tasks.clearLocalState import org.jetbrains.kotlin.gradle.tasks.throwGradleExceptionIfError import org.jetbrains.kotlin.gradle.utils.stackTraceAsString import org.jetbrains.kotlin.incremental.ChangedFiles @@ -292,8 +293,10 @@ internal class GradleKotlinCompilerWork @Inject constructor( return result } - private fun compileOutOfProcess(): ExitCode = - try { + private fun compileOutOfProcess(): ExitCode { + clearLocalState(outputFiles, log, reason = "out-of-process execution strategy is non-incremental") + + return try { runToolInSeparateProcess(compilerArgs, compilerClassName, compilerFullClasspath, log) } finally { reportExecutionResultIfNeeded { @@ -303,17 +306,20 @@ internal class GradleKotlinCompilerWork @Inject constructor( ) } } + } private fun compileInProcess(messageCollector: MessageCollector): ExitCode { + clearLocalState(outputFiles, log, reason = "in-process execution strategy is non-incremental") + // in-process compiler should always be run in a different thread // to avoid leaking thread locals from compiler (see KT-28037) val threadPool = Executors.newSingleThreadExecutor() val bufferingMessageCollector = GradleBufferingMessageCollector() - try { + return try { val future = threadPool.submit(Callable { compileInProcessImpl(bufferingMessageCollector) }) - return future.get() + future.get() } finally { bufferingMessageCollector.flush(messageCollector) threadPool.shutdown() diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/tasksUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/tasksUtils.kt index 1dd61092291..5cfc78f35bf 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/tasksUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/tasksUtils.kt @@ -2,10 +2,12 @@ package org.jetbrains.kotlin.gradle.tasks import org.gradle.api.GradleException import org.jetbrains.kotlin.cli.common.ExitCode +import org.jetbrains.kotlin.compilerRunner.KotlinLogger import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles import org.jetbrains.kotlin.gradle.logging.kotlinDebug +import java.io.File fun throwGradleExceptionIfError(exitCode: ExitCode) { when (exitCode) { @@ -20,13 +22,16 @@ fun throwGradleExceptionIfError(exitCode: ExitCode) { internal fun TaskWithLocalState.clearLocalState(reason: String? = null) { val log = GradleKotlinLogger(logger) + clearLocalState(allOutputFiles(), log, reason) +} +internal fun clearLocalState(outputFiles: Iterable, log: KotlinLogger, reason: String? = null) { log.kotlinDebug { val suffix = reason?.let { " ($it)" }.orEmpty() "Clearing output$suffix:" } - for (file in allOutputFiles()) { + for (file in outputFiles) { if (!file.exists()) continue when { file.isDirectory -> {