From fa367b5b8b3452a0641670a4b1ba9aab709e2fa5 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Sun, 11 Aug 2019 15:28:46 +0200 Subject: [PATCH] When enabling a disabled plugin, reload its descriptor with XInclude resolving to check if it can be enabled on the fly GitOrigin-RevId: fed8b940fb6e5023ef3852732c012bacf5a904f2 --- .../ide/plugins/IdeaPluginDescriptorImpl.java | 23 +++++++++---- .../ide/plugins/PluginManagerCore.java | 33 ++++++++++++------- .../PluginManagerConfigurableNewLayout.java | 4 ++- ...UpdatePluginsFromCustomRepositoryTest.java | 2 +- 4 files changed, 42 insertions(+), 20 deletions(-) diff --git a/platform/core-impl/src/com/intellij/ide/plugins/IdeaPluginDescriptorImpl.java b/platform/core-impl/src/com/intellij/ide/plugins/IdeaPluginDescriptorImpl.java index 3abffb589ceb..ed143cdadd59 100644 --- a/platform/core-impl/src/com/intellij/ide/plugins/IdeaPluginDescriptorImpl.java +++ b/platform/core-impl/src/com/intellij/ide/plugins/IdeaPluginDescriptorImpl.java @@ -135,21 +135,32 @@ public final class IdeaPluginDescriptorImpl implements IdeaPluginDescriptor { public void readExternal(@NotNull Element element, @NotNull URL url, @NotNull JDOMXIncluder.PathResolver pathResolver, - @Nullable Interner stringInterner) throws InvalidDataException, MalformedURLException { + @Nullable Interner stringInterner, + boolean ignoreDisabled) throws InvalidDataException, MalformedURLException { Application app = ApplicationManager.getApplication(); - readExternal(element, url, app != null && app.isUnitTestMode(), pathResolver, stringInterner); + readExternal(element, url, app != null && app.isUnitTestMode(), pathResolver, stringInterner, ignoreDisabled); } - public void loadFromFile(@NotNull File file, @Nullable SafeJdomFactory factory, boolean ignoreMissingInclude) throws IOException, JDOMException { + public void loadFromFile(@NotNull File file, + @Nullable SafeJdomFactory factory, + boolean ignoreMissingInclude) throws IOException, JDOMException { + loadFromFile(file, factory, ignoreMissingInclude, false); + } + + public void loadFromFile(@NotNull File file, + @Nullable SafeJdomFactory factory, + boolean ignoreMissingInclude, + boolean ignoreDisabledPlugins) throws IOException, JDOMException { readExternal(JDOMUtil.load(file, factory), file.toURI().toURL(), ignoreMissingInclude, - JDOMXIncluder.DEFAULT_PATH_RESOLVER, factory == null ? null : factory.stringInterner()); + JDOMXIncluder.DEFAULT_PATH_RESOLVER, factory == null ? null : factory.stringInterner(), ignoreDisabledPlugins); } private void readExternal(@NotNull Element element, @NotNull URL url, boolean ignoreMissingInclude, @NotNull JDOMXIncluder.PathResolver pathResolver, - @Nullable Interner stringInterner) throws InvalidDataException, MalformedURLException { + @Nullable Interner stringInterner, + boolean ignoreDisabledPlugins) throws InvalidDataException, MalformedURLException { // root element always `!isIncludeElement` and it means that result always is a singleton list // (also, plugin xml describes one plugin, this descriptor is not able to represent several plugins) if (JDOMUtil.isEmpty(element)) { @@ -158,7 +169,7 @@ public final class IdeaPluginDescriptorImpl implements IdeaPluginDescriptor { String pluginId = element.getChildTextTrim("id"); if (pluginId == null) pluginId = element.getChildTextTrim("name"); - if (pluginId == null || !PluginManagerCore.disabledPlugins().contains(pluginId)) { + if (pluginId == null || !PluginManagerCore.disabledPlugins().contains(pluginId) || ignoreDisabledPlugins) { JDOMXIncluder.resolveNonXIncludeElement(element, url, ignoreMissingInclude, pathResolver); } else if (LOG.isDebugEnabled()) { diff --git a/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java b/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java index 12cde627256e..c1ebc4e53567 100644 --- a/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java +++ b/platform/core-impl/src/com/intellij/ide/plugins/PluginManagerCore.java @@ -761,7 +761,7 @@ public class PluginManagerCore { try { IdeaPluginDescriptorImpl descriptor = new IdeaPluginDescriptorImpl(notNull(pluginPath, file), loadingContext.isBundled); - descriptor.loadFromFile(descriptorFile, loadingContext.getXmlFactory(), isUnitTestMode); + descriptor.loadFromFile(descriptorFile, loadingContext.getXmlFactory(), isUnitTestMode, loadingContext.ignoreDisabled); return descriptor; } catch (SerializationException | JDOMException | IOException e) { @@ -792,7 +792,7 @@ public class PluginManagerCore { IdeaPluginDescriptorImpl descriptor = new IdeaPluginDescriptorImpl(notNull(pluginPath, file), context.isBundled); SafeJdomFactory factory = context.getXmlFactory(); Interner interner = factory == null ? null : factory.stringInterner(); - descriptor.readExternal(JDOMUtil.load(zipFile.getInputStream(entry), factory), jarURL, pathResolver, interner); + descriptor.readExternal(JDOMUtil.load(zipFile.getInputStream(entry), factory), jarURL, pathResolver, interner, context.ignoreDisabled); context.lastZipWithDescriptor = file; return descriptor; } @@ -812,7 +812,12 @@ public class PluginManagerCore { @Nullable public static IdeaPluginDescriptorImpl loadDescriptor(@NotNull File file, @NotNull String fileName) { - return loadDescriptor(file, fileName, false, false, null); + return loadDescriptor(file, fileName, false); + } + + @Nullable + public static IdeaPluginDescriptorImpl loadDescriptor(@NotNull File file, @NotNull String fileName, boolean ignoreDisabled) { + return loadDescriptor(file, fileName, false, false, ignoreDisabled, null); } @Nullable @@ -820,8 +825,9 @@ public class PluginManagerCore { @NotNull String fileName, boolean bundled, boolean essential, + boolean ignoreDisabled, @Nullable LoadDescriptorsContext parentContext) { - try (LoadingContext context = new LoadingContext(parentContext, bundled, essential)) { + try (LoadingContext context = new LoadingContext(parentContext, bundled, essential, ignoreDisabled)) { return loadDescriptor(file, fileName, context); } } @@ -831,15 +837,17 @@ public class PluginManagerCore { final @Nullable LoadDescriptorsContext parentContext; final boolean isBundled; final boolean isEssential; + final boolean ignoreDisabled; File lastZipWithDescriptor; /** * parentContext is null only for CoreApplicationEnvironment - it is not valid otherwise because in this case XML is not interned. */ - LoadingContext(@Nullable LoadDescriptorsContext parentContext, boolean isBundled, boolean isEssential) { + LoadingContext(@Nullable LoadDescriptorsContext parentContext, boolean isBundled, boolean isEssential, boolean ignoreDisabled) { this.parentContext = parentContext; this.isBundled = isBundled; this.isEssential = isEssential; + this.ignoreDisabled = ignoreDisabled; } @SuppressWarnings("IOResourceOpenedButNotSafelyClosed") @@ -945,7 +953,7 @@ public class PluginManagerCore { // Note that this code is meant for IDE development / testing purposes URL resource = PluginManagerCore.class.getClassLoader().getResource(META_INF + optPathName); if (resource != null) { - optionalDescriptor = loadDescriptorFromResource(resource, optPathName, context.isBundled, false, context.parentContext); + optionalDescriptor = loadDescriptorFromResource(resource, optPathName, context.isBundled, false, context.ignoreDisabled, context.parentContext); } } return optionalDescriptor; @@ -1048,7 +1056,7 @@ public class PluginManagerCore { Set existingResults = new THashSet<>(result); List> tasks = new ArrayList<>(files.length); for (File file : files) { - tasks.add(context.getExecutorService().submit(() -> loadDescriptor(file, PLUGIN_XML, bundled, false, context))); + tasks.add(context.getExecutorService().submit(() -> loadDescriptor(file, PLUGIN_XML, bundled, false, false, context))); } for (Future task : tasks) { @@ -1178,7 +1186,7 @@ public class PluginManagerCore { List> tasks = new ArrayList<>(urls.size()); for (Map.Entry entry : urls.entrySet()) { URL url = entry.getKey(); - tasks.add(context.getExecutorService().submit(() -> loadDescriptorFromResource(url, entry.getValue(), true, url.equals(platformPluginURL), context))); + tasks.add(context.getExecutorService().submit(() -> loadDescriptorFromResource(url, entry.getValue(), true, url.equals(platformPluginURL), false, context))); } // plugin projects may have the same plugins in plugin path (sandbox or SDK) and on the classpath; latter should be ignored @@ -1223,18 +1231,19 @@ public class PluginManagerCore { @NotNull String pathName, boolean bundled, boolean essential, + boolean ignoreDisabled, @Nullable LoadDescriptorsContext parentContext) { try { if (URLUtil.FILE_PROTOCOL.equals(resource.getProtocol())) { File descriptorFile = urlToFile(resource); String pathname = StringUtil.trimEnd(FileUtil.toSystemIndependentName(descriptorFile.getPath()), pathName); File pluginDir = new File(pathname).getParentFile(); - return loadDescriptor(pluginDir, pathName, bundled, essential, parentContext); + return loadDescriptor(pluginDir, pathName, bundled, essential, ignoreDisabled, parentContext); } else if (URLUtil.JAR_PROTOCOL.equals(resource.getProtocol())) { String path = resource.getFile(); File pluginJar = urlToFile(new URL(path.substring(0, path.indexOf(URLUtil.JAR_SEPARATOR)))); - return loadDescriptor(pluginJar, pathName, bundled, essential, parentContext); + return loadDescriptor(pluginJar, pathName, bundled, essential, ignoreDisabled, parentContext); } } catch (Throwable e) { @@ -1265,7 +1274,7 @@ public class PluginManagerCore { for (StringTokenizer t = new StringTokenizer(pathProperty, File.pathSeparator + ","); t.hasMoreTokens();) { String s = t.nextToken(); - IdeaPluginDescriptorImpl ideaPluginDescriptor = loadDescriptor(new File(s), PLUGIN_XML, false, false, context); + IdeaPluginDescriptorImpl ideaPluginDescriptor = loadDescriptor(new File(s), PLUGIN_XML, false, false, false, context); if (ideaPluginDescriptor != null) { result.add(ideaPluginDescriptor); } @@ -1659,7 +1668,7 @@ public class PluginManagerCore { */ public static void registerExtensionPointAndExtensions(@NotNull File pluginRoot, @NotNull String fileName, @NotNull ExtensionsArea area) { IdeaPluginDescriptorImpl descriptor; - try (LoadingContext context = new LoadingContext(null, true, true)) { + try (LoadingContext context = new LoadingContext(null, true, true, false)) { if (pluginRoot.isDirectory()) { descriptor = loadDescriptorFromDir(pluginRoot, fileName, null, context); } diff --git a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerConfigurableNewLayout.java b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerConfigurableNewLayout.java index f22be48fa95c..5ada351da761 100644 --- a/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerConfigurableNewLayout.java +++ b/platform/platform-impl/src/com/intellij/ide/plugins/PluginManagerConfigurableNewLayout.java @@ -1451,7 +1451,9 @@ public class PluginManagerConfigurableNewLayout pluginDescriptorsToDisable.add(descriptor); } else { - pluginDescriptorsToEnable.add(descriptor); + // For disabled plugins, we do not resolve XInclude references and potentially do not load other parts of plugin.xml. + // To check if a plugin can be loaded without restart, we need to read the complete descriptor. + pluginDescriptorsToEnable.add(PluginManagerCore.loadDescriptor(descriptor.getPath(), PluginManagerCore.PLUGIN_XML, true)); } } descriptor.setEnabled(enabled); diff --git a/platform/platform-tests/testSrc/com/intellij/openapi/updateSettings/UpdatePluginsFromCustomRepositoryTest.java b/platform/platform-tests/testSrc/com/intellij/openapi/updateSettings/UpdatePluginsFromCustomRepositoryTest.java index 4754e2da0fb6..68d30f996e6a 100644 --- a/platform/platform-tests/testSrc/com/intellij/openapi/updateSettings/UpdatePluginsFromCustomRepositoryTest.java +++ b/platform/platform-tests/testSrc/com/intellij/openapi/updateSettings/UpdatePluginsFromCustomRepositoryTest.java @@ -45,7 +45,7 @@ public class UpdatePluginsFromCustomRepositoryTest extends BareTestFixtureTestCa String path = PlatformTestUtil.getPlatformTestDataPath() + "updates/customRepositories/" + getTestName(true); File descriptorFile = new File(path, filePath); IdeaPluginDescriptorImpl descriptor = new IdeaPluginDescriptorImpl(descriptorFile.getParentFile(), false); - descriptor.loadFromFile(descriptorFile, null, true); + descriptor.loadFromFile(descriptorFile, null, true, true); return descriptor; } } \ No newline at end of file