[evaluation-plugin] fix: configure projects using warmup util (GO-16057)

GitOrigin-RevId: ff97d17322c510af9f0e7ee3ab432725ba424964
This commit is contained in:
Andrei Efanov
2024-02-19 18:21:23 +01:00
committed by intellij-monorepo-bot
parent 634eab862c
commit 7892d33c7c
3 changed files with 13 additions and 144 deletions

View File

@@ -23,5 +23,6 @@
<orderEntry type="library" name="gson" level="project" />
<orderEntry type="library" name="commons-text" level="project" />
<orderEntry type="module" module-name="intellij.platform.inspect" />
<orderEntry type="module" module-name="intellij.platform.warmup" />
</component>
</module>

View File

@@ -20,8 +20,8 @@ import com.intellij.cce.workspace.ConfigFactory
import com.intellij.cce.workspace.EvaluationWorkspace
import com.intellij.openapi.application.ApplicationStarter
import com.intellij.openapi.project.Project
import kotlinx.coroutines.runBlocking
import java.io.File
import com.intellij.warmup.util.importOrOpenProject
import java.nio.file.FileSystems
import java.nio.file.Path
import java.nio.file.Paths
import kotlin.io.path.exists
@@ -69,18 +69,14 @@ internal class CompletionEvaluationStarter : ApplicationStarter {
try {
println("Open and load project $projectPath. Operation may take a few minutes.")
@Suppress("SSBasedInspection")
project = runBlocking {
ProjectOpeningUtils.openProject(
File(projectPath).toPath()
)
}
project = importOrOpenProject(OpenProjectArgsData(FileSystems.getDefault().getPath(projectPath)))
println("Project loaded!")
try {
action(project)
}
catch (exception: Exception) {
throw RuntimeException("Failed to run actions on the project: $exception")
throw RuntimeException("Failed to run actions on the project: $exception", exception)
}
}
catch (e: Exception) {

View File

@@ -1,74 +1,15 @@
// 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.actions
import com.intellij.conversion.ConversionListener
import com.intellij.conversion.ConversionService
import com.intellij.ide.CommandLineInspectionProgressReporter
import com.intellij.ide.CommandLineInspectionProjectConfigurator
import com.intellij.ide.CommandLineInspectionProjectConfigurator.ConfiguratorContext
import com.intellij.ide.impl.PatchProjectUtil
import com.intellij.ide.impl.ProjectUtil.openOrImport
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.application.ex.ApplicationManagerEx
import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.progress.util.ProgressIndicatorBase
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ex.ProjectManagerEx
import com.intellij.openapi.startup.StartupManager
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.warmup.util.OpenProjectArgs
import java.nio.file.Path
import java.util.function.Predicate
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
object ProjectOpeningUtils {
/**
* Rewritten from {@link com.intellij.codeInspection.InspectionApplicationBase}.
* Implementation which reuse InspectionApplicationBase:
*
* val app = object : InspectionApplicationBase() {
* fun open(): Project? {
* return this.openProject(projectPath, parentDisposable)
* }
* }
*
* return app.open() ?: throw ProjectApplicationException("Can not open project")
*/
suspend fun openProject(projectPath: Path): Project {
ApplicationManager.getApplication().assertIsNonDispatchThread()
ApplicationManagerEx.getApplicationEx().isSaveAllowed = false
LocalFileSystem.getInstance().refreshAndFindFileByPath(
FileUtil.toSystemIndependentName(projectPath.toString())
) ?: throw RuntimeException("Project directory not found.")
convertProject(projectPath)
configureProjectEnvironment(projectPath)
val project = openOrImport(projectPath, null, forceOpenInNewFrame = true)
?: throw RuntimeException("Can not open or import project from $projectPath.")
waitAllStartupActivitiesPassed(project)
ApplicationManager.getApplication().invokeAndWait {
VirtualFileManager.getInstance().refreshWithoutFileWatcher(false)
}
ApplicationManager.getApplication().invokeAndWait {
PatchProjectUtil.patchProject(project)
}
waitForInvokeLaterActivities()
return project
}
fun closeProject(project: Project) {
LOG.info("Closing project $project...")
ApplicationManager.getApplication().assertIsNonDispatchThread()
@@ -77,83 +18,14 @@ object ProjectOpeningUtils {
ProjectManagerEx.getInstanceEx().forceCloseProject(project)
}
}
private suspend fun convertProject(projectPath: Path) {
val conversionService = ConversionService.getInstance()
?: throw RuntimeException("Can not convert project $projectPath")
val conversionResult = conversionService.convertSilently(projectPath, ConversionListenerImpl())
if (conversionResult.openingIsCanceled()) {
throw RuntimeException("Project opening is canceled $projectPath")
}
}
private fun configureProjectEnvironment(projectPath: Path) {
for (configurator in CommandLineInspectionProjectConfigurator.EP_NAME.extensionList) {
val context = ConfiguratorContextImpl(projectPath)
if (configurator.isApplicable(context)) {
LOG.info("Applying configurator ${configurator.name} to configure project environment $projectPath.")
configurator.configureEnvironment(context)
}
}
}
private suspend fun waitAllStartupActivitiesPassed(project: Project): Unit = suspendCoroutine {
LOG.info("Waiting all startup activities passed $project...")
StartupManager.getInstance(project).runAfterOpened { it.resume(Unit) }
waitForInvokeLaterActivities()
}
/**
* Magic loop is used to wait all invoke later activities passed.
* No loop coses empty analyzer output as some project opening activities are not finished yet.
*/
private fun waitForInvokeLaterActivities() {
LOG.info("Waiting all invoked later activities...")
repeat(10) {
ApplicationManager.getApplication().invokeAndWait({}, ModalityState.any())
}
}
}
class ConversionListenerImpl : ConversionListener {
override fun conversionNeeded() {
LOG.info("Conversion is needed for project.")
}
override fun successfullyConverted(backupDir: Path) {
LOG.info("Project successfully converted.")
}
override fun error(message: String) {
throw RuntimeException(message)
}
override fun cannotWriteToFiles(readonlyFiles: List<Path>) {
throw RuntimeException("Can not write to files ${readonlyFiles.joinToString { it.fileName.toString() }}")
}
}
class ConfiguratorContextImpl(
private val projectRoot: Path,
private val indicator: ProgressIndicatorBase = ProgressIndicatorBase(),
private val filesFilter: Predicate<Path> = Predicate { true },
private val virtualFilesFilter: Predicate<VirtualFile> = Predicate { true }
) : ConfiguratorContext {
override fun getProgressIndicator() = indicator
override fun getLogger() = object : CommandLineInspectionProgressReporter {
override fun reportError(message: String) {
LOG.warn("ERROR: $message")
}
override fun reportMessage(minVerboseLevel: Int, message: String) {
LOG.info("PROGRESS: $message")
}
}
override fun getProjectPath() = projectRoot
override fun getFilesFilter(): Predicate<Path> = filesFilter
override fun getVirtualFilesFilter(): Predicate<VirtualFile> = virtualFilesFilter
}
data class OpenProjectArgsData(
override val projectDir: Path,
override val convertProject: Boolean = true,
override val configureProject: Boolean = true,
override val disabledConfigurators: Set<String> = emptySet(),
override val pathToConfigurationFile: Path? = null,
) : OpenProjectArgs
private val LOG = logger<ProjectOpeningUtils>()