Add basic synchronization workaround for scratch
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.idea.scratch
|
package org.jetbrains.kotlin.idea.scratch
|
||||||
|
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
|
import com.intellij.openapi.application.invokeAndWaitIfNeeded
|
||||||
import com.intellij.openapi.application.runReadAction
|
import com.intellij.openapi.application.runReadAction
|
||||||
import com.intellij.openapi.diagnostic.ControlFlowException
|
import com.intellij.openapi.diagnostic.ControlFlowException
|
||||||
import com.intellij.openapi.editor.EditorFactory
|
import com.intellij.openapi.editor.EditorFactory
|
||||||
@@ -188,6 +189,7 @@ abstract class SequentialScratchExecutor(file: ScratchFile) : ScratchExecutor(fi
|
|||||||
stopExecution {
|
stopExecution {
|
||||||
lock.release()
|
lock.release()
|
||||||
}
|
}
|
||||||
|
// blocking UI thread!?
|
||||||
check(lock.tryAcquire(2, TimeUnit.SECONDS)) {
|
check(lock.tryAcquire(2, TimeUnit.SECONDS)) {
|
||||||
"Couldn't stop REPL process in 2 seconds"
|
"Couldn't stop REPL process in 2 seconds"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ import javax.xml.parsers.DocumentBuilderFactory
|
|||||||
|
|
||||||
class KtScratchReplExecutor(file: ScratchFile) : SequentialScratchExecutor(file) {
|
class KtScratchReplExecutor(file: ScratchFile) : SequentialScratchExecutor(file) {
|
||||||
private val history: ReplHistory = ReplHistory()
|
private val history: ReplHistory = ReplHistory()
|
||||||
|
|
||||||
|
@Volatile
|
||||||
private var osProcessHandler: OSProcessHandler? = null
|
private var osProcessHandler: OSProcessHandler? = null
|
||||||
|
|
||||||
override fun startExecution() {
|
override fun startExecution() {
|
||||||
@@ -65,6 +67,8 @@ class KtScratchReplExecutor(file: ScratchFile) : SequentialScratchExecutor(file)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// There should be some kind of more wise synchronization cause this method is called from non-UI thread (process handler thread)
|
||||||
|
// and actually there could be side effects in handlers
|
||||||
private fun clearState() {
|
private fun clearState() {
|
||||||
history.clear()
|
history.clear()
|
||||||
osProcessHandler = null
|
osProcessHandler = null
|
||||||
@@ -145,9 +149,20 @@ class KtScratchReplExecutor(file: ScratchFile) : SequentialScratchExecutor(file)
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun notifyProcessTerminated(exitCode: Int) {
|
override fun notifyProcessTerminated(exitCode: Int) {
|
||||||
super.notifyProcessTerminated(exitCode)
|
// Do state cleaning before notification otherwise KtScratchFileEditorWithPreview.dispose
|
||||||
|
// would try to stop process again (after stop in tests 'stopReplProcess`)
|
||||||
|
// via `stopExecution` (because handler is not null) with next exception:
|
||||||
|
//
|
||||||
|
// Caused by: com.intellij.testFramework.LoggedErrorProcessor$TestLoggerAssertionError: The pipe is being closed
|
||||||
|
// at com.intellij.testFramework.LoggedErrorProcessor.processError(LoggedErrorProcessor.java:66)
|
||||||
|
// at com.intellij.testFramework.TestLogger.error(TestLogger.java:40)
|
||||||
|
// at com.intellij.openapi.diagnostic.Logger.error(Logger.java:170)
|
||||||
|
// at org.jetbrains.kotlin.idea.scratch.ScratchExecutor.errorOccurs(ScratchExecutor.kt:50)
|
||||||
|
// at org.jetbrains.kotlin.idea.scratch.repl.KtScratchReplExecutor.stopExecution(KtScratchReplExecutor.kt:61)
|
||||||
|
// at org.jetbrains.kotlin.idea.scratch.SequentialScratchExecutor.stopExecution$default(ScratchExecutor.kt:90)
|
||||||
clearState()
|
clearState()
|
||||||
|
|
||||||
|
super.notifyProcessTerminated(exitCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun strToSource(s: String, encoding: Charset = Charsets.UTF_8) = InputSource(ByteArrayInputStream(s.toByteArray(encoding)))
|
private fun strToSource(s: String, encoding: Charset = Charsets.UTF_8) = InputSource(ByteArrayInputStream(s.toByteArray(encoding)))
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ sourceSets {
|
|||||||
"test" { projectDefault() }
|
"test" { projectDefault() }
|
||||||
}
|
}
|
||||||
|
|
||||||
projectTest {
|
projectTest(parallel = true) {
|
||||||
dependsOn(":dist")
|
dependsOn(":dist")
|
||||||
workingDir = rootDir
|
workingDir = rootDir
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-2
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
|
|||||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||||
import org.jetbrains.kotlin.idea.actions.KOTLIN_WORKSHEET_EXTENSION
|
import org.jetbrains.kotlin.idea.actions.KOTLIN_WORKSHEET_EXTENSION
|
||||||
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
|
||||||
|
import org.jetbrains.kotlin.idea.debugger.coroutine.util.logger
|
||||||
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingUtil
|
import org.jetbrains.kotlin.idea.highlighter.KotlinHighlightingUtil
|
||||||
import org.jetbrains.kotlin.idea.scratch.actions.ClearScratchAction
|
import org.jetbrains.kotlin.idea.scratch.actions.ClearScratchAction
|
||||||
import org.jetbrains.kotlin.idea.scratch.actions.RunScratchAction
|
import org.jetbrains.kotlin.idea.scratch.actions.RunScratchAction
|
||||||
@@ -99,7 +100,7 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val outputDir = createTempDir(dirName)
|
val outputDir = FileUtil.createTempDirectory(dirName, "")
|
||||||
|
|
||||||
if (javaFiles.isNotEmpty()) {
|
if (javaFiles.isNotEmpty()) {
|
||||||
val options = listOf("-d", outputDir.path)
|
val options = listOf("-d", outputDir.path)
|
||||||
@@ -259,7 +260,11 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() {
|
|||||||
|
|
||||||
val start = System.currentTimeMillis()
|
val start = System.currentTimeMillis()
|
||||||
// wait until output is displayed in editor or for 1 minute
|
// wait until output is displayed in editor or for 1 minute
|
||||||
while (ScratchCompilationSupport.isAnyInProgress() && (System.currentTimeMillis() - start) < 60000) {
|
while (ScratchCompilationSupport.isAnyInProgress()) {
|
||||||
|
if ((System.currentTimeMillis() - start) > TIME_OUT) {
|
||||||
|
LOG.warn("Waiting timeout $TIME_OUT ms is exceed")
|
||||||
|
break
|
||||||
|
}
|
||||||
Thread.sleep(100)
|
Thread.sleep(100)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,6 +328,8 @@ abstract class AbstractScratchRunActionTest : FileEditorManagerTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private const val TIME_OUT = 60000 // 1 min
|
||||||
|
|
||||||
private val INSTANCE_WITH_KOTLIN_TEST = object : KotlinWithJdkAndRuntimeLightProjectDescriptor(
|
private val INSTANCE_WITH_KOTLIN_TEST = object : KotlinWithJdkAndRuntimeLightProjectDescriptor(
|
||||||
arrayListOf(
|
arrayListOf(
|
||||||
ForTestCompileRuntime.runtimeJarForTests(),
|
ForTestCompileRuntime.runtimeJarForTests(),
|
||||||
|
|||||||
Reference in New Issue
Block a user