diff --git a/grid/core-impl/resources/messages/DataGridBundle.properties b/grid/core-impl/resources/messages/DataGridBundle.properties index 74201fcdb192..0c22b0640562 100644 --- a/grid/core-impl/resources/messages/DataGridBundle.properties +++ b/grid/core-impl/resources/messages/DataGridBundle.properties @@ -41,8 +41,11 @@ action.Console.TableResult.DeleteRows.text=Delete Selected Rows action.Console.TableResult.DeleteRows.description=Delete selected rows action.Console.TableResult.LoadFile.text=Load File\u2026 notification.title.no.script.engine.found.for.file.extension=No script engine found for file extension ''{0}'' +notification.plugin.suggestion=Plugin suggestion notification.please.install.js.script.engine=Please install plugin ''{0}'' notification.install.plugin=Install plugin +notification.install.plugin.with.name=Install plugin ''{0}'' +notification.install.plugin.no=No notification.content.please.make.sure.your.script.engine.jar.s.language.runtime.are.in.ide.classpath=Please, make sure your script engine jar(s) and language runtime are in the IDE classpath. notification.title.failed.to.load.script=Failed to load script: {0} excel.xlsx=Excel (xlsx) @@ -396,4 +399,5 @@ action.Console.TableResult.SaveLobAsAction.TableChanged.text=table has been chan action.Console.TableResult.SaveLobAsAction.AmbiguousQueryResult.text=ambiguous query result ({0} rows received) action.Console.TableResult.LoadFullCellAction.Confirmation.title=Warning action.Console.TableResult.LoadFullCellAction.Confirmation.text=One of the loaded cells contains a large amount of data, which may affect performance. Do you want to continue? - +data.loaders.waiting=Waiting for the loaders to be ready +data.loaders.plugin.ad.notification=Get loader for the file ''{0}'' \ No newline at end of file diff --git a/grid/core-impl/src/extensions/ExtensionsService.java b/grid/core-impl/src/extensions/ExtensionsService.java index b9f483d12e60..2e6e02ff207c 100644 --- a/grid/core-impl/src/extensions/ExtensionsService.java +++ b/grid/core-impl/src/extensions/ExtensionsService.java @@ -2,6 +2,7 @@ package com.intellij.database.extensions; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.extensions.PluginId; +import kotlinx.coroutines.Job; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -14,6 +15,10 @@ public class ExtensionsService { return ApplicationManager.getApplication().getService(ExtensionsService.class); } + public @NotNull Job unpackPluginResources(PluginId id) { + return null; + } + public @NotNull Predicate extensionsRootTypeRegularFileFilter() { return null; } diff --git a/grid/core-impl/src/extensions/LoaderScripts.java b/grid/core-impl/src/extensions/LoaderScripts.java index 887ae04ef6b3..e78fef0717b1 100644 --- a/grid/core-impl/src/extensions/LoaderScripts.java +++ b/grid/core-impl/src/extensions/LoaderScripts.java @@ -2,6 +2,7 @@ package com.intellij.database.extensions; import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.util.text.StringUtil; +import kotlinx.coroutines.Job; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -25,6 +26,10 @@ public final class LoaderScripts { private LoaderScripts() { } + public static Job unpackPluginResources() { + return ExtensionsService.getInstance().unpackPluginResources(getPluginId()); + } + public static @Nullable String getScriptsDirectoryWithoutUnpack() { PluginId id = getPluginId(); return id == null ? null : ExtensionsService.getInstance().extensionsRootTypePathWithoutUnpack(id, SCRIPT_DIR); diff --git a/grid/impl/src/extensions/ExtensionsServiceImpl.java b/grid/impl/src/extensions/ExtensionsServiceImpl.java index 81083c853ab4..6137d9cf2b09 100644 --- a/grid/impl/src/extensions/ExtensionsServiceImpl.java +++ b/grid/impl/src/extensions/ExtensionsServiceImpl.java @@ -4,6 +4,7 @@ import com.intellij.ide.extensionResources.ExtensionsRootType; import com.intellij.ide.scratch.ScratchFileService; import com.intellij.openapi.extensions.PluginId; import com.intellij.openapi.util.text.Strings; +import kotlinx.coroutines.Job; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -12,6 +13,11 @@ import java.nio.file.Path; import java.util.function.Predicate; final class ExtensionsServiceImpl extends ExtensionsService { + @Override + public @NotNull Job unpackPluginResources(PluginId id) { + return ExtensionsRootType.getInstance().updateBundledResources(id); + } + @Override public @Nullable Path extensionsRootTypeFindResource(PluginId id, String path) throws IOException { return ExtensionsRootType.getInstance().findResource(id, path); diff --git a/platform/lang-impl/api-dump-unreviewed.txt b/platform/lang-impl/api-dump-unreviewed.txt index d8e17791120c..6e1e7dfe8528 100644 --- a/platform/lang-impl/api-dump-unreviewed.txt +++ b/platform/lang-impl/api-dump-unreviewed.txt @@ -9295,7 +9295,7 @@ f:com.intellij.ide.extensionResources.ExtensionsRootType - getOwner(com.intellij.openapi.vfs.VirtualFile):com.intellij.openapi.extensions.PluginId - s:regularFileFilter():java.util.function.Predicate - substituteName(com.intellij.openapi.project.Project,com.intellij.openapi.vfs.VirtualFile):java.lang.String -- updateBundledResources(com.intellij.openapi.extensions.PluginId):V +- updateBundledResources(com.intellij.openapi.extensions.PluginId):kotlinx.coroutines.Job - updatePluginResources(com.intellij.openapi.extensions.PluginId):V f:com.intellij.ide.extensionResources.ExternalResourcesUnpackExtensionBean - com.intellij.openapi.extensions.PluginAware diff --git a/platform/lang-impl/src/com/intellij/ide/extensionResources/ExtensionsRootType.java b/platform/lang-impl/src/com/intellij/ide/extensionResources/ExtensionsRootType.java index fd7f975f70d0..d683012e0dcb 100644 --- a/platform/lang-impl/src/com/intellij/ide/extensionResources/ExtensionsRootType.java +++ b/platform/lang-impl/src/com/intellij/ide/extensionResources/ExtensionsRootType.java @@ -15,6 +15,9 @@ import com.intellij.openapi.vfs.*; import com.intellij.util.PlatformUtils; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.io.DigestUtil; +import kotlinx.coroutines.CompletableJob; +import kotlinx.coroutines.Job; +import kotlinx.coroutines.JobKt; import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -296,41 +299,66 @@ public final class ExtensionsRootType extends RootType { FileUtil.rename(file, newName); } - private final Set updatingResources = ConcurrentHashMap.newKeySet(); + private final Map updatingResources = new ConcurrentHashMap<>(); - public void updateBundledResources(@NotNull PluginId pluginId) { - executeOnPooledIoThread(() -> { - updateBundledResourcesImpl(pluginId); - }); - } - - private void updateBundledResourcesImpl(@NotNull PluginId pluginId) { + public Job updateBundledResources(@NotNull PluginId pluginId) { IdeaPluginDescriptor plugin = PluginManagerCore.getPlugin(pluginId); - if (plugin == null || updatingResources.contains(plugin) || !updatingResources.add(plugin)) { - return; + if (plugin == null) { + CompletableJob job = JobKt.Job(null); + job.complete(); + return job; } - try { // updating lock - for (ExternalResourcesUnpackExtensionBean pluginBean : ExternalResourcesUnpackExtensionBean.getPluginsBeUnpackedTo(pluginId)) { - updateBundledResourcesImpl(pluginBean.getPluginDescriptor().getPluginId()); + return updatingResources.computeIfAbsent(plugin, (d) -> executeOnPooledIoThread(() -> { + try { + updateBundledResourcesImpl(d); } + finally { + updatingResources.remove(d); + } + })); + } + private void updateBundledResourcesImpl(@NotNull IdeaPluginDescriptor plugin) { + for (ExternalResourcesUnpackExtensionBean pluginBean : ExternalResourcesUnpackExtensionBean.getPluginsBeUnpackedTo(plugin.getPluginId())) { + updateBundledResourcesWithLock(pluginBean.getPluginDescriptor().getPluginId()); + } + + try { ResourceVersions versions = ResourceVersions.getInstance(); if (versions.shouldUpdateResourcesOf(plugin)) { - extractBundledResources(pluginId, ""); + extractBundledResources(plugin.getPluginId(), ""); versions.resourcesUpdated(plugin); } } catch (IOException e) { LOG.warn("Failed to extract bundled resources for plugin: " + plugin.getName(), e); } + } + + private void updateBundledResourcesWithLock(PluginId pluginId) { + IdeaPluginDescriptor ideaDesc = PluginManagerCore.getPlugin(pluginId); + if (ideaDesc == null || updatingResources.containsKey(ideaDesc)) { + return; + } + + CompletableJob job = JobKt.Job(null); + if (updatingResources.putIfAbsent(ideaDesc, job) != null) { + job.complete(); + return; + } + + try { // updating lock + updateBundledResourcesImpl(ideaDesc); + } finally { - updatingResources.remove(plugin); + updatingResources.remove(ideaDesc); + job.complete(); } } @TestOnly public void updatePluginResources(@NotNull PluginId pluginId) { - updateBundledResourcesImpl(pluginId); + updateBundledResourcesWithLock(pluginId); } } diff --git a/platform/util/concurrency/src/com/intellij/util/concurrency/executor.kt b/platform/util/concurrency/src/com/intellij/util/concurrency/executor.kt index 32eac31a0d9a..792997f225ba 100644 --- a/platform/util/concurrency/src/com/intellij/util/concurrency/executor.kt +++ b/platform/util/concurrency/src/com/intellij/util/concurrency/executor.kt @@ -26,8 +26,8 @@ import kotlin.Throws */ @Internal @ApiStatus.Obsolete -fun executeOnPooledIoThread(task: Runnable) { - (ApplicationManager.getApplication() as ComponentManagerEx).getCoroutineScope().launch(Dispatchers.IO) { +fun executeOnPooledIoThread(task: Runnable): Job { + return (ApplicationManager.getApplication() as ComponentManagerEx).getCoroutineScope().launch(Dispatchers.IO) { task.run() } }