[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="gson" level="project" />
<orderEntry type="library" name="commons-text" 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.inspect" />
<orderEntry type="module" module-name="intellij.platform.warmup" />
</component> </component>
</module> </module>

View File

@@ -20,8 +20,8 @@ import com.intellij.cce.workspace.ConfigFactory
import com.intellij.cce.workspace.EvaluationWorkspace import com.intellij.cce.workspace.EvaluationWorkspace
import com.intellij.openapi.application.ApplicationStarter import com.intellij.openapi.application.ApplicationStarter
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import kotlinx.coroutines.runBlocking import com.intellij.warmup.util.importOrOpenProject
import java.io.File import java.nio.file.FileSystems
import java.nio.file.Path import java.nio.file.Path
import java.nio.file.Paths import java.nio.file.Paths
import kotlin.io.path.exists import kotlin.io.path.exists
@@ -69,18 +69,14 @@ internal class CompletionEvaluationStarter : ApplicationStarter {
try { try {
println("Open and load project $projectPath. Operation may take a few minutes.") println("Open and load project $projectPath. Operation may take a few minutes.")
@Suppress("SSBasedInspection") @Suppress("SSBasedInspection")
project = runBlocking { project = importOrOpenProject(OpenProjectArgsData(FileSystems.getDefault().getPath(projectPath)))
ProjectOpeningUtils.openProject(
File(projectPath).toPath()
)
}
println("Project loaded!") println("Project loaded!")
try { try {
action(project) action(project)
} }
catch (exception: Exception) { 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) { 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. // 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 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.ApplicationManager
import com.intellij.openapi.application.ModalityState
import com.intellij.openapi.application.ex.ApplicationManagerEx
import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.progress.util.ProgressIndicatorBase
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ex.ProjectManagerEx import com.intellij.openapi.project.ex.ProjectManagerEx
import com.intellij.openapi.startup.StartupManager import com.intellij.warmup.util.OpenProjectArgs
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 java.nio.file.Path import java.nio.file.Path
import java.util.function.Predicate
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
object ProjectOpeningUtils { 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) { fun closeProject(project: Project) {
LOG.info("Closing project $project...") LOG.info("Closing project $project...")
ApplicationManager.getApplication().assertIsNonDispatchThread() ApplicationManager.getApplication().assertIsNonDispatchThread()
@@ -77,83 +18,14 @@ object ProjectOpeningUtils {
ProjectManagerEx.getInstanceEx().forceCloseProject(project) 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())
}
}
} }
data class OpenProjectArgsData(
class ConversionListenerImpl : ConversionListener { override val projectDir: Path,
override fun conversionNeeded() { override val convertProject: Boolean = true,
LOG.info("Conversion is needed for project.") override val configureProject: Boolean = true,
} override val disabledConfigurators: Set<String> = emptySet(),
override val pathToConfigurationFile: Path? = null,
override fun successfullyConverted(backupDir: Path) { ) : OpenProjectArgs
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
}
private val LOG = logger<ProjectOpeningUtils>() private val LOG = logger<ProjectOpeningUtils>()