IJPL-180572 Added disk installation support for combined plugin manager

GitOrigin-RevId: a12de6ae337d1d4085a199e684e502e32f1a4d67
This commit is contained in:
Denis Zaichenko
2025-06-26 20:28:21 +00:00
committed by intellij-monorepo-bot
parent 7693a01b70
commit 2c00770b3b
15 changed files with 88 additions and 45 deletions
@@ -3264,15 +3264,10 @@ f:com.intellij.ide.plugins.PluginHostsConfigurable
- isModified():Z
- reset():V
f:com.intellij.ide.plugins.PluginInstallCallbackData
- <init>(java.nio.file.Path,com.intellij.ide.plugins.IdeaPluginDescriptorImpl,Z):V
- f:component1():java.nio.file.Path
- f:component2():com.intellij.ide.plugins.IdeaPluginDescriptorImpl
- f:component3():Z
- f:copy(java.nio.file.Path,com.intellij.ide.plugins.IdeaPluginDescriptorImpl,Z):com.intellij.ide.plugins.PluginInstallCallbackData
- bs:copy$default(com.intellij.ide.plugins.PluginInstallCallbackData,java.nio.file.Path,com.intellij.ide.plugins.IdeaPluginDescriptorImpl,Z,I,java.lang.Object):com.intellij.ide.plugins.PluginInstallCallbackData
- equals(java.lang.Object):Z
- f:getFile():java.nio.file.Path
- f:getPluginDescriptor():com.intellij.ide.plugins.IdeaPluginDescriptorImpl
- f:getRestartNeeded():Z
- hashCode():I
f:com.intellij.ide.plugins.PluginInstaller
@@ -3699,19 +3694,6 @@ c:com.intellij.ide.plugins.newui.SearchQueryParser$Marketplace
- p:handleAttribute(java.lang.String,java.lang.String):V
com.intellij.ide.plugins.newui.TabHeaderListener
- a:selectionChanged(I):V
f:com.intellij.ide.plugins.newui.TabbedPaneHeaderComponent
- javax.swing.JPanel
- <init>(com.intellij.openapi.actionSystem.DefaultActionGroup,com.intellij.ide.plugins.newui.TabHeaderListener):V
- addNotify():V
- addTab(java.lang.String,javax.swing.Icon):V
- getSelectionTab():I
- setBounds(I,I,I,I):V
- setListener():V
- setSelection(I):V
- setSelectionWithEvents(I):V
- setTabTooltip(I,java.lang.String):V
- update():V
- updateUI():V
f:com.intellij.ide.plugins.newui.TagComponent
- com.intellij.ide.plugins.newui.LinkComponent
- <init>():V
+6
View File
@@ -218,6 +218,12 @@ f:com.intellij.ide.plugins.InstalledPluginsState
- getInstalledWithoutRestartPlugins():java.util.Collection
com.intellij.ide.plugins.PluginEnableStateChangedListener
- a:stateChanged(java.util.Collection,Z):V
f:com.intellij.ide.plugins.PluginInstallCallbackData
- <init>(java.nio.file.Path,com.intellij.ide.plugins.IdeaPluginDescriptor,Z):V
- f:component2():com.intellij.ide.plugins.IdeaPluginDescriptor
- f:copy(java.nio.file.Path,com.intellij.ide.plugins.IdeaPluginDescriptor,Z):com.intellij.ide.plugins.PluginInstallCallbackData
- bs:copy$default(com.intellij.ide.plugins.PluginInstallCallbackData,java.nio.file.Path,com.intellij.ide.plugins.IdeaPluginDescriptor,Z,I,java.lang.Object):com.intellij.ide.plugins.PluginInstallCallbackData
- f:getPluginDescriptor():com.intellij.ide.plugins.IdeaPluginDescriptor
com.intellij.ide.plugins.PluginManagerMain$PluginEnabler
- com.intellij.ide.plugins.PluginEnabler
- disable(java.util.Collection):Z
@@ -16,6 +16,7 @@ import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.StandardFileSystems;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.concurrency.annotations.RequiresEdt;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -25,6 +26,7 @@ import java.util.Locale;
import java.util.Set;
import java.util.function.Consumer;
@ApiStatus.Internal
public class InstallFromDiskAction extends DumbAwareAction {
private static final String PLUGINS_PRESELECTION_PATH = "plugins.preselection.path";
@@ -4,8 +4,8 @@ package com.intellij.ide.plugins
import java.nio.file.Path
data class PluginInstallCallbackData(
val file: Path,
val pluginDescriptor: IdeaPluginDescriptorImpl,
val file: Path?,
val pluginDescriptor: IdeaPluginDescriptor,
val restartNeeded: Boolean,
)
@@ -251,7 +251,8 @@ public final class PluginInstaller {
}, IdeBundle.message("action.InstallFromDiskAction.progress.text"), true, project);
if (pluginDescriptor == null) {
MessagesEx.showErrorDialog(parent, IdeBundle.message("dialog.message.fail.to.load.plugin.descriptor.from.file", file.getFileName()), CommonBundle.getErrorTitle());
MessagesEx.showErrorDialog(parent, IdeBundle.message("dialog.message.fail.to.load.plugin.descriptor.from.file", file.getFileName()),
CommonBundle.getErrorTitle());
return;
}
@@ -278,7 +279,8 @@ public final class PluginInstaller {
return;
}
if (isBrokenPlugin(pluginDescriptor)) {
var message = CoreBundle.message("plugin.loading.error.long.marked.as.broken", pluginDescriptor.getName(), pluginDescriptor.getVersion());
var message =
CoreBundle.message("plugin.loading.error.long.marked.as.broken", pluginDescriptor.getName(), pluginDescriptor.getVersion());
MessagesEx.showErrorDialog(parent, message, CommonBundle.getErrorTitle());
return;
}
@@ -452,15 +454,16 @@ public final class PluginInstaller {
@RequiresEdt
static void installPluginFromCallbackData(@NotNull PluginInstallCallbackData callbackData) {
var descriptor = callbackData.getPluginDescriptor();
if (callbackData.getRestartNeeded()) {
shutdownOrRestartAppAfterInstall(descriptor);
}
else {
var loaded = installAndLoadDynamicPlugin(callbackData.getFile(), descriptor);
if (!loaded) {
if (callbackData.getPluginDescriptor() instanceof IdeaPluginDescriptorImpl descriptor && callbackData.getFile() != null) {
if (callbackData.getRestartNeeded()) {
shutdownOrRestartAppAfterInstall(descriptor);
}
else {
var loaded = installAndLoadDynamicPlugin(callbackData.getFile(), descriptor);
if (!loaded) {
shutdownOrRestartAppAfterInstall(descriptor);
}
}
}
}
@@ -468,9 +471,9 @@ public final class PluginInstaller {
PluginManagerConfigurable.shutdownOrRestartAppAfterInstall(
PluginManagerConfigurable.getUpdatesDialogTitle(),
action -> IdeBundle.message("plugin.installed.ide.restart.required.message",
descriptor.getName(),
action,
ApplicationNamesInfo.getInstance()
.getFullProductName()));
descriptor.getName(),
action,
ApplicationNamesInfo.getInstance()
.getFullProductName()));
}
}
@@ -95,6 +95,8 @@ public final class PluginManagerConfigurable
public static final String ID = "preferences.pluginManager";
public static final String SELECTION_TAB_KEY = "PluginConfigurable.selectionTab";
public static final DataKey<Consumer<PluginInstallCallbackData>> PLUGIN_INSTALL_CALLBACK_DATA_KEY =
DataKey.create("PLUGIN_INSTALL_CALLBACK_DATA_KEY");
@SuppressWarnings("UseJBColor") public static final Color MAIN_BG_COLOR =
JBColor.namedColor("Plugins.background", JBColor.lazy(() -> JBColor.isBright() ? UIUtil.getListBackground() : new Color(0x313335)));
@@ -204,7 +206,12 @@ public final class PluginManagerConfigurable
String query = (index == MARKETPLACE_TAB ? myInstalledTab : myMarketplaceTab).getSearchQuery();
(index == MARKETPLACE_TAB ? myMarketplaceTab : myInstalledTab).setSearchQuery(query);
});
}){
@Override
public void uiDataSnapshot(@NotNull DataSink sink) {
sink.set(PLUGIN_INSTALL_CALLBACK_DATA_KEY, PluginManagerConfigurable.this::onPluginInstalledFromDisk);
}
};
createGearGotIt();
myUpdateAll.setVisible(false);
@@ -281,7 +288,9 @@ public final class PluginManagerConfigurable
}
getPluginsViewCustomizer().processConfigurable(this);
if (myPluginManagerCustomizer != null) {
myPluginManagerCustomizer.initCustomizer(myCardPanel);
}
return myCardPanel;
}
@@ -355,6 +364,9 @@ public final class PluginManagerConfigurable
PluginManagerConfigurable.this.onPluginInstalledFromDisk(callbackData);
}
});
if (myPluginManagerCustomizer != null) {
actions.addAll(myPluginManagerCustomizer.getExtraPluginsActions());
}
actions.addSeparator();
actions.add(new ChangePluginStateAction(false));
actions.add(new ChangePluginStateAction(true));
@@ -491,7 +503,7 @@ public final class PluginManagerConfigurable
}
private void doCreateMarketplaceTab(@NotNull Consumer<? super PluginsGroupComponent> selectionListener, Project project) {
PluginManagerPanelFactory.INSTANCE.createMarketplacePanel(myCoroutineScope, myPluginModelFacade.getModel(), project, model -> {
PluginManagerPanelFactory.INSTANCE.createMarketplacePanel(myCoroutineScope, myPluginModelFacade.getModel(), project, model -> {
List<PluginsGroup> groups = new ArrayList<>();
try {
Map<String, List<PluginUiModel>> customRepositoriesMap = UiPluginManager.getInstance().getCustomRepositoryPluginMap();
@@ -0,0 +1,10 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.ide.plugins.marketplace
import com.intellij.ide.plugins.api.PluginDto
import kotlinx.serialization.Serializable
import org.jetbrains.annotations.ApiStatus
@Serializable
@ApiStatus.Internal
data class PluginInstalledFromDiskResult(val pluginDto: PluginDto?, val restartNeeded: Boolean)
@@ -155,13 +155,13 @@ public class MyPluginModel extends InstalledPluginsTableModel implements PluginE
}
public void pluginInstalledFromDisk(@NotNull PluginInstallCallbackData callbackData) {
IdeaPluginDescriptorImpl descriptor = callbackData.getPluginDescriptor();
IdeaPluginDescriptor descriptor = callbackData.getPluginDescriptor();
CheckErrorsResult errors = UiPluginManager.getInstance().getErrors(sessionId.toString(), descriptor.getPluginId());
appendOrUpdateDescriptor(new PluginUiModelAdapter(descriptor), callbackData.getRestartNeeded(), getErrors(errors));
if (!callbackData.getRestartNeeded()) {
if (!callbackData.getRestartNeeded() && callbackData.getFile() != null && descriptor instanceof IdeaPluginDescriptorImpl) {
mySession.getDynamicPluginsToInstall().put(descriptor.getPluginId(),
new PendingDynamicPluginInstall(callbackData.getFile(),
descriptor));
(IdeaPluginDescriptorImpl)descriptor));
}
}
@@ -9,9 +9,12 @@ import com.intellij.openapi.util.registry.Registry
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.annotations.Nls
import javax.swing.Action
import javax.swing.JComponent
@ApiStatus.Internal
interface PluginManagerCustomizer {
fun initCustomizer(parentComponent: JComponent)
fun getInstallButonCustomizationModel(
pluginModelFacade: PluginModelFacade,
pluginToInstallModel: PluginUiModel,
@@ -33,6 +36,8 @@ interface PluginManagerCustomizer {
fun updateAfterModification(updateUi: () -> Unit)
fun getExtraPluginsActions(): List<AnAction>
@Nls
fun getAdditionalTitleText(pluginModel: PluginUiModel): String?
@@ -19,6 +19,7 @@ import com.intellij.util.ui.AbstractLayoutManager;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.JBValue;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -32,7 +33,8 @@ import java.awt.event.ComponentEvent;
/**
* @author Alexander Lobas
*/
public final class TabbedPaneHeaderComponent extends JPanel {
@ApiStatus.Internal
public class TabbedPaneHeaderComponent extends JPanel implements UiDataProvider {
private final JBValue myHeight = new JBValue.Float(30);
private final JBValue myGap = new JBValue.Float(10);
@@ -92,6 +94,11 @@ public final class TabbedPaneHeaderComponent extends JPanel {
add(createToolbar(actions, IdeBundle.message("plugin.manager.tooltip"), AllIcons.General.GearPlain), BorderLayout.EAST);
}
@Override
public void uiDataSnapshot(@NotNull DataSink sink) {
}
static @NotNull JComponent createToolbar(@NotNull DefaultActionGroup actions,
@Nullable @NlsActions.ActionText String tooltip,
@NotNull Icon icon) {
@@ -18,6 +18,7 @@ jvm_library(
"//platform/kernel/shared:kernel",
"//platform/kernel/rpc.backend",
"//platform/platform-impl:ide-impl",
"//platform/editor-ui-api:editor-ui",
"//platform/util",
"//platform/plugins/parser/impl",
"//platform/core-impl",
@@ -38,6 +38,7 @@
<orderEntry type="module" module-name="intellij.platform.kernel" />
<orderEntry type="module" module-name="intellij.platform.rpc.backend" />
<orderEntry type="module" module-name="intellij.platform.ide.impl" />
<orderEntry type="module" module-name="intellij.platform.editor.ui" />
<orderEntry type="module" module-name="intellij.platform.util" />
<orderEntry type="module" module-name="intellij.platform.plugins.parser.impl" />
<orderEntry type="module" module-name="intellij.platform.core.impl" />
@@ -2,14 +2,13 @@
package com.intellij.platform.pluginManager.backend.rpc
import com.intellij.ide.plugins.DynamicPlugins
import com.intellij.ide.plugins.InstallFromDiskAction
import com.intellij.ide.plugins.InstallPluginRequest
import com.intellij.ide.plugins.InstalledPluginsTableModel
import com.intellij.ide.plugins.PluginEnabler
import com.intellij.ide.plugins.PluginInstaller
import com.intellij.ide.plugins.PluginManagerCore
import com.intellij.ide.plugins.marketplace.ApplyPluginsStateResult
import com.intellij.ide.plugins.marketplace.CheckErrorsResult
import com.intellij.ide.plugins.marketplace.InstallPluginResult
import com.intellij.ide.plugins.marketplace.PrepareToUninstallResult
import com.intellij.ide.plugins.marketplace.SetEnabledStateResult
import com.intellij.ide.plugins.marketplace.*
import com.intellij.ide.plugins.newui.BgProgressIndicator
import com.intellij.ide.plugins.newui.DefaultUiPluginManagerController
import com.intellij.ide.plugins.newui.PluginManagerSessionService
@@ -46,6 +45,18 @@ class BackendPluginInstallerApi : PluginInstallerApi {
return DefaultUiPluginManagerController.setEnableStateForDependencies(sessionId, descriptorIds, enable)
}
override suspend fun installPluginFromDisk(projectId: ProjectId?): PluginInstalledFromDiskResult {
return withContext(Dispatchers.EDT) {
val project = projectId?.findProjectOrNull()
val deferred = CompletableDeferred<PluginInstalledFromDiskResult>()
InstallFromDiskAction.installPluginFromDisk(null, project, InstalledPluginsTableModel(project), PluginEnabler.HEADLESS, null) {
deferred.complete(PluginInstalledFromDiskResult(PluginDescriptorConverter.toPluginDto(it.pluginDescriptor), it.restartNeeded))
}
deferred.await()
}
}
override suspend fun prepareToUninstall(pluginsToUninstall: List<PluginId>): PrepareToUninstallResult {
return DefaultUiPluginManagerController.prepareToUninstall(pluginsToUninstall)
}
@@ -33,6 +33,7 @@ object PluginDescriptorConverter {
isLicenseOptional = descriptor.isLicenseOptional
releaseVersion = descriptor.releaseVersion
displayCategory = descriptor.displayCategory
releaseDate = descriptor.releaseDate?.toInstant()?.toEpochMilli()
descriptor.dependencies.forEach { dependency ->
addDependency(dependency.pluginId, dependency.isOptional)
@@ -6,6 +6,7 @@ import com.intellij.ide.plugins.marketplace.ApplyPluginsStateResult
import com.intellij.ide.plugins.marketplace.CheckErrorsResult
import com.intellij.openapi.extensions.PluginId
import com.intellij.ide.plugins.marketplace.InstallPluginResult
import com.intellij.ide.plugins.marketplace.PluginInstalledFromDiskResult
import com.intellij.ide.plugins.marketplace.PrepareToUninstallResult
import com.intellij.ide.plugins.marketplace.SetEnabledStateResult
import com.intellij.platform.project.ProjectId
@@ -33,6 +34,7 @@ interface PluginInstallerApi : RemoteApi<Unit> {
suspend fun prepareToUninstall(pluginsToUninstall: List<PluginId>): PrepareToUninstallResult
suspend fun getErrors(sessionId: String, pluginId: PluginId): CheckErrorsResult
suspend fun setEnableStateForDependencies(sessionId: String, descriptorIds: Set<PluginId>, enable: Boolean, ): SetEnabledStateResult
suspend fun installPluginFromDisk(projectId: ProjectId?): PluginInstalledFromDiskResult
companion object {
suspend fun getInstance(): PluginInstallerApi {