mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Prompt to install dependencies from plugins repository when installing plugins from disk (IDEA-245012)
GitOrigin-RevId: 9c3d0833d13e7aee01a5fc9e929d027de7dd0dc7
This commit is contained in:
committed by
intellij-monorepo-bot
parent
94500445ed
commit
3d1778cc1d
@@ -27,7 +27,7 @@ public class PluginDropHandler extends CustomFileDropHandler {
|
||||
public boolean handleDrop(@NotNull Transferable t, @Nullable Editor editor, Project project) {
|
||||
File file = getFile(t);
|
||||
if (file == null) return false;
|
||||
return PluginInstaller.install(new InstalledPluginsTableModel(), file, PluginInstallCallbackDataKt::installPluginFromCallbackData, null);
|
||||
return PluginInstaller.installFromDisk(new InstalledPluginsTableModel(), file, PluginInstallCallbackDataKt::installPluginFromCallbackData, null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -19,7 +19,6 @@ import com.intellij.openapi.updateSettings.impl.PluginDownloader;
|
||||
import com.intellij.openapi.updateSettings.impl.UpdateSettings;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.SmartList;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
@@ -37,7 +36,7 @@ public class PluginInstallOperation {
|
||||
private final PluginManagerMain.PluginEnabler myPluginEnabler;
|
||||
private final ProgressIndicator myIndicator;
|
||||
private boolean mySuccess = true;
|
||||
private final Set<PluginNode> myDependant = new HashSet<>();
|
||||
private final Set<PluginInstallCallbackData> myDependant = new HashSet<>();
|
||||
private boolean myAllowInstallWithoutRestart = false;
|
||||
private final List<PendingDynamicPluginInstall> myPendingDynamicPluginInstalls = new ArrayList<>();
|
||||
private boolean myRestartRequired = false;
|
||||
@@ -87,7 +86,7 @@ public class PluginInstallOperation {
|
||||
return mySuccess;
|
||||
}
|
||||
|
||||
public Set<PluginNode> getInstalledDependentPlugins() {
|
||||
public Set<PluginInstallCallbackData> getInstalledDependentPlugins() {
|
||||
return myDependant;
|
||||
}
|
||||
|
||||
@@ -160,16 +159,53 @@ public class PluginInstallOperation {
|
||||
|
||||
|
||||
private boolean prepareToInstall(PluginNode pluginNode, List<PluginId> pluginIds) throws IOException {
|
||||
myDependant.add(pluginNode);
|
||||
Ref<IdeaPluginDescriptor> toDisable = checkDependenciesAndReplacements(pluginNode, pluginIds);
|
||||
if (toDisable == null) return false;
|
||||
|
||||
myShownErrors = false;
|
||||
|
||||
PluginDownloader downloader = PluginDownloader.createDownloader(pluginNode, pluginNode.getRepositoryName(), null);
|
||||
|
||||
IdeaPluginDescriptorImpl descriptor = downloader.prepareToInstallAndLoadDescriptor(myIndicator);
|
||||
if (descriptor != null) {
|
||||
boolean allowNoRestart = myAllowInstallWithoutRestart && DynamicPlugins.allowLoadUnloadWithoutRestart(descriptor);
|
||||
if (allowNoRestart) {
|
||||
myPendingDynamicPluginInstalls.add(new PendingDynamicPluginInstall(downloader.getFile(), descriptor));
|
||||
InstalledPluginsState state = InstalledPluginsState.getInstanceIfLoaded();
|
||||
if (state != null) {
|
||||
state.onPluginInstall(downloader.getDescriptor(), false, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
myRestartRequired = true;
|
||||
synchronized (PluginInstaller.ourLock) {
|
||||
downloader.install();
|
||||
}
|
||||
}
|
||||
myDependant.add(new PluginInstallCallbackData(downloader.getFile(), descriptor, !allowNoRestart));
|
||||
pluginNode.setStatus(PluginNode.Status.DOWNLOADED);
|
||||
if (!toDisable.isNull()) {
|
||||
myPluginEnabler.disablePlugins(Collections.singleton(toDisable.get()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
myShownErrors = downloader.isShownErrors();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Ref<IdeaPluginDescriptor> checkDependenciesAndReplacements(IdeaPluginDescriptor pluginNode, @Nullable List<PluginId> pluginIds) {
|
||||
// check for dependent plugins at first.
|
||||
if (pluginNode.getDepends() != null && !pluginNode.getDepends().isEmpty()) {
|
||||
List<IdeaPluginDependency> dependencies = pluginNode.getDependencies();
|
||||
if (!dependencies.isEmpty()) {
|
||||
// prepare plugins list for install
|
||||
final PluginId[] optionalDependentPluginIds = pluginNode.getOptionalDependentPluginIds();
|
||||
final List<PluginNode> depends = new ArrayList<>();
|
||||
final List<PluginNode> optionalDeps = new ArrayList<>();
|
||||
for (int i = 0; i < pluginNode.getDepends().size(); i++) {
|
||||
PluginId depPluginId = pluginNode.getDepends().get(i);
|
||||
for (IdeaPluginDependency dependency : dependencies) {
|
||||
PluginId depPluginId = dependency.getPluginId();
|
||||
|
||||
if (PluginManagerCore.isModuleDependency(depPluginId)) {
|
||||
PluginId pluginIdByModule = PluginModulesHelper.getInstance().getMarketplacePluginIdByModule(depPluginId);
|
||||
@@ -194,7 +230,7 @@ public class PluginInstallOperation {
|
||||
}
|
||||
|
||||
if (depPluginDescriptor != null) {
|
||||
if (ArrayUtil.indexOf(optionalDependentPluginIds, depPluginId) != -1) {
|
||||
if (dependency.isOptional()) {
|
||||
optionalDeps.add(depPlugin);
|
||||
}
|
||||
else {
|
||||
@@ -215,10 +251,10 @@ public class PluginInstallOperation {
|
||||
}, ModalityState.any());
|
||||
}
|
||||
catch (Exception e) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
if (!proceed[0] || !prepareToInstall(depends)) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,10 +270,10 @@ public class PluginInstallOperation {
|
||||
}, ModalityState.any());
|
||||
}
|
||||
catch (Exception e) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
if (proceed[0] && !prepareToInstall(optionalDeps)) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -262,37 +298,7 @@ public class PluginInstallOperation {
|
||||
}, ModalityState.any());
|
||||
}
|
||||
}
|
||||
|
||||
myShownErrors = false;
|
||||
|
||||
PluginDownloader downloader = PluginDownloader.createDownloader(pluginNode, pluginNode.getRepositoryName(), null);
|
||||
|
||||
IdeaPluginDescriptorImpl descriptor = downloader.prepareToInstallAndLoadDescriptor(myIndicator);
|
||||
if (descriptor != null) {
|
||||
if (myAllowInstallWithoutRestart && DynamicPlugins.allowLoadUnloadWithoutRestart(descriptor)) {
|
||||
myPendingDynamicPluginInstalls.add(new PendingDynamicPluginInstall(downloader.getFile(), descriptor));
|
||||
InstalledPluginsState state = InstalledPluginsState.getInstanceIfLoaded();
|
||||
if (state != null) {
|
||||
state.onPluginInstall(downloader.getDescriptor(), false, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
myRestartRequired = true;
|
||||
synchronized (PluginInstaller.ourLock) {
|
||||
downloader.install();
|
||||
}
|
||||
}
|
||||
pluginNode.setStatus(PluginNode.Status.DOWNLOADED);
|
||||
if (!toDisable.isNull()) {
|
||||
myPluginEnabler.disablePlugins(Collections.singleton(toDisable.get()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
myShownErrors = downloader.isShownErrors();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return toDisable;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
@@ -25,8 +25,8 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.ArrayUtilRt;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.io.Decompressor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -230,10 +230,10 @@ public final class PluginInstaller {
|
||||
PluginStateManager.addStateListener(listener);
|
||||
}
|
||||
|
||||
public static boolean install(@NotNull InstalledPluginsTableModel model,
|
||||
@NotNull File file,
|
||||
@NotNull Consumer<? super PluginInstallCallbackData> callback,
|
||||
@Nullable Component parent) {
|
||||
public static boolean installFromDisk(@NotNull InstalledPluginsTableModel model,
|
||||
@NotNull File file,
|
||||
@NotNull Consumer<? super PluginInstallCallbackData> callback,
|
||||
@Nullable Component parent) {
|
||||
try {
|
||||
IdeaPluginDescriptorImpl pluginDescriptor = PluginDescriptorLoader.loadDescriptorFromArtifact(file.toPath(), null);
|
||||
if (pluginDescriptor == null) {
|
||||
@@ -273,19 +273,55 @@ public final class PluginInstaller {
|
||||
return false;
|
||||
}
|
||||
|
||||
PluginManagerMain.PluginEnabler pluginEnabler = model instanceof PluginManagerMain.PluginEnabler
|
||||
? (PluginManagerMain.PluginEnabler)model
|
||||
: new PluginManagerMain.PluginEnabler.HEADLESS();
|
||||
Ref<Boolean> cancel = Ref.create(false);
|
||||
Ref<IdeaPluginDescriptor> toDisable = new Ref<>();
|
||||
Ref<Boolean> dependenciesRequireRestart = Ref.create(false);
|
||||
Set<PluginInstallCallbackData> installedDependencies = new HashSet<>();
|
||||
boolean success = ProgressManager.getInstance().runProcessWithProgressSynchronously(() -> {
|
||||
PluginInstallOperation dependencyInstallOperation = new PluginInstallOperation(
|
||||
Collections.emptyList(),
|
||||
CustomPluginRepositoryService.getInstance().getCustomRepositoryPlugins(),
|
||||
pluginEnabler,
|
||||
ProgressManager.getInstance().getProgressIndicator());
|
||||
dependencyInstallOperation.setAllowInstallWithoutRestart(true);
|
||||
Ref<IdeaPluginDescriptor> ref = dependencyInstallOperation.checkDependenciesAndReplacements(pluginDescriptor, null);
|
||||
if (ref == null) {
|
||||
cancel.set(true);
|
||||
}
|
||||
else {
|
||||
dependenciesRequireRestart.set(dependencyInstallOperation.isRestartRequired());
|
||||
installedDependencies.addAll(dependencyInstallOperation.getInstalledDependentPlugins());
|
||||
toDisable.set(ref.get());
|
||||
}
|
||||
}, IdeBundle.message("progress.title.checking.plugin.dependencies"), true, null, (JComponent) parent);
|
||||
|
||||
if (!success || cancel.get()) return false;
|
||||
|
||||
Path oldFile = null;
|
||||
if (installedPlugin != null && !installedPlugin.isBundled()) {
|
||||
oldFile = installedPlugin.getPluginPath();
|
||||
}
|
||||
|
||||
boolean installWithoutRestart = oldFile == null && DynamicPlugins.allowLoadUnloadWithoutRestart(pluginDescriptor);
|
||||
boolean installWithoutRestart = oldFile == null && DynamicPlugins.allowLoadUnloadWithoutRestart(pluginDescriptor) && !dependenciesRequireRestart.get();
|
||||
if (!installWithoutRestart) {
|
||||
installAfterRestart(file, false, oldFile, pluginDescriptor);
|
||||
}
|
||||
|
||||
ourState.onPluginInstall(pluginDescriptor, installedPlugin != null, !installWithoutRestart);
|
||||
checkInstalledPluginDependencies(model, pluginDescriptor, parent);
|
||||
if (!toDisable.isNull()) {
|
||||
// TODO[yole] unload and check for restart
|
||||
pluginEnabler.disablePlugins(Collections.singleton(toDisable.get()));
|
||||
}
|
||||
checkInstalledPluginDependencies(model, pluginDescriptor, parent,
|
||||
ContainerUtil.map2Set(installedDependencies, (callbackData) -> callbackData.getPluginDescriptor().getPluginId()));
|
||||
callback.consume(new PluginInstallCallbackData(file, pluginDescriptor, !installWithoutRestart));
|
||||
for (PluginInstallCallbackData callbackData: installedDependencies) {
|
||||
if (!callbackData.getPluginDescriptor().getPluginId().equals(pluginDescriptor.getPluginId())) {
|
||||
callback.consume(callbackData);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (IOException ex) {
|
||||
@@ -309,13 +345,14 @@ public final class PluginInstaller {
|
||||
|
||||
private static void checkInstalledPluginDependencies(@NotNull InstalledPluginsTableModel model,
|
||||
@NotNull IdeaPluginDescriptorImpl pluginDescriptor,
|
||||
@Nullable Component parent) {
|
||||
@Nullable Component parent,
|
||||
Set<PluginId> installedDependencies) {
|
||||
final Set<PluginId> notInstalled = new HashSet<>();
|
||||
final Set<PluginId> disabledIds = new HashSet<>();
|
||||
final PluginId[] dependentPluginIds = pluginDescriptor.getDependentPluginIds();
|
||||
final PluginId[] optionalDependentPluginIds = pluginDescriptor.getOptionalDependentPluginIds();
|
||||
for (PluginId id : dependentPluginIds) {
|
||||
if (ArrayUtilRt.find(optionalDependentPluginIds, id) > -1) continue;
|
||||
for (IdeaPluginDependency dep : pluginDescriptor.getDependencies()) {
|
||||
if (dep.isOptional()) continue;
|
||||
PluginId id = dep.getPluginId();
|
||||
if (installedDependencies.contains(id)) continue;
|
||||
final boolean disabled = model.isDisabled(id);
|
||||
final boolean enabled = model.isEnabled(id);
|
||||
if (!enabled && !disabled && !PluginManagerCore.isModuleDependency(id)) {
|
||||
@@ -364,7 +401,7 @@ public final class PluginInstaller {
|
||||
FileChooser.chooseFile(descriptor, null, parent, toSelect, virtualFile -> {
|
||||
File file = VfsUtilCore.virtualToIoFile(virtualFile);
|
||||
PropertiesComponent.getInstance().setValue(PLUGINS_PRESELECTION_PATH, FileUtil.toSystemIndependentName(file.getParent()));
|
||||
install(model, file, callback, parent);
|
||||
installFromDisk(model, file, callback, parent);
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user