diff --git a/plugins/evaluation-plugin/core/src/com/intellij/cce/actions/ActionsGenerator.kt b/plugins/evaluation-plugin/core/src/com/intellij/cce/actions/ActionsGenerator.kt index d981e058c04d..5c353f06365f 100644 --- a/plugins/evaluation-plugin/core/src/com/intellij/cce/actions/ActionsGenerator.kt +++ b/plugins/evaluation-plugin/core/src/com/intellij/cce/actions/ActionsGenerator.kt @@ -2,11 +2,11 @@ package com.intellij.cce.actions import com.intellij.cce.core.CodeFragment -import com.intellij.cce.processor.GenerateActionsProcessor +import com.intellij.cce.processor.ActionGenerator import com.intellij.cce.util.FileTextUtil.computeChecksum -class ActionsGenerator(private val processor: GenerateActionsProcessor) { - fun generate(code: CodeFragment): FileActions { +class ActionsGenerator(private val processor: ActionGenerator) { + suspend fun generate(code: CodeFragment): FileActions { val actions = processor.buildActions(code) return FileActions(code.path, computeChecksum(code.text), actions.count { it is CallFeature }, actions) } diff --git a/plugins/evaluation-plugin/core/src/com/intellij/cce/fus/FusLogsSaver.kt b/plugins/evaluation-plugin/core/src/com/intellij/cce/fus/FusLogsSaver.kt index c7926b7b34f2..dbe6553ec5a9 100644 --- a/plugins/evaluation-plugin/core/src/com/intellij/cce/fus/FusLogsSaver.kt +++ b/plugins/evaluation-plugin/core/src/com/intellij/cce/fus/FusLogsSaver.kt @@ -25,7 +25,7 @@ class FusLogsSaver(private val finalStorageDir: Path, private val allowedGroups: require(finalStorageDir.exists()) } - override fun invokeRememberingLogs(action: () -> T): T { + override suspend fun invokeRememberingLogs(action: suspend () -> T): T { val logFilter: (LogEvent) -> Boolean = if (allowedGroups != null) { log -> log.group.id in allowedGroups } else { _ -> true } diff --git a/plugins/evaluation-plugin/core/src/com/intellij/cce/fus/MockFUSCollector.kt b/plugins/evaluation-plugin/core/src/com/intellij/cce/fus/MockFUSCollector.kt index baad9fa71739..ef8922537273 100644 --- a/plugins/evaluation-plugin/core/src/com/intellij/cce/fus/MockFUSCollector.kt +++ b/plugins/evaluation-plugin/core/src/com/intellij/cce/fus/MockFUSCollector.kt @@ -12,8 +12,10 @@ import java.util.concurrent.CopyOnWriteArrayList import java.util.concurrent.Executor object MockFUSCollector { - fun collectLogEvents(parentDisposable: Disposable, - action: () -> T): Pair, T> { + suspend fun collectLogEvents( + parentDisposable: Disposable, + action: suspend () -> T, + ): Pair, T> { val mockLoggerProvider = MockStatisticsEventLoggerProvider("ML") val llmcLoggerProvider = MockStatisticsEventLoggerProvider("LLMC") @@ -81,7 +83,7 @@ private class MockStatisticsEventLoggerProvider(recorderId: String) : Statistics } } -fun collectingFusLogs(logEventFilter: (LogEvent) -> Boolean, action: () -> T): Pair> = Disposer.newDisposable().use { lifetime -> +suspend fun collectingFusLogs(logEventFilter: (LogEvent) -> Boolean, action: suspend () -> T): Pair> = Disposer.newDisposable().use { lifetime -> val (allFusLogs, result) = MockFUSCollector.collectLogEvents(lifetime, action) val mlFusLogs: List = allFusLogs.filter { logEventFilter(it) } result to mlFusLogs diff --git a/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/ActionInvokingInterpreter.kt b/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/ActionInvokingInterpreter.kt index 968b1a394fb9..4f78a416c665 100644 --- a/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/ActionInvokingInterpreter.kt +++ b/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/ActionInvokingInterpreter.kt @@ -11,7 +11,7 @@ class ActionInvokingInterpreter(private val invokersFactory: InvokersFactory, private val filter: InterpretFilter, private val order: InterpretationOrder) { - fun interpret(fileActions: FileActions, sessionHandler: (Session) -> Unit): List { + suspend fun interpret(fileActions: FileActions, sessionHandler: (Session) -> Unit): List { val actionsInvoker = invokersFactory.createActionsInvoker() val featureInvoker = invokersFactory.createFeatureInvoker() val fileOpener = FileOpener(fileActions.path, actionsInvoker) @@ -40,7 +40,7 @@ class ActionInvokingInterpreter(private val invokersFactory: InvokersFactory, } is CallFeature -> { if (shouldCompleteToken) { - val session = featureInvoker.callFeature(action.expectedText, action.offset, action.nodeProperties, action.sessionId.id) + val session = featureInvoker.call(action.expectedText, action.offset, action.nodeProperties, action.sessionId.id) sessions.add(session) sessionHandler(session) } diff --git a/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/ActionsInvoker.kt b/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/ActionsInvoker.kt index 3b010ea24ec4..53d3af0f86be 100644 --- a/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/ActionsInvoker.kt +++ b/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/ActionsInvoker.kt @@ -10,7 +10,7 @@ interface ActionsInvoker { fun delay(seconds: Int) fun openFile(file: String): String fun closeFile(file: String) - fun optimiseImports(file: String) + suspend fun optimiseImports(file: String) fun isOpen(file: String): Boolean fun save() fun getText(): String diff --git a/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/BindingFeatureInvoker.kt b/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/BindingFeatureInvoker.kt index c63f28d1179c..1020912af4ce 100644 --- a/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/BindingFeatureInvoker.kt +++ b/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/BindingFeatureInvoker.kt @@ -10,14 +10,12 @@ import com.intellij.cce.evaluation.data.EvalDataDescription /** * Feature invoker that add an abstraction layer over evaluation data storage format. */ -interface BindingFeatureInvoker : FeatureInvoker { - fun invoke(properties: TokenProperties): BoundEvalData +interface BindingFeatureInvoker : AsyncFeatureInvoker { + suspend fun invoke(properties: TokenProperties): BoundEvalData - override fun callFeature(expectedText: String, offset: Int, properties: TokenProperties, sessionId: String): Session = + override suspend fun call(expectedText: String, offset: Int, properties: TokenProperties, sessionId: String): Session = invoke(properties).session(expectedText, offset, properties, sessionId) - override fun comparator(generated: String, expected: String): Boolean = true - infix fun > B.bind(value: T): Binding = Binding.create(this, value) } diff --git a/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/FeatureInvoker.kt b/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/FeatureInvoker.kt index b8240f093f25..e2e0c2cf2405 100644 --- a/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/FeatureInvoker.kt +++ b/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/FeatureInvoker.kt @@ -3,8 +3,16 @@ package com.intellij.cce.interpreter import com.intellij.cce.core.Session import com.intellij.cce.core.TokenProperties -interface FeatureInvoker { +interface AsyncFeatureInvoker { + suspend fun call(expectedText: String, offset: Int, properties: TokenProperties, sessionId: String): Session +} + +interface FeatureInvoker : AsyncFeatureInvoker { fun callFeature(expectedText: String, offset: Int, properties: TokenProperties, sessionId: String): Session fun comparator(generated: String, expected: String, ): Boolean + + override suspend fun call(expectedText: String, offset: Int, properties: TokenProperties, sessionId: String): Session { + return callFeature(expectedText, offset, properties, sessionId) + } } diff --git a/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/InvokersFactory.kt b/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/InvokersFactory.kt index e52dbe33016b..b56ce158198c 100644 --- a/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/InvokersFactory.kt +++ b/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/InvokersFactory.kt @@ -2,5 +2,5 @@ package com.intellij.cce.interpreter interface InvokersFactory { fun createActionsInvoker(): ActionsInvoker - fun createFeatureInvoker(): FeatureInvoker + fun createFeatureInvoker(): AsyncFeatureInvoker } diff --git a/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/PresentableFeatureInvoker.kt b/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/PresentableFeatureInvoker.kt index 3dabebd1665c..1b5b1654c74b 100644 --- a/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/PresentableFeatureInvoker.kt +++ b/plugins/evaluation-plugin/core/src/com/intellij/cce/interpreter/PresentableFeatureInvoker.kt @@ -11,8 +11,7 @@ import com.intellij.cce.report.CardLayout * The invocation result is easily presentable as a card in an evaluation report. */ interface PresentableFeatureInvoker : BindingFeatureInvoker { - // TODO suspend to get rid of runBlockingCancellable everywhere - override fun invoke(properties: TokenProperties): PresentableEvalData + override suspend fun invoke(properties: TokenProperties): PresentableEvalData } data class PresentableEvalData( diff --git a/plugins/evaluation-plugin/core/src/com/intellij/cce/metric/util/LLMJudge.kt b/plugins/evaluation-plugin/core/src/com/intellij/cce/metric/util/LLMJudge.kt index aae505771631..4c82fd35224f 100644 --- a/plugins/evaluation-plugin/core/src/com/intellij/cce/metric/util/LLMJudge.kt +++ b/plugins/evaluation-plugin/core/src/com/intellij/cce/metric/util/LLMJudge.kt @@ -6,5 +6,5 @@ data class LLMJudgeResult( ) interface LLMJudge { - fun computeLLMJudgeScoreSync(question: String, aiaResponse: String, reference: String): LLMJudgeResult + suspend fun computeLLMJudgeScoreSync(question: String, aiaResponse: String, reference: String): LLMJudgeResult } diff --git a/plugins/evaluation-plugin/core/src/com/intellij/cce/processor/CodeFragmentProcessor.kt b/plugins/evaluation-plugin/core/src/com/intellij/cce/processor/CodeFragmentProcessor.kt index dc0ac639eff0..574136b289d7 100644 --- a/plugins/evaluation-plugin/core/src/com/intellij/cce/processor/CodeFragmentProcessor.kt +++ b/plugins/evaluation-plugin/core/src/com/intellij/cce/processor/CodeFragmentProcessor.kt @@ -4,5 +4,5 @@ package com.intellij.cce.processor import com.intellij.cce.core.CodeFragment interface CodeFragmentProcessor { - fun process(code: CodeFragment) = Unit + suspend fun processFragment(code: CodeFragment): Unit = Unit } diff --git a/plugins/evaluation-plugin/core/src/com/intellij/cce/processor/EvaluationRootProcessor.kt b/plugins/evaluation-plugin/core/src/com/intellij/cce/processor/EvaluationRootProcessor.kt index 38096285869e..c606c4968757 100644 --- a/plugins/evaluation-plugin/core/src/com/intellij/cce/processor/EvaluationRootProcessor.kt +++ b/plugins/evaluation-plugin/core/src/com/intellij/cce/processor/EvaluationRootProcessor.kt @@ -10,7 +10,7 @@ abstract class EvaluationRootProcessor : CodeFragmentProcessor { class DefaultEvaluationRootProcessor : EvaluationRootProcessor() { private var evaluationRoot: CodeFragment? = null - override fun process(code: CodeFragment) { + override suspend fun processFragment(code: CodeFragment) { evaluationRoot = code } @@ -20,7 +20,7 @@ class DefaultEvaluationRootProcessor : EvaluationRootProcessor() { class EvaluationRootByRangeProcessor(private val startOffset: Int, private val endOffset: Int) : EvaluationRootProcessor() { private var evaluationRoot: CodeFragment? = null - override fun process(code: CodeFragment) { + override suspend fun processFragment(code: CodeFragment) { evaluationRoot = CodeFragment(startOffset, endOffset - startOffset) evaluationRoot?.path = code.path evaluationRoot?.text = code.text diff --git a/plugins/evaluation-plugin/core/src/com/intellij/cce/processor/GenerateActionsProcessor.kt b/plugins/evaluation-plugin/core/src/com/intellij/cce/processor/GenerateActionsProcessor.kt index 5a6cd3effb74..9c2420c4cf86 100644 --- a/plugins/evaluation-plugin/core/src/com/intellij/cce/processor/GenerateActionsProcessor.kt +++ b/plugins/evaluation-plugin/core/src/com/intellij/cce/processor/GenerateActionsProcessor.kt @@ -5,16 +5,32 @@ import com.intellij.cce.actions.Action import com.intellij.cce.actions.ActionsBuilder import com.intellij.cce.core.CodeFragment -abstract class GenerateActionsProcessor : CodeFragmentProcessor { - private lateinit var actionsBuilder: ActionsBuilder +abstract class ActionGenerator : CodeFragmentProcessor { + protected lateinit var actionsBuilder: ActionsBuilder + + suspend fun buildActions(code: CodeFragment): List { + actionsBuilder = ActionsBuilder() + processFragment(code) + return actionsBuilder.build() + } +} + +abstract class AsyncActionGenerator : ActionGenerator() { + open suspend fun process(code: CodeFragment): Unit = Unit + + final override suspend fun processFragment(code: CodeFragment): Unit = process(code) + + protected suspend fun actions(init: suspend ActionsBuilder.() -> Unit) { + init(actionsBuilder) + } +} + +abstract class GenerateActionsProcessor : ActionGenerator() { + open fun process(code: CodeFragment): Unit = Unit + + final override suspend fun processFragment(code: CodeFragment): Unit = process(code) protected fun actions(init: ActionsBuilder.() -> Unit) { init(actionsBuilder) } - - fun buildActions(code: CodeFragment): List { - actionsBuilder = ActionsBuilder() - process(code) - return actionsBuilder.build() - } -} +} \ No newline at end of file diff --git a/plugins/evaluation-plugin/core/src/com/intellij/cce/util/Progress.kt b/plugins/evaluation-plugin/core/src/com/intellij/cce/util/Progress.kt index f4b1ef08c11f..bf4c996a8441 100644 --- a/plugins/evaluation-plugin/core/src/com/intellij/cce/util/Progress.kt +++ b/plugins/evaluation-plugin/core/src/com/intellij/cce/util/Progress.kt @@ -7,9 +7,10 @@ interface Progress { fun finish() = Unit fun isCanceled(): Boolean - fun wrapWithProgress(block: (Progress) -> Unit) { + suspend fun wrapWithProgress(block: suspend (Progress) -> T): T { start() - block(this) + val result = block(this) finish() + return result } } diff --git a/plugins/evaluation-plugin/core/src/com/intellij/cce/workspace/storages/LogsSaver.kt b/plugins/evaluation-plugin/core/src/com/intellij/cce/workspace/storages/LogsSaver.kt index a89133bab53d..aa36ff3bd7f5 100644 --- a/plugins/evaluation-plugin/core/src/com/intellij/cce/workspace/storages/LogsSaver.kt +++ b/plugins/evaluation-plugin/core/src/com/intellij/cce/workspace/storages/LogsSaver.kt @@ -1,13 +1,13 @@ package com.intellij.cce.workspace.storages interface LogsSaver { - fun invokeRememberingLogs(action: () -> T): T + suspend fun invokeRememberingLogs(action: suspend () -> T): T fun save(languageName: String?, trainingPercentage: Int) } class NoLogsSaver : LogsSaver { - override fun invokeRememberingLogs(action: () -> T): T = action() + override suspend fun invokeRememberingLogs(action: suspend () -> T): T = action() override fun save(languageName: String?, trainingPercentage: Int) = Unit } @@ -17,7 +17,7 @@ fun logsSaverIf(condition: Boolean, createSaver: () -> LogsSaver): LogsSaver = i private fun makeNestingCollector(saverA: LogsSaver, saverB: LogsSaver ) = object : LogsSaver { - override fun invokeRememberingLogs(action: () -> T): T { + override suspend fun invokeRememberingLogs(action: suspend () -> T): T { return saverA.invokeRememberingLogs { saverB.invokeRememberingLogs(action) } diff --git a/plugins/evaluation-plugin/core/src/com/intellij/cce/workspace/storages/StatLogsSaver.kt b/plugins/evaluation-plugin/core/src/com/intellij/cce/workspace/storages/StatLogsSaver.kt index 5a764685a509..db0ac61c71e2 100644 --- a/plugins/evaluation-plugin/core/src/com/intellij/cce/workspace/storages/StatLogsSaver.kt +++ b/plugins/evaluation-plugin/core/src/com/intellij/cce/workspace/storages/StatLogsSaver.kt @@ -15,7 +15,7 @@ class StatLogsSaver(private val logsTemporaryStoragePath: Path, private val fina private val formatter = SimpleDateFormat("dd_MM_yyyy") private val sessionIds = linkedSetOf() - override fun invokeRememberingLogs(action: () -> T): T = action() + override suspend fun invokeRememberingLogs(action: suspend () -> T): T = action() override fun save(languageName: String?, trainingPercentage: Int) { val logsDir = logsTemporaryStoragePath.toFile() diff --git a/plugins/evaluation-plugin/languages/src/com/intellij/cce/visitor/CodeFragmentBuilder.kt b/plugins/evaluation-plugin/languages/src/com/intellij/cce/visitor/CodeFragmentBuilder.kt index 931e35cfeb5a..26dee0f79ae9 100644 --- a/plugins/evaluation-plugin/languages/src/com/intellij/cce/visitor/CodeFragmentBuilder.kt +++ b/plugins/evaluation-plugin/languages/src/com/intellij/cce/visitor/CodeFragmentBuilder.kt @@ -23,10 +23,10 @@ abstract class CodeFragmentBuilder { } } - protected fun findRoot(code: CodeFragment, rootProcessor: EvaluationRootProcessor): CodeFragment { - rootProcessor.process(code) + protected suspend fun findRoot(code: CodeFragment, rootProcessor: EvaluationRootProcessor): CodeFragment { + rootProcessor.processFragment(code) return rootProcessor.getRoot() ?: throw NullRootException(code.path) } - abstract fun build(file: VirtualFile, rootProcessor: EvaluationRootProcessor, featureName: String): CodeFragment? + abstract suspend fun build(file: VirtualFile, rootProcessor: EvaluationRootProcessor, featureName: String): CodeFragment? } diff --git a/plugins/evaluation-plugin/languages/src/com/intellij/cce/visitor/CodeFragmentFromPsiBuilder.kt b/plugins/evaluation-plugin/languages/src/com/intellij/cce/visitor/CodeFragmentFromPsiBuilder.kt index 1e96ff3d8eec..d6a2c816e0f6 100644 --- a/plugins/evaluation-plugin/languages/src/com/intellij/cce/visitor/CodeFragmentFromPsiBuilder.kt +++ b/plugins/evaluation-plugin/languages/src/com/intellij/cce/visitor/CodeFragmentFromPsiBuilder.kt @@ -19,7 +19,7 @@ open class CodeFragmentFromPsiBuilder(private val project: Project, val language open fun getVisitors(): List = EvaluationVisitor.EP_NAME.extensionList - override fun build(file: VirtualFile, rootProcessor: EvaluationRootProcessor, featureName: String): CodeFragment? { + override suspend fun build(file: VirtualFile, rootProcessor: EvaluationRootProcessor, featureName: String): CodeFragment? { val psiFile = dumbService.runReadActionInSmartMode { PsiManager.getInstance(project).findFile(file) } diff --git a/plugins/evaluation-plugin/languages/src/com/intellij/cce/visitor/CodeFragmentFromTextBuilder.kt b/plugins/evaluation-plugin/languages/src/com/intellij/cce/visitor/CodeFragmentFromTextBuilder.kt index 38100801672d..5ca00b6ab2ba 100644 --- a/plugins/evaluation-plugin/languages/src/com/intellij/cce/visitor/CodeFragmentFromTextBuilder.kt +++ b/plugins/evaluation-plugin/languages/src/com/intellij/cce/visitor/CodeFragmentFromTextBuilder.kt @@ -8,7 +8,7 @@ import com.intellij.cce.util.text import com.intellij.openapi.vfs.VirtualFile class CodeFragmentFromTextBuilder : CodeFragmentBuilder() { - override fun build(file: VirtualFile, rootProcessor: EvaluationRootProcessor, featureName: String): CodeFragment { + override suspend fun build(file: VirtualFile, rootProcessor: EvaluationRootProcessor, featureName: String): CodeFragment { val text = file.text() val codeFragment = CodeFragment(0, text.length) codeFragment.text = text diff --git a/plugins/evaluation-plugin/src/com/intellij/cce/actions/CompletionEvaluationStarter.kt b/plugins/evaluation-plugin/src/com/intellij/cce/actions/CompletionEvaluationStarter.kt index 9cb2f37e379f..d798f2073296 100644 --- a/plugins/evaluation-plugin/src/com/intellij/cce/actions/CompletionEvaluationStarter.kt +++ b/plugins/evaluation-plugin/src/com/intellij/cce/actions/CompletionEvaluationStarter.kt @@ -20,12 +20,12 @@ import com.intellij.cce.evaluation.FinishEvaluationStep import com.intellij.cce.evaluation.allPreliminarySteps import com.intellij.cce.evaluation.step.ReportGenerationStep import com.intellij.cce.evaluation.step.SetupStatsCollectorStep -import com.intellij.cce.evaluation.step.runInIntellij +import com.intellij.cce.evaluation.step.run import com.intellij.cce.util.ExceptionsUtil.stackTraceToString import com.intellij.cce.workspace.Config import com.intellij.cce.workspace.ConfigFactory import com.intellij.cce.workspace.EvaluationWorkspace -import com.intellij.openapi.application.ApplicationStarter +import com.intellij.openapi.application.ModernApplicationStarter import com.intellij.openapi.application.ex.ApplicationEx.FORCE_EXIT import com.intellij.openapi.application.ex.ApplicationManagerEx import com.intellij.openapi.diagnostic.currentClassLogger @@ -35,12 +35,9 @@ import kotlin.io.path.exists import kotlin.io.path.isDirectory import kotlin.system.exitProcess -internal class CompletionEvaluationStarter : ApplicationStarter { - override val requiredModality: Int - get() = ApplicationStarter.NOT_IN_EDT - - override fun main(args: List) { - fun run() = MainEvaluationCommand("ml-evaluate") +internal class CompletionEvaluationStarter : ModernApplicationStarter() { + override suspend fun start(args: List) { + val command = MainEvaluationCommand("ml-evaluate") .subcommands( FullCommand(), GenerateActionsCommand(), @@ -55,11 +52,16 @@ internal class CompletionEvaluationStarter : ApplicationStarter { it.extend(command) } } - .main(args.toList().subList(1, args.size)) val startTimestamp = System.currentTimeMillis() try { - run() + command.main(args.toList().subList(1, args.size)) + for (subcommand in command.registeredSubcommands()) { + if (subcommand is EvaluationCommand) { + subcommand.postponedRun() + } + } + val delta = 5_000 - (System.currentTimeMillis() - startTimestamp) if (delta > 0) { Thread.sleep(delta) // for graceful shutdown @@ -78,6 +80,8 @@ internal class CompletionEvaluationStarter : ApplicationStarter { protected val featureName by argument(name = "Feature name").default("rename") + private var postponed: Boolean = false + protected fun loadConfig(configPath: Path, strategySerializer: StrategySerializer): Config { try { println("Load config: $configPath") @@ -91,25 +95,40 @@ internal class CompletionEvaluationStarter : ApplicationStarter { } } - protected fun runPreliminarySteps(feature: EvaluableFeature<*>, workspace: EvaluationWorkspace) { + abstract suspend fun asyncRun() + + final override fun run() { + // Clikt doesn't support async execution. And there is no way to get the selected command. + // So in this blocking method we only save the intention to run the command. + // Actual execution should be performed later with the postponedRun method. + postponed = true + } + + suspend fun postponedRun() { + if (postponed) { + asyncRun() + } + } + + protected suspend fun runPreliminarySteps(feature: EvaluableFeature<*>, workspace: EvaluationWorkspace) { for (step in allPreliminarySteps(feature)) { println("Starting preliminary step: ${step.name}") - step.runInIntellij(null, workspace) + step.run(workspace) } } } class MainEvaluationCommand(name: String) : EvaluationCommand(name, "Evaluate code completion quality in headless mode") { - override fun run() = Unit + override suspend fun asyncRun() = Unit } abstract class EvaluationCommandBase(name: String, help: String) : EvaluationCommand(name, help) { private val configPath by argument(name = "config-path", help = "Path to config").default(ConfigFactory.DEFAULT_CONFIG_NAME) - override fun run() { + override suspend fun asyncRun() { val feature = EvaluableFeature.forFeature(featureName) ?: throw Exception("No support for the $featureName") val config = loadConfig(Paths.get(configPath), feature.getStrategySerializer()) - val workspace = EvaluationWorkspace.create(config, SetupStatsCollectorStep.statsCollectorLogsDirectory) + val workspace = EvaluationWorkspace.create(config, SetupStatsCollectorStep.statsCollectorLogsDirectory, debug = true) val datasetContext = DatasetContext(workspace, workspace, configPath) runPreliminarySteps(feature, workspace) feature.prepareEnvironment(config, workspace).use { environment -> @@ -147,7 +166,7 @@ internal class CompletionEvaluationStarter : ApplicationStarter { private val generateReport by option(names = arrayOf("--generate-report", "-r"), help = "Generate report").flag() private val reorderElements by option(names = arrayOf("--reorder-elements", "-e"), help = "Reorder elements").flag() - override fun run() { + override suspend fun asyncRun() { val feature = EvaluableFeature.forFeature(featureName) ?: throw Exception("No support for the feature") val workspace = EvaluationWorkspace.open(workspacePath, SetupStatsCollectorStep.statsCollectorLogsDirectory) val datasetContext = DatasetContext(workspace, workspace, null) @@ -170,7 +189,7 @@ internal class CompletionEvaluationStarter : ApplicationStarter { abstract fun getWorkspaces(): List - override fun run() { + override suspend fun asyncRun() { val workspacesToCompare = getWorkspaces() val feature = EvaluableFeature.forFeature(featureName) ?: throw Exception("No support for the feature") val config = workspacesToCompare.map { EvaluationWorkspace.open(it, SetupStatsCollectorStep.statsCollectorLogsDirectory) }.buildMultipleEvaluationsConfig( @@ -207,7 +226,7 @@ internal class CompletionEvaluationStarter : ApplicationStarter { help = "Generate merged report for all evaluation workspaces in a directory") { private val root by argument(name = "directory", help = "Root directory for evaluation workspaces") - override fun run() { + override suspend fun asyncRun() { val workspacesToMerge = readWorkspacesFromDirectory(root) val feature = EvaluableFeature.forFeature(featureName) ?: throw Exception("No support for the feature") val config = workspacesToMerge.map { EvaluationWorkspace.open(it, SetupStatsCollectorStep.statsCollectorLogsDirectory) }.buildMultipleEvaluationsConfig( @@ -234,7 +253,7 @@ internal class CompletionEvaluationStarter : ApplicationStarter { feature, ) - step.runInIntellij(null, outputWorkspace) + step.run(outputWorkspace) } /** diff --git a/plugins/evaluation-plugin/src/com/intellij/cce/actions/ContextCollectionEvaluationCommand.kt b/plugins/evaluation-plugin/src/com/intellij/cce/actions/ContextCollectionEvaluationCommand.kt index 53996cebd10c..20b3fea86bdc 100644 --- a/plugins/evaluation-plugin/src/com/intellij/cce/actions/ContextCollectionEvaluationCommand.kt +++ b/plugins/evaluation-plugin/src/com/intellij/cce/actions/ContextCollectionEvaluationCommand.kt @@ -18,7 +18,8 @@ import com.intellij.cce.filter.EvaluationFilter import com.intellij.cce.filter.EvaluationFilterReader import com.intellij.cce.interpreter.FeatureInvoker import com.intellij.cce.metric.Metric -import com.intellij.cce.processor.GenerateActionsProcessor +import com.intellij.cce.processor.ActionGenerator +import com.intellij.cce.processor.AsyncActionGenerator import com.intellij.cce.report.GeneratorDirectories import com.intellij.cce.report.MultiLineFileReportGenerator import com.intellij.cce.util.FilesHelper @@ -29,6 +30,7 @@ import com.intellij.cce.workspace.ConfigFactory import com.intellij.cce.workspace.EvaluationWorkspace import com.intellij.cce.workspace.storages.FeaturesStorage import com.intellij.cce.workspace.storages.FullLineLogsStorage +import com.intellij.openapi.application.readAction import com.intellij.openapi.application.runInEdt import com.intellij.openapi.application.runReadAction import com.intellij.openapi.editor.Document @@ -52,7 +54,7 @@ internal class ContextCollectionEvaluationCommand : CompletionEvaluationStarter. help = "Path to config" ).default(ConfigFactory.DEFAULT_CONFIG_NAME) - override fun run() { + override suspend fun asyncRun() { val feature = EvaluableFeature.forFeature(featureName) ?: error("There is no support for the $featureName") val config = loadConfig(Paths.get(configPath), feature.getStrategySerializer()) val workspace = EvaluationWorkspace.create(config, SetupStatsCollectorStep.statsCollectorLogsDirectory) @@ -73,10 +75,10 @@ internal class ContextCollectionEvaluationCommand : CompletionEvaluationStarter. feature.name, environment.featureInvoker ) { - override fun prepareDataset(datasetContext: DatasetContext, progress: Progress) { - val files = runReadAction { - FilesHelper.getFilesOfLanguage(project, actions.evaluationRoots, actions.ignoreFileNames, actions.language) - }.sortedBy { it.name } + override suspend fun prepareDataset(datasetContext: DatasetContext, progress: Progress) { + val files = readAction { + FilesHelper.getFilesOfLanguage(project, actions.evaluationRoots, actions.ignoreFileNames, actions.language).sortedBy { it.name } + } val strategy = config.strategy as CompletionContextCollectionStrategy val sampled = files.shuffled(Random(strategy.samplingSeed)).take(strategy.samplesCount).sortedBy { it.name } generateActions(datasetContext, actions.language, sampled, evaluationRootInfo, progress) @@ -142,12 +144,12 @@ private class ContextCollectionActionsInvoker( } } -private class ContextCollectionMultiLineProcessor(private val strategy: CompletionContextCollectionStrategy) : GenerateActionsProcessor() { - override fun process(code: CodeFragment) { +private class ContextCollectionMultiLineProcessor(private val strategy: CompletionContextCollectionStrategy) : AsyncActionGenerator() { + override suspend fun process(code: CodeFragment) { actions { - runReadAction { + readAction { check(code is CodeFragmentWithPsi) - val file = code.psi.dereference() as? PsiFile ?: return@runReadAction + val file = code.psi.dereference() as? PsiFile ?: return@readAction val project = file.project val document = PsiDocumentManager.getInstance(project).getDocument(file) checkNotNull(document) { "There should've been a document instance for $file (${file.virtualFile})" } @@ -278,7 +280,7 @@ private class ContextCollectionStrategySerializer : StrategySerializer("completion-context") { - override fun getGenerateActionsProcessor(strategy: CompletionContextCollectionStrategy, project: Project): GenerateActionsProcessor { + override fun getGenerateActionsProcessor(strategy: CompletionContextCollectionStrategy, project: Project): ActionGenerator { return ContextCollectionMultiLineProcessor(strategy) } diff --git a/plugins/evaluation-plugin/src/com/intellij/cce/actions/CsvEnvironment.kt b/plugins/evaluation-plugin/src/com/intellij/cce/actions/CsvEnvironment.kt index b8aeee579968..cfc9b74124be 100644 --- a/plugins/evaluation-plugin/src/com/intellij/cce/actions/CsvEnvironment.kt +++ b/plugins/evaluation-plugin/src/com/intellij/cce/actions/CsvEnvironment.kt @@ -12,12 +12,12 @@ class CsvEnvironment( override val datasetRef: DatasetRef, private val chunkSize: Int, private val targetField: String, - private val featureInvoker: FeatureInvoker, + private val featureInvoker: AsyncFeatureInvoker, ) : SimpleFileEnvironment { override val preparationDescription: String = "Checking that CSV file exists" - override fun initialize(datasetContext: DatasetContext) { + override suspend fun initialize(datasetContext: DatasetContext) { super.initialize(datasetContext) val datasetPath = datasetContext.path(datasetRef) @@ -49,7 +49,7 @@ class CsvEnvironment( val (target, features) = props.value val call = callFeature(target, props.offset, features) ChunkHelper.Result( - featureInvoker.callFeature(call.expectedText, call.offset, call.nodeProperties, call.sessionId.id), + featureInvoker.call(call.expectedText, call.offset, call.nodeProperties, call.sessionId.id), "$target <- ${features.toList().joinToString(", ") { "${it.first} = ${it.second}" }}", call ) diff --git a/plugins/evaluation-plugin/src/com/intellij/cce/actions/DatasetRef.kt b/plugins/evaluation-plugin/src/com/intellij/cce/actions/DatasetRef.kt index deb389429248..91afb23b771c 100644 --- a/plugins/evaluation-plugin/src/com/intellij/cce/actions/DatasetRef.kt +++ b/plugins/evaluation-plugin/src/com/intellij/cce/actions/DatasetRef.kt @@ -11,7 +11,7 @@ sealed interface DatasetRef { val name: String - fun prepare(datasetContext: DatasetContext) + suspend fun prepare(datasetContext: DatasetContext) fun resultPath(datasetContext: DatasetContext): Path = datasetContext.path(name) @@ -58,7 +58,7 @@ sealed interface DatasetRef { internal data class AbsoluteRef(val relativePath: String) : DatasetRef { override val name: String = Path.of(relativePath).name.toString() - override fun prepare(datasetContext: DatasetContext) { + override suspend fun prepare(datasetContext: DatasetContext) { val path = resultPath(datasetContext) check(path.exists()) { "Path ${relativePath} doesn't exist: ${path.absolutePathString()}" @@ -71,7 +71,7 @@ internal data class AbsoluteRef(val relativePath: String) : DatasetRef { internal data class ConfigRelativeRef(val relativePath: String) : DatasetRef { override val name: String = Path.of(relativePath).normalize().toString() - override fun prepare(datasetContext: DatasetContext) { + override suspend fun prepare(datasetContext: DatasetContext) { val path = resultPath(datasetContext) check(path.exists()) { @@ -90,7 +90,7 @@ internal data class ConfigRelativeRef(val relativePath: String) : DatasetRef { } internal data class ExistingRef(override val name: String) : DatasetRef { - override fun prepare(datasetContext: DatasetContext) { + override suspend fun prepare(datasetContext: DatasetContext) { val path = datasetContext.path(name) check(path.exists()) { @@ -112,7 +112,7 @@ internal data class RemoteFileRef(private val url: String) : DatasetRef { } } - override fun prepare(datasetContext: DatasetContext) { + override suspend fun prepare(datasetContext: DatasetContext) { val path = datasetContext.path(name) if (path.exists()) { @@ -145,7 +145,7 @@ internal data class RemoteFileRef(private val url: String) : DatasetRef { } internal data class AiPlatformFileRef(override val name: String): DatasetRef { - override fun prepare(datasetContext: DatasetContext) { } + override suspend fun prepare(datasetContext: DatasetContext) { } } private val LOG = fileLogger() \ No newline at end of file diff --git a/plugins/evaluation-plugin/src/com/intellij/cce/actions/ProjectActionsEnvironment.kt b/plugins/evaluation-plugin/src/com/intellij/cce/actions/ProjectActionsEnvironment.kt index 3e5324b30d03..5b772d25d399 100644 --- a/plugins/evaluation-plugin/src/com/intellij/cce/actions/ProjectActionsEnvironment.kt +++ b/plugins/evaluation-plugin/src/com/intellij/cce/actions/ProjectActionsEnvironment.kt @@ -4,15 +4,11 @@ package com.intellij.cce.actions import com.intellij.cce.core.* import com.intellij.cce.evaluable.EvaluationStrategy import com.intellij.cce.evaluable.common.CommonActionsInvoker -import com.intellij.cce.evaluation.EvaluationChunk -import com.intellij.cce.evaluation.EvaluationEnvironment -import com.intellij.cce.evaluation.EvaluationRootInfo -import com.intellij.cce.evaluation.EvaluationStep -import com.intellij.cce.evaluation.step.runInIntellij +import com.intellij.cce.evaluation.* import com.intellij.cce.interpreter.* +import com.intellij.cce.processor.ActionGenerator import com.intellij.cce.processor.DefaultEvaluationRootProcessor import com.intellij.cce.processor.EvaluationRootByRangeProcessor -import com.intellij.cce.processor.GenerateActionsProcessor import com.intellij.cce.util.ExceptionsUtil.stackTraceToString import com.intellij.cce.util.FilesHelper import com.intellij.cce.util.Progress @@ -20,12 +16,11 @@ import com.intellij.cce.util.Summary import com.intellij.cce.util.text import com.intellij.cce.visitor.CodeFragmentBuilder import com.intellij.cce.workspace.Config -import com.intellij.cce.workspace.EvaluationWorkspace import com.intellij.cce.workspace.info.FileErrorInfo import com.intellij.cce.workspace.storages.storage.ActionsSingleFileStorage import com.intellij.configurationStore.StoreUtil.saveSettings import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.application.ReadAction +import com.intellij.openapi.application.readAction import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile @@ -39,10 +34,10 @@ open class ProjectActionsEnvironment( private val sessionsLimit: Int?, private val evaluationRootInfo: EvaluationRootInfo, val project: Project, - val processor: GenerateActionsProcessor, + val processor: ActionGenerator, override val setupSteps: List, private val featureName: String, - val featureInvoker: FeatureInvoker, + val featureInvoker: AsyncFeatureInvoker, ) : EvaluationEnvironment { private val datasetRef = config.sourceFile.run { val sf = this ?: "" @@ -56,17 +51,17 @@ open class ProjectActionsEnvironment( override val preparationDescription: String = "Generating actions by selected files" - override fun initialize(datasetContext: DatasetContext) { + override suspend fun initialize(datasetContext: DatasetContext) { datasetRef?.prepare(datasetContext) } - override fun prepareDataset(datasetContext: DatasetContext, progress: Progress) { + override suspend fun prepareDataset(datasetContext: DatasetContext, progress: Progress) { if (datasetRef != null) { val finalPath = DatasetRefConverter().convert(datasetRef, datasetContext, project) ?: datasetContext.path(datasetRef) datasetContext.replaceActionsStorage(ActionsSingleFileStorage(finalPath)) } else { - val filesForEvaluation = ReadAction.compute, Throwable> { + val filesForEvaluation = readAction { FilesHelper.getFilesOfLanguage(project, config.evaluationRoots, config.ignoreFileNames, config.language) } @@ -99,7 +94,7 @@ open class ProjectActionsEnvironment( } } - protected fun generateActions( + protected suspend fun generateActions( datasetContext: DatasetContext, languageName: String?, files: Collection, @@ -171,9 +166,6 @@ open class ProjectActionsEnvironment( actionsSummarizer.save(datasetContext) } - override fun execute(step: EvaluationStep, workspace: EvaluationWorkspace): EvaluationWorkspace? = - step.runInIntellij(project, workspace) - override fun close() { ProjectOpeningUtils.closeProject(project) @@ -248,7 +240,7 @@ open class ProjectActionsEnvironment( override val name: String = fileActions.path override val sessionsExist: Boolean = fileActions.sessionsCount > 0 - override fun evaluate( + override suspend fun evaluate( handler: InterpretationHandler, filter: InterpretFilter, order: InterpretationOrder, @@ -256,7 +248,7 @@ open class ProjectActionsEnvironment( ): EvaluationChunk.Result { val factory = object : InvokersFactory { override fun createActionsInvoker(): ActionsInvoker = CommonActionsInvoker(project) - override fun createFeatureInvoker(): FeatureInvoker = featureInvoker + override fun createFeatureInvoker(): AsyncFeatureInvoker = featureInvoker } val actionInterpreter = ActionInvokingInterpreter(factory, handler, filter, order) return EvaluationChunk.Result( diff --git a/plugins/evaluation-plugin/src/com/intellij/cce/evaluable/ChunkHelper.kt b/plugins/evaluation-plugin/src/com/intellij/cce/evaluable/ChunkHelper.kt index 118de27cb630..4454f787f6f5 100644 --- a/plugins/evaluation-plugin/src/com/intellij/cce/evaluable/ChunkHelper.kt +++ b/plugins/evaluation-plugin/src/com/intellij/cce/evaluable/ChunkHelper.kt @@ -28,14 +28,14 @@ class ChunkHelper( fun chunks( chunkSize: Int, entities: Sequence, - evaluate: ChunkHelper.(Props) -> Result, + evaluate: suspend ChunkHelper.(Props) -> Result, ): Sequence { return entities.chunked(chunkSize).mapIndexed { index, values -> object : EvaluationChunk { override val datasetName: String = this@ChunkHelper.datasetName override val name: String = "${chunkNamePrefix}:${chunkSize * index}-${chunkSize * index + values.size - 1}" - override fun evaluate( + override suspend fun evaluate( handler: InterpretationHandler, filter: InterpretFilter, order: InterpretationOrder, @@ -81,7 +81,7 @@ class ChunkHelper( layoutManager: LayoutManager, chunkSize: Int, entities: Sequence, - evaluate: ChunkHelper.(Props) -> PresentableResult, + evaluate: suspend ChunkHelper.(Props) -> PresentableResult, ): Sequence { return chunks(chunkSize, entities) { props -> var call: CallFeature? = null @@ -111,7 +111,7 @@ class ChunkHelper( fun presentableChunk( layoutManager: LayoutManager, - evaluate: ChunkHelper.(Props) -> PresentableResult + evaluate: suspend ChunkHelper.(Props) -> PresentableResult ): Sequence = presentableChunks(layoutManager, 1, sequenceOf(Unit)) { evaluate(it) } fun callFeature(target: String, offset: Int, features: Map): CallFeature { diff --git a/plugins/evaluation-plugin/src/com/intellij/cce/evaluable/EvaluableFeatureBase.kt b/plugins/evaluation-plugin/src/com/intellij/cce/evaluable/EvaluableFeatureBase.kt index c7261b8715e4..64aa2702c54f 100644 --- a/plugins/evaluation-plugin/src/com/intellij/cce/evaluable/EvaluableFeatureBase.kt +++ b/plugins/evaluation-plugin/src/com/intellij/cce/evaluable/EvaluableFeatureBase.kt @@ -10,8 +10,8 @@ import com.intellij.cce.evaluation.SetupSdkPreferences import com.intellij.cce.evaluation.SetupSdkStepFactory import com.intellij.cce.evaluation.step.CheckProjectSdkStep import com.intellij.cce.evaluation.step.DropProjectSdkStep -import com.intellij.cce.interpreter.FeatureInvoker -import com.intellij.cce.processor.GenerateActionsProcessor +import com.intellij.cce.interpreter.AsyncFeatureInvoker +import com.intellij.cce.processor.ActionGenerator import com.intellij.cce.report.BasicFileReportGenerator import com.intellij.cce.report.FileReportGenerator import com.intellij.cce.report.GeneratorDirectories @@ -30,12 +30,12 @@ abstract class EvaluableFeatureBase(override val name: S /** * how to prepare the context before the feature invocation */ - abstract fun getGenerateActionsProcessor(strategy: T, project: Project): GenerateActionsProcessor + abstract fun getGenerateActionsProcessor(strategy: T, project: Project): ActionGenerator /** * how to call the feature */ - abstract fun getFeatureInvoker(project: Project, language: Language, strategy: T): FeatureInvoker + abstract fun getFeatureInvoker(project: Project, language: Language, strategy: T): AsyncFeatureInvoker abstract fun getEvaluationSteps(language: Language, strategy: T): List diff --git a/plugins/evaluation-plugin/src/com/intellij/cce/evaluable/PresentableFeature.kt b/plugins/evaluation-plugin/src/com/intellij/cce/evaluable/PresentableFeature.kt index 47dca98cf5e9..88bce74026b9 100644 --- a/plugins/evaluation-plugin/src/com/intellij/cce/evaluable/PresentableFeature.kt +++ b/plugins/evaluation-plugin/src/com/intellij/cce/evaluable/PresentableFeature.kt @@ -12,7 +12,6 @@ import com.intellij.cce.report.FileReportGenerator import com.intellij.cce.report.GeneratorDirectories import com.intellij.cce.workspace.Config import com.intellij.cce.workspace.EvaluationWorkspace -import com.intellij.openapi.progress.runBlockingCancellable import java.util.concurrent.atomic.AtomicReference /** @@ -56,11 +55,9 @@ class LayoutManager( ) { private val globalLayout = AtomicReference(workspace.layout) - fun processData(f: suspend () -> PresentableEvalData): PresentableEvalData { - val data = runBlockingCancellable { - PresentableEvalData.augment(augmenters) { - f() - } + suspend fun processData(f: suspend () -> PresentableEvalData): PresentableEvalData { + val data = PresentableEvalData.augment(augmenters) { + f() } try { processData(data) diff --git a/plugins/evaluation-plugin/src/com/intellij/cce/evaluable/common/CommonActionsInvoker.kt b/plugins/evaluation-plugin/src/com/intellij/cce/evaluable/common/CommonActionsInvoker.kt index 0be49e81700c..1f23230d7858 100644 --- a/plugins/evaluation-plugin/src/com/intellij/cce/evaluable/common/CommonActionsInvoker.kt +++ b/plugins/evaluation-plugin/src/com/intellij/cce/evaluable/common/CommonActionsInvoker.kt @@ -16,7 +16,6 @@ import com.intellij.openapi.editor.impl.TrailingSpacesStripper import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.fileEditor.OpenFileDescriptor -import com.intellij.openapi.progress.runBlockingCancellable import com.intellij.openapi.project.Project import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.vfs.LocalFileSystem @@ -29,6 +28,7 @@ import com.intellij.util.progress.sleepCancellable import java.io.File import java.nio.file.Paths +// TODO rewrite without blocking class CommonActionsInvoker(private val project: Project) : ActionsInvoker { init { TestModeFlags.set(CompletionAutoPopupHandler.ourTestingAutopopup, true) @@ -126,10 +126,10 @@ class CommonActionsInvoker(private val project: Project) : ActionsInvoker { FileEditorManager.getInstance(project).closeFile(virtualFile) } - override fun optimiseImports(file: String) { + override suspend fun optimiseImports(file: String) { LOG.info("Optimise imports in file: $file") val virtualFile = LocalFileSystem.getInstance().findFileByIoFile(File(fullPath(file)))!! - return runBlockingCancellable { ImportOptimiser.optimiseImports(project, virtualFile) } + return ImportOptimiser.optimiseImports(project, virtualFile) } override fun isOpen(file: String): Boolean = readActionInSmartMode(project) { diff --git a/plugins/evaluation-plugin/src/com/intellij/cce/evaluable/conflictResolution/ConflictEnvironment.kt b/plugins/evaluation-plugin/src/com/intellij/cce/evaluable/conflictResolution/ConflictEnvironment.kt index fcb13a208be6..6d8518cf3e42 100644 --- a/plugins/evaluation-plugin/src/com/intellij/cce/evaluable/conflictResolution/ConflictEnvironment.kt +++ b/plugins/evaluation-plugin/src/com/intellij/cce/evaluable/conflictResolution/ConflictEnvironment.kt @@ -36,7 +36,7 @@ class ConflictEnvironment( override val name: String = "${fileConflict.hash} - ${fileConflict.fileName}" override val datasetName: String = datasetRef.name - override fun evaluate( + override suspend fun evaluate( handler: InterpretationHandler, filter: InterpretFilter, // TODO should we use it somehow? order: InterpretationOrder, // TODO should we use somehow? diff --git a/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/ActionsInterpretationHandler.kt b/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/ActionsInterpretationHandler.kt index c163a03526d1..10f6113d85db 100644 --- a/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/ActionsInterpretationHandler.kt +++ b/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/ActionsInterpretationHandler.kt @@ -33,7 +33,7 @@ class ActionsInterpretationHandler( logsSaverIf(config.interpret.saveFusLogs) { workspace.fusLogsSaver } ).asCompositeLogsSaver() - fun invoke(environment: EvaluationEnvironment, workspace: EvaluationWorkspace, indicator: Progress) { + suspend fun invoke(environment: EvaluationEnvironment, workspace: EvaluationWorkspace, indicator: Progress) { var sessionsCount: Int val computingTime = measureTimeMillis { sessionsCount = environment.sessionCount(datasetContext) diff --git a/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/EvaluationChunk.kt b/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/EvaluationChunk.kt index 09b434b8217d..ef507035bcb6 100644 --- a/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/EvaluationChunk.kt +++ b/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/EvaluationChunk.kt @@ -14,7 +14,7 @@ interface EvaluationChunk { val sessionsExist: Boolean get() = true - fun evaluate( + suspend fun evaluate( handler: InterpretationHandler, filter: InterpretFilter, order: InterpretationOrder, diff --git a/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/EvaluationEnvironment.kt b/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/EvaluationEnvironment.kt index 5a4d4c0cfe9c..4ee2b18a0e55 100644 --- a/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/EvaluationEnvironment.kt +++ b/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/EvaluationEnvironment.kt @@ -4,9 +4,7 @@ import com.intellij.cce.actions.DatasetContext import com.intellij.cce.actions.DatasetRef import com.intellij.cce.evaluation.data.Bindable import com.intellij.cce.evaluation.data.Binding -import com.intellij.cce.evaluation.step.runInIntellij import com.intellij.cce.util.Progress -import com.intellij.cce.workspace.EvaluationWorkspace /** * Environment represents resources needed for an evaluation. @@ -19,17 +17,15 @@ interface EvaluationEnvironment : AutoCloseable { val preparationDescription: String - fun initialize(datasetContext: DatasetContext) + suspend fun initialize(datasetContext: DatasetContext) - fun prepareDataset(datasetContext: DatasetContext, progress: Progress) + suspend fun prepareDataset(datasetContext: DatasetContext, progress: Progress) fun sessionCount(datasetContext: DatasetContext): Int // TODO should return something closeable for large files fun chunks(datasetContext: DatasetContext): Sequence - fun execute(step: EvaluationStep, workspace: EvaluationWorkspace): EvaluationWorkspace? - // place here just for convenience, should be final protected by meaning infix fun > B.bind(value: T): Binding = Binding.create(this, value) } @@ -42,16 +38,13 @@ interface SimpleFileEnvironment : EvaluationEnvironment { override val preparationDescription: String get() = "Checking that dataset file is available" - override fun initialize(datasetContext: DatasetContext) { + override suspend fun initialize(datasetContext: DatasetContext) { datasetRef.prepare(datasetContext) } - override fun prepareDataset(datasetContext: DatasetContext, progress: Progress) { + override suspend fun prepareDataset(datasetContext: DatasetContext, progress: Progress) { } - override fun execute(step: EvaluationStep, workspace: EvaluationWorkspace): EvaluationWorkspace? = - step.runInIntellij(null, workspace) - override fun close() { } } \ No newline at end of file diff --git a/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/EvaluationProcess.kt b/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/EvaluationProcess.kt index 00fba107b3fb..9d7cab135341 100644 --- a/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/EvaluationProcess.kt +++ b/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/EvaluationProcess.kt @@ -1,25 +1,25 @@ // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.cce.evaluation +import com.intellij.cce.evaluation.step.run import com.intellij.cce.workspace.EvaluationWorkspace import com.intellij.openapi.application.ApplicationManager import kotlin.system.measureTimeMillis class EvaluationProcess private constructor ( - private val environment: EvaluationEnvironment, private val steps: List, private val finalStep: FinishEvaluationStep? ) { companion object { - fun build(environment: EvaluationEnvironment, stepFactory: StepFactory, init: Builder.() -> Unit): EvaluationProcess { + suspend fun build(environment: EvaluationEnvironment, stepFactory: StepFactory, init: Builder.() -> Unit): EvaluationProcess { environment.initialize(stepFactory.datasetContext) val builder = Builder() builder.init() - return builder.build(environment, stepFactory) + return builder.build(stepFactory) } } - fun start(workspace: EvaluationWorkspace): EvaluationWorkspace { + suspend fun start(workspace: EvaluationWorkspace): EvaluationWorkspace { val stats = mutableMapOf() var currentWorkspace = workspace var hasError = false @@ -27,7 +27,7 @@ class EvaluationProcess private constructor ( if (hasError && step !is UndoableEvaluationStep.UndoStep) continue println("Starting step: ${step.name} (${step.description})") val duration = measureTimeMillis { - val result = environment.execute(step, currentWorkspace) + val result = step.run(currentWorkspace) if (result == null) { hasError = true } else { @@ -47,7 +47,7 @@ class EvaluationProcess private constructor ( var shouldGenerateReports: Boolean = false var shouldReorderElements: Boolean = false - fun build(environment: EvaluationEnvironment, factory: StepFactory): EvaluationProcess { + fun build(factory: StepFactory): EvaluationProcess { val steps = mutableListOf() val isTestingEnvironment = ApplicationManager.getApplication().isUnitTestMode @@ -92,7 +92,7 @@ class EvaluationProcess private constructor ( steps.add(step.undoStep()) } - return EvaluationProcess(environment, steps, factory.finishEvaluationStep().takeIf { !isTestingEnvironment }) + return EvaluationProcess(steps, factory.finishEvaluationStep().takeIf { !isTestingEnvironment }) } } } \ No newline at end of file diff --git a/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/step/ActionsInterpretationStep.kt b/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/step/ActionsInterpretationStep.kt index 940b89eadb8f..47be83a2f5ba 100644 --- a/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/step/ActionsInterpretationStep.kt +++ b/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/step/ActionsInterpretationStep.kt @@ -18,7 +18,7 @@ class ActionsInterpretationStep( override val description: String = "Interpretation of generated actions" - override fun runInBackground(workspace: EvaluationWorkspace, progress: Progress): EvaluationWorkspace { + override suspend fun runInBackground(workspace: EvaluationWorkspace, progress: Progress): EvaluationWorkspace { val resultWorkspace = if (newWorkspace) EvaluationWorkspace.create(config, SetupStatsCollectorStep.statsCollectorLogsDirectory) else workspace diff --git a/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/step/BackgroundEvaluationStep.kt b/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/step/BackgroundEvaluationStep.kt index 78f7b75df8b4..b571cf36ca61 100644 --- a/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/step/BackgroundEvaluationStep.kt +++ b/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/step/BackgroundEvaluationStep.kt @@ -9,41 +9,29 @@ import com.intellij.cce.util.Progress import com.intellij.cce.util.TeamcityProgress import com.intellij.cce.util.isUnderTeamCity import com.intellij.cce.workspace.EvaluationWorkspace -import com.intellij.openapi.progress.ProgressIndicator -import com.intellij.openapi.progress.ProgressManager -import com.intellij.openapi.progress.Task -import com.intellij.openapi.progress.impl.BackgroundableProcessIndicator -import com.intellij.openapi.project.Project -import com.intellij.util.concurrency.FutureResult +import kotlin.coroutines.cancellation.CancellationException interface BackgroundEvaluationStep : EvaluationStep { - fun runInBackground(workspace: EvaluationWorkspace, progress: Progress): EvaluationWorkspace + suspend fun runInBackground(workspace: EvaluationWorkspace, progress: Progress): EvaluationWorkspace } -fun EvaluationStep.runInIntellij(project: Project?, workspace: EvaluationWorkspace): EvaluationWorkspace? { +suspend fun EvaluationStep.run(workspace: EvaluationWorkspace): EvaluationWorkspace? { return when (this) { is ForegroundEvaluationStep -> start(workspace) is BackgroundEvaluationStep -> { - val result = FutureResult() - val task = object : Task.Backgroundable(project, name, true) { - override fun run(indicator: ProgressIndicator) { - createProgress(title).wrapWithProgress { - result.set(runInBackground(workspace, it)) - } + createProgress(name).wrapWithProgress { + try { + runInBackground(workspace, it) } - - override fun onCancel() { - evaluationAbortedHandler.onCancel(this.title) - result.set(null) + catch (e: CancellationException) { + evaluationAbortedHandler.onCancel(name) + throw e } - - override fun onThrowable(error: Throwable) { - evaluationAbortedHandler.onError(error, this.title) - result.set(null) + catch (e: Throwable) { + evaluationAbortedHandler.onError(e, name) + null } } - ProgressManager.getInstance().runProcessWithProgressAsynchronously(task, BackgroundableProcessIndicator(task)) - return result.get() } else -> throw IllegalStateException("Unexpected type of `$this`") } diff --git a/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/step/CreateWorkspaceStep.kt b/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/step/CreateWorkspaceStep.kt index 96b6ff710c75..473997d72dbb 100644 --- a/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/step/CreateWorkspaceStep.kt +++ b/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/step/CreateWorkspaceStep.kt @@ -11,7 +11,7 @@ abstract class CreateWorkspaceStep( private val handler: TwoWorkspaceHandler ) : BackgroundEvaluationStep { - override fun runInBackground(workspace: EvaluationWorkspace, progress: Progress): EvaluationWorkspace { + override suspend fun runInBackground(workspace: EvaluationWorkspace, progress: Progress): EvaluationWorkspace { val newWorkspace = EvaluationWorkspace.create(config, SetupStatsCollectorStep.statsCollectorLogsDirectory) handler.invoke(workspace, newWorkspace, progress) return newWorkspace diff --git a/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/step/DatasetPreparationStep.kt b/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/step/DatasetPreparationStep.kt index 770373c058c9..1a883f538a6c 100644 --- a/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/step/DatasetPreparationStep.kt +++ b/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/step/DatasetPreparationStep.kt @@ -13,7 +13,7 @@ class DatasetPreparationStep( override val description: String = environment.preparationDescription - override fun runInBackground(workspace: EvaluationWorkspace, progress: Progress): EvaluationWorkspace { + override suspend fun runInBackground(workspace: EvaluationWorkspace, progress: Progress): EvaluationWorkspace { environment.prepareDataset(datasetContext, progress) return workspace } diff --git a/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/step/ReportGenerationStep.kt b/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/step/ReportGenerationStep.kt index 7f542eb53db6..9186cd60fef0 100644 --- a/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/step/ReportGenerationStep.kt +++ b/plugins/evaluation-plugin/src/com/intellij/cce/evaluation/step/ReportGenerationStep.kt @@ -43,7 +43,7 @@ class ReportGenerationStep( else emptyList() private val sessionLookupFilter: SessionLookupsFilter = SessionLookupsFilter(lookupFilters) - override fun runInBackground(workspace: EvaluationWorkspace, progress: Progress): EvaluationWorkspace { + override suspend fun runInBackground(workspace: EvaluationWorkspace, progress: Progress): EvaluationWorkspace { val workspaces = inputWorkspaces ?: listOf(workspace) val configs = workspaces.map { it.readConfig(feature.getStrategySerializer()) } val evaluationTitles = configs.map { it.reports.evaluationTitle } diff --git a/plugins/evaluation-plugin/src/com/intellij/cce/util/HttpUtil.kt b/plugins/evaluation-plugin/src/com/intellij/cce/util/HttpUtil.kt index 6799a63db5eb..0556008bd21e 100644 --- a/plugins/evaluation-plugin/src/com/intellij/cce/util/HttpUtil.kt +++ b/plugins/evaluation-plugin/src/com/intellij/cce/util/HttpUtil.kt @@ -1,6 +1,5 @@ package com.intellij.cce.util -import com.intellij.openapi.progress.runBlockingCancellable import io.ktor.client.HttpClient import io.ktor.client.engine.java.Java import io.ktor.client.plugins.HttpRequestRetry @@ -36,7 +35,7 @@ private val httpClient: HttpClient by lazy { } } -private suspend fun httpGetSuspend(url: String, authToken: String?): ByteArray { +suspend fun httpGet(url: String, authToken: String?): ByteArray { val response = httpClient.get(url) { headers { if (authToken != null) { @@ -51,10 +50,3 @@ private suspend fun httpGetSuspend(url: String, authToken: String?): ByteArray { return response.bodyAsBytes() } - -fun httpGet(url: String, authToken: String?): ByteArray { - //todo refac eval framework to make it work with suspend funs - return runBlockingCancellable { - httpGetSuspend(url, authToken) - } -} \ No newline at end of file