simplify PluginDescriptorLoader

GitOrigin-RevId: e4c68aa7049cbcd85c3a40fca93458c96d0338b5
This commit is contained in:
Vladimir Krivosheev
2021-03-30 07:08:41 +00:00
committed by intellij-monorepo-bot
parent d92e089eb1
commit d286794a13
12 changed files with 645 additions and 600 deletions
@@ -7,19 +7,19 @@ import com.intellij.openapi.util.SafeJdomFactory;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
import org.jdom.*;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.nio.file.ProviderNotFoundException;
import java.nio.file.spi.FileSystemProvider;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
final class DescriptorListLoadingContext implements AutoCloseable {
@ApiStatus.Internal
public final class DescriptorListLoadingContext implements AutoCloseable {
@SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized")
private static final boolean unitTestWithBundledPlugins = Boolean.getBoolean("idea.run.tests.with.bundled.plugins");
@@ -46,8 +46,6 @@ final class DescriptorListLoadingContext implements AutoCloseable {
private final Map<String, PluginId> optionalConfigNames;
private FileSystemProvider zipFsProvider;
public static @NotNull DescriptorListLoadingContext createSingleDescriptorContext(@NotNull Set<PluginId> disabledPlugins) {
return new DescriptorListLoadingContext(IGNORE_MISSING_SUB_DESCRIPTOR, disabledPlugins, PluginManagerCore.createLoadingResult(null));
}
@@ -70,28 +68,6 @@ final class DescriptorListLoadingContext implements AutoCloseable {
});
}
FileSystemProvider getZipFsProvider() {
FileSystemProvider result = zipFsProvider;
if (result == null) {
result = findZipFsProvider();
zipFsProvider = result;
}
return result;
}
private static @NotNull FileSystemProvider findZipFsProvider() {
for (FileSystemProvider provider : FileSystemProvider.installedProviders()) {
try {
if (provider.getScheme().equals("jar")) {
return provider;
}
}
catch (UnsupportedOperationException ignored) {
}
}
throw new ProviderNotFoundException("Provider not found");
}
boolean isPluginDisabled(@NotNull PluginId id) {
return id != PluginManagerCore.CORE_ID && disabledPlugins.contains(id);
}
@@ -1,57 +1,58 @@
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ide.plugins;
package com.intellij.ide.plugins
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException
import java.nio.file.FileSystem
import java.nio.file.Path
import java.nio.file.ProviderNotFoundException
import java.nio.file.spi.FileSystemProvider
import java.util.*
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.FileSystem;
import java.nio.file.Path;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
// parentContext is null only for CoreApplicationEnvironment - it is not valid otherwise because in this case XML is not interned.
internal class DescriptorLoadingContext : AutoCloseable {
private var openedFiles: MutableMap<Path, FileSystem>? = null
final class DescriptorLoadingContext implements AutoCloseable {
private @Nullable Map<Path, FileSystem> openedFiles;
final DescriptorListLoadingContext parentContext;
final boolean isBundled;
final boolean isEssential;
private var zipFsProvider: FileSystemProvider? = null
/**
* parentContext is null only for CoreApplicationEnvironment - it is not valid otherwise because in this case XML is not interned.
*/
DescriptorLoadingContext(@NotNull DescriptorListLoadingContext parentContext, boolean isBundled, boolean isEssential) {
this.parentContext = parentContext;
this.isBundled = isBundled;
this.isEssential = isEssential;
private fun getZipFsProvider(): FileSystemProvider {
var result = zipFsProvider
if (result == null) {
result = findZipFsProvider()
zipFsProvider = result
}
return result
}
@NotNull FileSystem open(@NotNull Path file) {
if (openedFiles == null) {
openedFiles = new HashMap<>();
}
return openedFiles.computeIfAbsent(file, it -> {
private fun findZipFsProvider(): FileSystemProvider {
for (provider in FileSystemProvider.installedProviders()) {
try {
//noinspection SpellCheckingInspection
return parentContext.getZipFsProvider().newFileSystem(it, Collections.singletonMap("zipinfo-time", "false"));
if (provider.scheme == "jar") {
return provider
}
}
catch (IOException e) {
throw new UncheckedIOException(e);
catch (ignored: UnsupportedOperationException) {
}
});
}
throw ProviderNotFoundException("Provider not found")
}
@Override
public void close() {
if (openedFiles != null) {
for (FileSystem file : openedFiles.values()) {
try {
file.close();
}
catch (IOException ignore) {
}
fun open(file: Path): FileSystem {
if (openedFiles == null) {
openedFiles = HashMap()
}
return openedFiles!!.computeIfAbsent(file) {
@Suppress("SpellCheckingInspection")
getZipFsProvider().newFileSystem(it, Collections.singletonMap("zipinfo-time", "false"))
}
}
override fun close() {
for (file in (openedFiles ?: return).values) {
try {
file.close()
}
catch (ignore: IOException) {
}
}
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,4 +1,4 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ide.plugins;
import com.intellij.core.CoreBundle;
@@ -109,7 +109,7 @@ final class PluginLoadingResult {
error.register(pluginErrors);
}
void reportCannotLoad(@NotNull Path file, Exception e) {
void reportCannotLoad(@NotNull Path file, Throwable e) {
DescriptorListLoadingContext.LOG.warn("Cannot load " + file, e);
globalErrors.add(() -> CoreBundle.message("plugin.loading.error.text.file.contains.invalid.plugin.descriptor",
FileUtil.getLocationRelativeToUserHome(file.toString(), false)));
@@ -70,16 +70,16 @@ public final class PluginManager {
public static @Nullable IdeaPluginDescriptorImpl loadDescriptor(@NotNull Path file,
@NotNull Set<PluginId> disabledPlugins,
boolean bundled,
boolean isBundled,
@NotNull PathResolver pathResolver) {
DescriptorListLoadingContext parentContext = DescriptorListLoadingContext.createSingleDescriptorContext(disabledPlugins);
try (DescriptorLoadingContext context = new DescriptorLoadingContext(parentContext, bundled, false)) {
return PluginDescriptorLoader.loadDescriptorFromFileOrDir(file,
PluginManagerCore.PLUGIN_XML,
context,
pathResolver,
Files.isDirectory(file));
}
return PluginDescriptorLoader.loadDescriptorFromFileOrDir(file,
PluginManagerCore.PLUGIN_XML,
parentContext,
pathResolver,
isBundled,
/* isEssential = */false,
Files.isDirectory(file));
}
/**
@@ -41,7 +41,6 @@ import java.io.*;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.ref.Reference;
import java.net.URL;
import java.nio.file.*;
import java.util.*;
import java.util.concurrent.CompletableFuture;
@@ -731,7 +730,7 @@ public final class PluginManagerCore {
else {
effectiveBundledPluginPath = Paths.get(PathManager.getPreInstalledPluginsPath());
}
PluginDescriptorLoader.loadBundledDescriptorsAndDescriptorsFromDir(context, dir, effectiveBundledPluginPath);
PluginDescriptorLoader.loadBundledDescriptorsAndDescriptorsFromDir(context, dir, effectiveBundledPluginPath, isRunningFromSources());
for (IdeaPluginDescriptorImpl descriptor : loadingResult.idMap.values()) {
if (!descriptor.isBundled()) {
@@ -777,19 +776,6 @@ public final class PluginManagerCore {
prepareLoadingPluginsErrorMessage(pluginErrors, globalErrors, actions);
}
@TestOnly
public static @NotNull List<? extends IdeaPluginDescriptor> testLoadDescriptorsFromClassPath(@NotNull ClassLoader loader)
throws ExecutionException, InterruptedException {
Map<URL, String> urlsFromClassPath = new LinkedHashMap<>();
PluginDescriptorLoader.collectPluginFilesInClassPath(loader, urlsFromClassPath);
BuildNumber buildNumber = BuildNumber.fromString("2042.42");
DescriptorListLoadingContext context = new DescriptorListLoadingContext(0, Collections.emptySet(), new PluginLoadingResult(Collections.emptyMap(), () -> buildNumber, false));
PluginDescriptorLoader.loadDescriptorsFromClassPath(urlsFromClassPath, context, null, new ClassPathXmlPathResolver(loader));
context.result.finishLoading();
return context.result.getEnabledPlugins();
}
public static void scheduleDescriptorLoading() {
getOrScheduleLoading();
}
@@ -802,7 +788,7 @@ public final class PluginManagerCore {
future = CompletableFuture.supplyAsync(() -> {
Activity activity = StartUpMeasurer.startActivity("plugin descriptor loading");
DescriptorListLoadingContext context = PluginDescriptorLoader.loadDescriptors();
DescriptorListLoadingContext context = PluginDescriptorLoader.loadDescriptors(isUnitTestMode, isRunningFromSources());
activity.end();
return context;
}, ForkJoinPool.commonPool());
@@ -1350,21 +1336,7 @@ public final class PluginManagerCore {
* @param area area which extension points and extensions should be registered
*/
public static void registerExtensionPointAndExtensions(@NotNull Path pluginRoot, @NotNull String fileName, @NotNull ExtensionsArea area) {
IdeaPluginDescriptorImpl descriptor;
DescriptorListLoadingContext parentContext =
DescriptorListLoadingContext.createSingleDescriptorContext(DisabledPluginsState.disabledPlugins());
PathResolver pathResolver = PluginXmlPathResolver.DEFAULT_PATH_RESOLVER;
try (DescriptorLoadingContext context = new DescriptorLoadingContext(parentContext, true, true)) {
if (Files.isDirectory(pluginRoot)) {
descriptor = PluginDescriptorLoader
.loadDescriptorFromDir(pluginRoot, META_INF + fileName, null, context.parentContext, context.isEssential, context.isBundled,
pathResolver);
}
else {
descriptor = PluginDescriptorLoader.loadDescriptorFromJar(pluginRoot, fileName, pathResolver, context, null);
}
}
IdeaPluginDescriptorImpl descriptor = PluginDescriptorLoader.INSTANCE.loadForCoreEnv$intellij_platform_core_impl(pluginRoot, fileName);
if (descriptor == null) {
getLogger().error("Cannot load " + fileName + " from " + pluginRoot);
return;
@@ -1387,7 +1359,7 @@ public final class PluginManagerCore {
try {
if (context == null) {
context = PluginDescriptorLoader.loadDescriptors();
context = PluginDescriptorLoader.loadDescriptors(isUnitTestMode, isRunningFromSources());
}
Activity activity = StartUpMeasurer.startActivity("plugin initialization");
PluginManagerState initResult = initializePlugins(context, coreLoader, !isUnitTestMode);
@@ -1,4 +1,4 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.ide.customize;
import com.intellij.ide.IdeBundle;
@@ -34,7 +34,7 @@ public class PluginGroups {
private Runnable myLoadingCallback;
public PluginGroups() {
myAllPlugins = PluginDescriptorLoader.loadUncachedDescriptors();
myAllPlugins = PluginDescriptorLoader.loadUncachedDescriptors(PluginManagerCore.isUnitTestMode, PluginManagerCore.isRunningFromSources());
SwingWorker<List<PluginNode>, Object> worker = new SwingWorker<>() {
@Override
protected @NotNull List<PluginNode> doInBackground() {
@@ -353,10 +353,10 @@ public final class PluginInstaller {
return false;
}
IdeaPluginDescriptorImpl targetDescriptor = PluginManager.loadDescriptor(targetFile,
DisabledPluginsState.disabledPlugins(),
false,
PluginXmlPathResolver.DEFAULT_PATH_RESOLVER);
IdeaPluginDescriptorImpl targetDescriptor = PluginDescriptorLoader.loadDescriptor(targetFile,
DisabledPluginsState.disabledPlugins(),
false,
PluginXmlPathResolver.DEFAULT_PATH_RESOLVER);
if (targetDescriptor == null) {
return false;
}
@@ -22,10 +22,13 @@ internal fun loadDescriptorInTest(dir: Path, disabledPlugins: Set<PluginId> = em
PluginManagerCore.getAndClearPluginLoadingErrors()
val buildNumber = BuildNumber.fromString("2042.42")
val parentContext = DescriptorListLoadingContext(0, disabledPlugins, PluginLoadingResult(emptyMap(), Supplier { buildNumber }))
val result = DescriptorLoadingContext(parentContext, isBundled, /* isEssential = */ true).use { context ->
PluginDescriptorLoader.loadDescriptorFromFileOrDir(dir, PluginManagerCore.PLUGIN_XML, context,
PluginXmlPathResolver.DEFAULT_PATH_RESOLVER, Files.isDirectory(dir))
}
val result = PluginDescriptorLoader.loadDescriptorFromFileOrDir(file = dir,
pathName = PluginManagerCore.PLUGIN_XML,
context = parentContext,
pathResolver = PluginXmlPathResolver.DEFAULT_PATH_RESOLVER,
isBundled = isBundled,
isEssential = true,
isDirectory = Files.isDirectory(dir))
if (result == null) {
@Suppress("USELESS_CAST")
assertThat(PluginManagerCore.getAndClearPluginLoadingErrors()).isNotEmpty
@@ -44,10 +47,13 @@ fun loadExtensionWithText(
}
internal fun loadPluginWithText(pluginBuilder: PluginBuilder, loader: ClassLoader, fs: FileSystem): Disposable {
val directory = if (fs == FileSystems.getDefault())
val directory = if (fs == FileSystems.getDefault()) {
FileUtil.createTempDirectory("test", "test", true).toPath()
else
}
else {
fs.getPath("/").resolve(Ksuid.generate())
}
val pluginDirectory = directory.resolve("plugin")
pluginBuilder.build(pluginDirectory)
@@ -1,4 +1,4 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
@file:Suppress("UsePropertyAccessSyntax")
package com.intellij.ide.plugins
@@ -104,7 +104,7 @@ class PluginDescriptorTest {
Paths.get(testDataPath, "duplicate1.jar").toUri().toURL(),
Paths.get(testDataPath, "duplicate2.jar").toUri().toURL()
)
assertThat(PluginManagerCore.testLoadDescriptorsFromClassPath(URLClassLoader(urls, null))).hasSize(1)
assertThat(PluginDescriptorLoader.testLoadDescriptorsFromClassPath(URLClassLoader(urls, null))).hasSize(1)
}
@Test
@@ -126,7 +126,7 @@ class PluginDescriptorTest {
urls.add(path.toUri().toURL())
}
}
val descriptors = PluginManagerCore.testLoadDescriptorsFromClassPath(URLClassLoader(urls.toTypedArray(), null))
val descriptors = PluginDescriptorLoader.testLoadDescriptorsFromClassPath(URLClassLoader(urls.toTypedArray(), null))
// core and com.intellij.workspace
assertThat(descriptors).hasSize(1)
}
@@ -379,13 +379,13 @@ class PluginDescriptorTest {
}
val loader1 = TestLoader("", "/spaces%20spaces/")
TestCase.assertEquals(1, PluginManagerCore.testLoadDescriptorsFromClassPath(loader1).size)
TestCase.assertEquals(1, PluginDescriptorLoader.testLoadDescriptorsFromClassPath(loader1).size)
val loader2 = TestLoader("", "/spaces spaces/")
TestCase.assertEquals(1, PluginManagerCore.testLoadDescriptorsFromClassPath(loader2).size)
TestCase.assertEquals(1, PluginDescriptorLoader.testLoadDescriptorsFromClassPath(loader2).size)
val loader3 = TestLoader("jar:", "/jar%20spaces.jar!/")
TestCase.assertEquals(1, PluginManagerCore.testLoadDescriptorsFromClassPath(loader3).size)
TestCase.assertEquals(1, PluginDescriptorLoader.testLoadDescriptorsFromClassPath(loader3).size)
val loader4 = TestLoader("jar:", "/jar spaces.jar!/")
assertThat(PluginManagerCore.testLoadDescriptorsFromClassPath(loader4)).hasSize(1)
assertThat(PluginDescriptorLoader.testLoadDescriptorsFromClassPath(loader4)).hasSize(1)
}
@Test
@@ -457,8 +457,8 @@ private fun writeDescriptor(id: String, pluginDir: Path, @Language("xml") data:
}
private val testDataPath: String
get() = PlatformTestUtil.getPlatformTestDataPath() + "plugins/pluginDescriptor"
get() = "${PlatformTestUtil.getPlatformTestDataPath()}plugins/pluginDescriptor"
private fun loadDescriptorInTest(dirName: String, disabledPlugins: Set<PluginId> = emptySet()): IdeaPluginDescriptorImpl {
return loadDescriptorInTest(Paths.get(testDataPath, dirName), disabledPlugins)
return loadDescriptorInTest(Path.of(testDataPath, dirName), disabledPlugins)
}
@@ -64,12 +64,10 @@ internal fun doLoadApp(setupEventQueue: () -> Unit) {
val preloadServiceFuture = preloadServices(plugins, app, activityPrefix = "")
app.loadComponents(null)
preloadServiceFuture
.thenRun { ForkJoinTask.invokeAll(callAppInitialized(app)) }
.get(40, TimeUnit.SECONDS)
preloadServiceFuture.get(40, TimeUnit.SECONDS)
ForkJoinTask.invokeAll(callAppInitialized(app))
(PersistentFS.getInstance() as PersistentFSImpl).cleanPersistedContents()
}
catch (e: TimeoutException) {
throw RuntimeException("Cannot preload services in 40 seconds: ${ThreadDumper.dumpThreadsToString()}", e)