Catch and report exceptions from DependenciesResolver
This commit is contained in:
+45
-21
@@ -28,6 +28,7 @@ import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.openapi.vfs.VirtualFileManager
|
||||
import com.intellij.openapi.vfs.newvfs.BulkFileListener
|
||||
import com.intellij.openapi.vfs.newvfs.events.VFileEvent
|
||||
import kotlinx.coroutines.experimental.CoroutineDispatcher
|
||||
import kotlinx.coroutines.experimental.Job
|
||||
import kotlinx.coroutines.experimental.asCoroutineDispatcher
|
||||
import kotlinx.coroutines.experimental.launch
|
||||
@@ -135,40 +136,63 @@ internal class ScriptDependenciesUpdater(
|
||||
): TimeStampedJob {
|
||||
val currentTimeStamp = TimeStamps.next()
|
||||
|
||||
fun process(result: DependenciesResolver.ResolveResult) {
|
||||
val lastRequest = requests[file.path]
|
||||
val lastTimeStamp = lastRequest?.job?.timeStamp
|
||||
val isLastSentRequest = lastTimeStamp == null || lastTimeStamp == currentTimeStamp
|
||||
if (isLastSentRequest) {
|
||||
if (lastRequest != null) {
|
||||
// no job running atm unless there is a job started while we process this result
|
||||
requests.replace(file.path, lastRequest, ModStampedRequest(lastRequest.modificationStamp, job = null))
|
||||
}
|
||||
ServiceManager.getService(project, ScriptReportSink::class.java)?.attachReports(file, result.reports)
|
||||
val resultingDependencies = (result.dependencies ?: ScriptDependencies.Empty).adjustByDefinition(scriptDef)
|
||||
if (cache(resultingDependencies, file)) {
|
||||
onChange()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val dependenciesResolver = scriptDef.dependencyResolver
|
||||
val scriptContents = contentLoader.getScriptContents(scriptDef, file)
|
||||
val environment = contentLoader.getEnvironment(scriptDef)
|
||||
val newJob = if (dependenciesResolver is AsyncDependenciesResolver) {
|
||||
launch(asyncUpdatesDispatcher) {
|
||||
process(dependenciesResolver.resolveAsync(scriptContents, environment))
|
||||
launchAsyncUpdate(asyncUpdatesDispatcher, file, currentTimeStamp, scriptDef) {
|
||||
dependenciesResolver.resolveAsync(scriptContents, environment)
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(dependenciesResolver is LegacyResolverWrapper)
|
||||
launch(legacyUpdatesDispatcher) {
|
||||
process(dependenciesResolver.resolve(scriptContents, environment))
|
||||
launchAsyncUpdate(legacyUpdatesDispatcher, file, currentTimeStamp, scriptDef) {
|
||||
dependenciesResolver.resolve(scriptContents, environment)
|
||||
}
|
||||
}
|
||||
return TimeStampedJob(newJob, currentTimeStamp)
|
||||
}
|
||||
|
||||
private fun launchAsyncUpdate(
|
||||
dispatcher: CoroutineDispatcher,
|
||||
file: VirtualFile,
|
||||
currentTimeStamp: TimeStamp,
|
||||
scriptDef: KotlinScriptDefinition,
|
||||
doResolve: suspend () -> DependenciesResolver.ResolveResult
|
||||
) = launch(dispatcher) {
|
||||
val result = try {
|
||||
doResolve()
|
||||
}
|
||||
catch (t: Throwable) {
|
||||
t.asResolveFailure(scriptDef)
|
||||
}
|
||||
|
||||
processResult(file, currentTimeStamp, result, scriptDef)
|
||||
}
|
||||
|
||||
private fun processResult(
|
||||
file: VirtualFile,
|
||||
currentTimeStamp: TimeStamp,
|
||||
result: DependenciesResolver.ResolveResult,
|
||||
scriptDef: KotlinScriptDefinition
|
||||
) {
|
||||
val lastRequest = requests[file.path]
|
||||
val lastTimeStamp = lastRequest?.job?.timeStamp
|
||||
val isLastSentRequest = lastTimeStamp == null || lastTimeStamp == currentTimeStamp
|
||||
if (isLastSentRequest) {
|
||||
if (lastRequest != null) {
|
||||
// no job running atm unless there is a job started while we process this result
|
||||
requests.replace(file.path, lastRequest, ModStampedRequest(lastRequest.modificationStamp, job = null))
|
||||
}
|
||||
ServiceManager.getService(project, ScriptReportSink::class.java)?.attachReports(file, result.reports)
|
||||
val resultingDependencies = (result.dependencies ?: ScriptDependencies.Empty).adjustByDefinition(scriptDef)
|
||||
if (cache(resultingDependencies, file)) {
|
||||
onChange()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun updateSync(file: VirtualFile, scriptDef: KotlinScriptDefinition): Boolean {
|
||||
val newDeps = contentLoader.loadContentsAndResolveDependencies(scriptDef, file) ?: ScriptDependencies.Empty
|
||||
return cache(newDeps, file)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<error descr="TestDependenciesResolver threw exception IllegalStateException:
|
||||
Exception from resolver">
|
||||
</error>
|
||||
val s = 3
|
||||
val g = 4
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package custom.scriptDefinition
|
||||
|
||||
import java.io.File
|
||||
import kotlin.script.dependencies.*
|
||||
import kotlin.script.dependencies.experimental.*
|
||||
import kotlin.script.templates.ScriptTemplateDefinition
|
||||
|
||||
class TestDependenciesResolver : DependenciesResolver {
|
||||
override fun resolve(
|
||||
scriptContents: ScriptContents,
|
||||
environment: Environment
|
||||
): DependenciesResolver.ResolveResult {
|
||||
error("Exception from resolver")
|
||||
}
|
||||
}
|
||||
|
||||
@ScriptTemplateDefinition(TestDependenciesResolver::class, scriptFilePattern = "script.kts")
|
||||
open class Template
|
||||
+6
@@ -95,4 +95,10 @@ public class ScriptConfigurationHighlightingTestGenerated extends AbstractScript
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/script/definition/highlighting/simple/");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("throwingResolver")
|
||||
public void testThrowingResolver() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/script/definition/highlighting/throwingResolver/");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user