Clear outputs before compiling with in-process/out-of-process execution mode
Issue #KT-30492 Fixed
This commit is contained in:
+32
-8
@@ -1,5 +1,6 @@
|
|||||||
package org.jetbrains.kotlin.gradle
|
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.getFileByName
|
||||||
import org.jetbrains.kotlin.gradle.util.modify
|
import org.jetbrains.kotlin.gradle.util.modify
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@@ -18,9 +19,29 @@ class ExecutionStrategyJsIT : ExecutionStrategyIT() {
|
|||||||
override fun CompiledProject.checkOutput() {
|
override fun CompiledProject.checkOutput() {
|
||||||
assertFileExists("web/js/out.js")
|
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
|
@Test
|
||||||
fun testDaemon() {
|
fun testDaemon() {
|
||||||
doTestExecutionStrategy("daemon")
|
doTestExecutionStrategy("daemon")
|
||||||
@@ -48,14 +69,18 @@ open class ExecutionStrategyIT : BaseGradleIT() {
|
|||||||
assertContains(finishMessage)
|
assertContains(finishMessage)
|
||||||
checkOutput()
|
checkOutput()
|
||||||
assertNoWarnings()
|
assertNoWarnings()
|
||||||
|
assertFileExists(kotlinClassesDir(subproject = "app") + "foo/B.class")
|
||||||
}
|
}
|
||||||
|
|
||||||
val fKt = project.projectDir.getFileByName("f.kt")
|
val classesKt = project.projectDir.getFileByName("classes.kt")
|
||||||
fKt.delete()
|
classesKt.modify {
|
||||||
|
it.checkedReplace("class B", "//class B")
|
||||||
|
}
|
||||||
project.build("build", strategyCLIArg) {
|
project.build("build", strategyCLIArg) {
|
||||||
assertFailed()
|
assertSuccessful()
|
||||||
assertContains(finishMessage)
|
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() {
|
protected abstract fun CompiledProject.checkOutput()
|
||||||
assertFileExists(kotlinClassesDir(subproject = "app") + "foo/MainKt.class")
|
protected abstract fun CompiledProject.checkOutputAfterChange()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
package foo
|
||||||
|
|
||||||
|
class A
|
||||||
|
|
||||||
|
class B
|
||||||
-4
@@ -1,4 +0,0 @@
|
|||||||
package foo
|
|
||||||
|
|
||||||
@Suppress("unused_parameter")
|
|
||||||
fun f(fn: (x: Int)->Unit) { }
|
|
||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
package foo
|
package foo
|
||||||
|
|
||||||
fun main() {
|
fun main() {
|
||||||
f { it * 2 }
|
A()
|
||||||
}
|
}
|
||||||
+10
-4
@@ -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.plugin.internal.state.TaskLoggers
|
||||||
import org.jetbrains.kotlin.gradle.report.BuildReportMode
|
import org.jetbrains.kotlin.gradle.report.BuildReportMode
|
||||||
import org.jetbrains.kotlin.gradle.report.TaskExecutionResult
|
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.tasks.throwGradleExceptionIfError
|
||||||
import org.jetbrains.kotlin.gradle.utils.stackTraceAsString
|
import org.jetbrains.kotlin.gradle.utils.stackTraceAsString
|
||||||
import org.jetbrains.kotlin.incremental.ChangedFiles
|
import org.jetbrains.kotlin.incremental.ChangedFiles
|
||||||
@@ -292,8 +293,10 @@ internal class GradleKotlinCompilerWork @Inject constructor(
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun compileOutOfProcess(): ExitCode =
|
private fun compileOutOfProcess(): ExitCode {
|
||||||
try {
|
clearLocalState(outputFiles, log, reason = "out-of-process execution strategy is non-incremental")
|
||||||
|
|
||||||
|
return try {
|
||||||
runToolInSeparateProcess(compilerArgs, compilerClassName, compilerFullClasspath, log)
|
runToolInSeparateProcess(compilerArgs, compilerClassName, compilerFullClasspath, log)
|
||||||
} finally {
|
} finally {
|
||||||
reportExecutionResultIfNeeded {
|
reportExecutionResultIfNeeded {
|
||||||
@@ -303,17 +306,20 @@ internal class GradleKotlinCompilerWork @Inject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun compileInProcess(messageCollector: MessageCollector): ExitCode {
|
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
|
// in-process compiler should always be run in a different thread
|
||||||
// to avoid leaking thread locals from compiler (see KT-28037)
|
// to avoid leaking thread locals from compiler (see KT-28037)
|
||||||
val threadPool = Executors.newSingleThreadExecutor()
|
val threadPool = Executors.newSingleThreadExecutor()
|
||||||
val bufferingMessageCollector = GradleBufferingMessageCollector()
|
val bufferingMessageCollector = GradleBufferingMessageCollector()
|
||||||
try {
|
return try {
|
||||||
val future = threadPool.submit(Callable {
|
val future = threadPool.submit(Callable {
|
||||||
compileInProcessImpl(bufferingMessageCollector)
|
compileInProcessImpl(bufferingMessageCollector)
|
||||||
})
|
})
|
||||||
return future.get()
|
future.get()
|
||||||
} finally {
|
} finally {
|
||||||
bufferingMessageCollector.flush(messageCollector)
|
bufferingMessageCollector.flush(messageCollector)
|
||||||
threadPool.shutdown()
|
threadPool.shutdown()
|
||||||
|
|||||||
+6
-1
@@ -2,10 +2,12 @@ package org.jetbrains.kotlin.gradle.tasks
|
|||||||
|
|
||||||
import org.gradle.api.GradleException
|
import org.gradle.api.GradleException
|
||||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
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.logging.GradleKotlinLogger
|
||||||
import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState
|
import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState
|
||||||
import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles
|
import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles
|
||||||
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
|
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
fun throwGradleExceptionIfError(exitCode: ExitCode) {
|
fun throwGradleExceptionIfError(exitCode: ExitCode) {
|
||||||
when (exitCode) {
|
when (exitCode) {
|
||||||
@@ -20,13 +22,16 @@ fun throwGradleExceptionIfError(exitCode: ExitCode) {
|
|||||||
|
|
||||||
internal fun TaskWithLocalState.clearLocalState(reason: String? = null) {
|
internal fun TaskWithLocalState.clearLocalState(reason: String? = null) {
|
||||||
val log = GradleKotlinLogger(logger)
|
val log = GradleKotlinLogger(logger)
|
||||||
|
clearLocalState(allOutputFiles(), log, reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun clearLocalState(outputFiles: Iterable<File>, log: KotlinLogger, reason: String? = null) {
|
||||||
log.kotlinDebug {
|
log.kotlinDebug {
|
||||||
val suffix = reason?.let { " ($it)" }.orEmpty()
|
val suffix = reason?.let { " ($it)" }.orEmpty()
|
||||||
"Clearing output$suffix:"
|
"Clearing output$suffix:"
|
||||||
}
|
}
|
||||||
|
|
||||||
for (file in allOutputFiles()) {
|
for (file in outputFiles) {
|
||||||
if (!file.exists()) continue
|
if (!file.exists()) continue
|
||||||
when {
|
when {
|
||||||
file.isDirectory -> {
|
file.isDirectory -> {
|
||||||
|
|||||||
Reference in New Issue
Block a user