From 5849b9860ba5cd72e5f3172fd07c6ad07d33728a Mon Sep 17 00:00:00 2001 From: "Nikita.Skvortsov" Date: Tue, 24 Dec 2024 14:17:48 +0100 Subject: [PATCH] [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 --- .../settings/ProjectBuildClasspathManager.kt | 41 ++++++++++--------- .../ExternalSystemImportingTestCase.java | 2 +- .../ExternalSystemProjectTestCase.kt | 5 ++- .../testFramework/ExternalSystemTestUtil.kt | 14 +++++++ 4 files changed, 41 insertions(+), 21 deletions(-) diff --git a/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/ProjectBuildClasspathManager.kt b/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/ProjectBuildClasspathManager.kt index 917517568b0e..150ab0ccafd2 100644 --- a/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/ProjectBuildClasspathManager.kt +++ b/platform/external-system-api/src/com/intellij/openapi/externalSystem/settings/ProjectBuildClasspathManager.kt @@ -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. + *
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 = ExternalSystemApiUtil.getAllManagers() - .map { it.localSettingsProvider.`fun`(project) } - .flatMap { it.availableProjects.keys } - .map { it.path } - + @RequiresBackgroundThread fun setProjectBuildClasspathSync(value: Map) { - // 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) { - project.workspaceModel - .updateProjectModel("AbstractExternalSystemLocalSettings explicit update") { storage -> - updateOrAddValueToStorage(value, storage) - } - } - private fun updateOrAddValueToStorage( value: Map, 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 = ExternalSystemApiUtil.getAllManagers() + .map { it.localSettingsProvider.`fun`(project) } + .flatMap { it.availableProjects.keys } + .map { it.path } } \ No newline at end of file diff --git a/platform/external-system-api/testFramework/src/com/intellij/platform/externalSystem/testFramework/ExternalSystemImportingTestCase.java b/platform/external-system-api/testFramework/src/com/intellij/platform/externalSystem/testFramework/ExternalSystemImportingTestCase.java index b01dfbcd5738..ddf37d77e078 100644 --- a/platform/external-system-api/testFramework/src/com/intellij/platform/externalSystem/testFramework/ExternalSystemImportingTestCase.java +++ b/platform/external-system-api/testFramework/src/com/intellij/platform/externalSystem/testFramework/ExternalSystemImportingTestCase.java @@ -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 { diff --git a/platform/external-system-api/testFramework/src/com/intellij/platform/externalSystem/testFramework/ExternalSystemProjectTestCase.kt b/platform/external-system-api/testFramework/src/com/intellij/platform/externalSystem/testFramework/ExternalSystemProjectTestCase.kt index 6373eec84e39..1aea4204b15e 100644 --- a/platform/external-system-api/testFramework/src/com/intellij/platform/externalSystem/testFramework/ExternalSystemProjectTestCase.kt +++ b/platform/external-system-api/testFramework/src/com/intellij/platform/externalSystem/testFramework/ExternalSystemProjectTestCase.kt @@ -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) } diff --git a/platform/external-system-api/testFramework/src/com/intellij/platform/externalSystem/testFramework/ExternalSystemTestUtil.kt b/platform/external-system-api/testFramework/src/com/intellij/platform/externalSystem/testFramework/ExternalSystemTestUtil.kt index 0d3bb3fbe6ba..5f9f6975e6a4 100644 --- a/platform/external-system-api/testFramework/src/com/intellij/platform/externalSystem/testFramework/ExternalSystemTestUtil.kt +++ b/platform/external-system-api/testFramework/src/com/intellij/platform/externalSystem/testFramework/ExternalSystemTestUtil.kt @@ -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, project: Project, timeout: Duration = DEFAULT_TEST_TIMEOUT) { + timeoutRunBlocking(timeout) { + ProjectDataManager.getInstance().importData(dataNode, project) + } +} \ No newline at end of file