[es] Do not allow setting project build classpath from EDT IDEA-361978

Change tests that call `setProjectBuildClasspathSync` (via `ProjectDataManager#importData`) to run things on background tread with job in context.

GitOrigin-RevId: a1581a19b8f640340140aaf575e3c656a8a94911
This commit is contained in:
Nikita.Skvortsov
2025-01-31 14:18:01 +00:00
committed by intellij-monorepo-bot
parent 3c250be0e9
commit 5849b9860b
4 changed files with 41 additions and 21 deletions
@@ -14,28 +14,33 @@ import com.intellij.openapi.project.Project
import com.intellij.platform.backend.workspace.WorkspaceModel
import com.intellij.platform.backend.workspace.workspaceModel
import com.intellij.platform.workspace.storage.MutableEntityStorage
import com.intellij.util.concurrency.annotations.RequiresBackgroundThread
import com.intellij.util.ui.EDT.*
import kotlinx.coroutines.CoroutineScope
import org.jetbrains.annotations.ApiStatus
import java.util.*
/**
* Manages the build classpath for external projects within a specific project context.
*
* This service provides functionality to read and update the build classpath configurations
* for external projects associated with the current IntelliJ project.
* To remove outdated information (e.g., a project that is no longer linked to an IntelliJ project), an explicit call to
* [removeUnavailableClasspaths] is required.
* This will remove any information of unavailable (or not yet available!) projects.
* <br>Methods of this service are not thread-safe.
* Get- and Set- method calls should be guarded by a lock on the client side.
*
* @ApiStatus.Internal
*/
@ApiStatus.Internal
@Service(Service.Level.PROJECT)
class ProjectBuildClasspathManager(val project: Project, val coroutineScope: CoroutineScope) {
private fun getAvailableProjectsPaths(): List<String> = ExternalSystemApiUtil.getAllManagers()
.map { it.localSettingsProvider.`fun`(project) }
.flatMap { it.availableProjects.keys }
.map { it.path }
@RequiresBackgroundThread
fun setProjectBuildClasspathSync(value: Map<String, ExternalProjectBuildClasspathPojo>) {
// Android tests' setup undate project build classpath on EDTs
if (isCurrentThreadEdt()) {
runWriteAction { setProjectBuildClasspathInWriteAction(value) }
} else {
runBlockingCancellable {
setProjectBuildClasspath(value)
}
runBlockingCancellable {
setProjectBuildClasspath(value)
}
}
@@ -46,13 +51,6 @@ class ProjectBuildClasspathManager(val project: Project, val coroutineScope: Cor
}
}
fun setProjectBuildClasspathInWriteAction(value: Map<String, ExternalProjectBuildClasspathPojo>) {
project.workspaceModel
.updateProjectModel("AbstractExternalSystemLocalSettings explicit update") { storage ->
updateOrAddValueToStorage(value, storage)
}
}
private fun updateOrAddValueToStorage(
value: Map<String, ExternalProjectBuildClasspathPojo>,
storage: MutableEntityStorage,
@@ -84,4 +82,9 @@ class ProjectBuildClasspathManager(val project: Project, val coroutineScope: Cor
val updatedClasspath = currentClasspath.filterKeys { it in availableProjectsPaths }
setProjectBuildClasspathSync(updatedClasspath)
}
private fun getAvailableProjectsPaths(): List<String> = ExternalSystemApiUtil.getAllManagers()
.map { it.localSettingsProvider.`fun`(project) }
.flatMap { it.availableProjects.keys }
.map { it.path }
}
@@ -452,7 +452,7 @@ public abstract class ExternalSystemImportingTestCase extends ExternalSystemTest
node.visit(dataNode -> dataNode.setIgnored(ignored));
}
runInEdtAndWait(() -> { ProjectDataManager.getInstance().importData(projectDataNode, myProject); });
ExternalSystemTestUtilKt.importData(projectDataNode, myProject);
}
protected void importProject(@NotNull String config, @Nullable Boolean skipIndexing) throws IOException {
@@ -14,6 +14,7 @@ import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.util.io.FileUtil
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.platform.externalSystem.testFramework.ExternalSystemTestUtil.TEST_EXTERNAL_SYSTEM_ID
import com.intellij.platform.ide.progress.runWithModalProgressBlocking
import com.intellij.testFramework.ExtensionTestUtil
import com.intellij.testFramework.HeavyPlatformTestCase
import java.io.File
@@ -56,7 +57,9 @@ abstract class ExternalSystemProjectTestCase : HeavyPlatformTestCase() {
val externalModulePaths = ExternalSystemApiUtil.findAll(node, ProjectKeys.MODULE).map { it.data.linkedExternalProjectPath }.toSet()
settings.getLinkedProjectSettings(projectPath)!!.setModules(externalModulePaths)
ProjectDataManager.getInstance().importData(node, project)
runWithModalProgressBlocking(project, "Import project data from data nodes") {
ProjectDataManager.getInstance().importData(node, project)
}
val projectInfo = InternalExternalProjectInfo(projectSystemId, projectPath, node)
projectManager.updateExternalProjectData(projectInfo)
}
@@ -1,8 +1,15 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.platform.externalSystem.testFramework
import com.intellij.openapi.externalSystem.model.DataNode
import com.intellij.openapi.externalSystem.model.ProjectSystemId
import com.intellij.openapi.externalSystem.model.project.ProjectData
import com.intellij.openapi.externalSystem.service.project.ProjectDataManager
import com.intellij.openapi.project.Project
import com.intellij.testFramework.common.DEFAULT_TEST_TIMEOUT
import com.intellij.testFramework.common.timeoutRunBlocking
import com.intellij.util.messages.Topic
import kotlin.time.Duration
object ExternalSystemTestUtil {
@JvmField
@@ -13,3 +20,10 @@ object ExternalSystemTestUtil {
"TEST_EXTERNAL_SYSTEM_SETTINGS", TestExternalSystemSettingsListener::class.java
)
}
@JvmOverloads
fun importData(dataNode: DataNode<ProjectData>, project: Project, timeout: Duration = DEFAULT_TEST_TIMEOUT) {
timeoutRunBlocking(timeout) {
ProjectDataManager.getInstance().importData<ProjectData?>(dataNode, project)
}
}