[modular loader] search for files included in plugin.xml in the plugin libraries when started from sources (RDCT-773)

We have a case with Terminal plugin where plugin.xml includes 'completion-specs.xml' file from a library JAR. When IDE is started from sources, this JAR isn't merged with the main plugin JAR, so we need to use custom PathResolver when loading plugin.xml to be able to load it.

GitOrigin-RevId: 625c8aa0daf224159d17d70160637ff8b0d3f896
This commit is contained in:
Nikolay Chashnikov
2024-02-13 14:36:29 +01:00
committed by intellij-monorepo-bot
parent 9208817161
commit b864b06e51
2 changed files with 36 additions and 35 deletions

View File

@@ -3,14 +3,12 @@ package com.intellij.platform.bootstrap
import com.intellij.ide.plugins.*
import com.intellij.platform.runtime.repository.IncludedRuntimeModule
import java.nio.file.Path
/**
* Implementation of [PathResolver] which can load module descriptors not only from the main plugin JAR file, unlike [PluginXmlPathResolver]
* which always loads them from the JAR file containing plugin.xml file.
*/
internal class ModuleBasedPluginXmlPathResolver(
private val allResourceRoots: List<Path>,
private val includedModules: List<IncludedRuntimeModule>,
private val fallbackResolver: PathResolver,
) : PathResolver {
@@ -21,24 +19,22 @@ internal class ModuleBasedPluginXmlPathResolver(
path: String,
readInto: RawPluginDescriptor?,
): RawPluginDescriptor {
if (allResourceRoots.size > 1) {
// if there are multiple JARs,
// it may happen that module descriptor is located in other JARs (e.g., in case of 'com.intellij.java.frontend' plugin),
// so try loading it from the root of the corresponding module
val moduleName = path.removeSuffix(".xml")
val moduleDescriptor = includedModules.find { it.moduleDescriptor.moduleId.stringId == moduleName }?.moduleDescriptor
if (moduleDescriptor != null) {
val input = moduleDescriptor.readFile(path) ?: error("Cannot resolve $path in $moduleDescriptor")
return readModuleDescriptor(
input = input,
readContext = readContext,
pathResolver = this,
dataLoader = dataLoader,
includeBase = null,
readInto = readInto,
locationSource = path,
)
}
// if there are multiple JARs,
// it may happen that module descriptor is located in other JARs (e.g., in case of 'com.intellij.java.frontend' plugin),
// so try loading it from the root of the corresponding module
val moduleName = path.removeSuffix(".xml")
val moduleDescriptor = includedModules.find { it.moduleDescriptor.moduleId.stringId == moduleName }?.moduleDescriptor
if (moduleDescriptor != null) {
val input = moduleDescriptor.readFile(path) ?: error("Cannot resolve $path in $moduleDescriptor")
return readModuleDescriptor(
input = input,
readContext = readContext,
pathResolver = this,
dataLoader = dataLoader,
includeBase = null,
readInto = readInto,
locationSource = path,
)
}
return fallbackResolver.resolveModuleFile(readContext = readContext, dataLoader = dataLoader, path = path, readInto = readInto)
}

View File

@@ -16,6 +16,7 @@ import kotlinx.coroutines.async
import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.exists
import kotlin.io.path.extension
internal class ModuleBasedProductLoadingStrategy(internal val moduleRepository: RuntimeModuleRepository) : ProductLoadingStrategy() {
@OptIn(ExperimentalStdlibApi::class)
@@ -167,6 +168,13 @@ internal class ModuleBasedProductLoadingStrategy(internal val moduleRepository:
}
val allResourceRoots = includedModules.flatMapTo(LinkedHashSet()) { it.moduleDescriptor.resourceRootPaths }
val requiredLibraries = collectRequiredLibraryModules(pluginModuleGroup)
if (requiredLibraries.isNotEmpty()) {
thisLogger().debug("Additional library modules will be added to classpath of $pluginModuleGroup: $requiredLibraries")
requiredLibraries.flatMapTo(allResourceRoots) { it.resourceRootPaths }
}
val allResourceRootsList = allResourceRoots.toList();
val descriptor = if (Files.isDirectory(mainResourceRoot)) {
loadDescriptorFromDir(
dir = mainResourceRoot,
@@ -174,33 +182,30 @@ internal class ModuleBasedProductLoadingStrategy(internal val moduleRepository:
context = context,
isBundled = true,
pathResolver = ModuleBasedPluginXmlPathResolver(
allResourceRoots = allResourceRoots.toList(),
includedModules = includedModules,
fallbackResolver = PluginXmlPathResolver.DEFAULT_PATH_RESOLVER,
includedModules = includedModules,
fallbackResolver = PluginXmlPathResolver(allResourceRootsList.filter { it.extension == "jar" }, zipFilePool),
)
)
}
else {
val includedModulesRootsList = allResourceRoots.toList()
val defaultResolver = PluginXmlPathResolver(allResourceRootsList, zipFilePool)
val pathResolver =
if (allResourceRootsList.size == 1) {
defaultResolver
}
else {
ModuleBasedPluginXmlPathResolver(includedModules = includedModules, fallbackResolver = defaultResolver)
}
loadDescriptorFromJar(
file = mainResourceRoot,
pathResolver = ModuleBasedPluginXmlPathResolver(
allResourceRoots = includedModulesRootsList,
includedModules = includedModules,
fallbackResolver = PluginXmlPathResolver(includedModulesRootsList, zipFilePool),
),
pathResolver = pathResolver,
parentContext = context,
isBundled = true,
pluginDir = mainResourceRoot.parent.parent,
pool = zipFilePool,
)
}
val requiredLibraries = collectRequiredLibraryModules(pluginModuleGroup)
if (requiredLibraries.isNotEmpty()) {
thisLogger().debug("Additional library modules will be added to classpath of $pluginModuleGroup: $requiredLibraries")
requiredLibraries.flatMapTo(allResourceRoots) { it.resourceRootPaths }
}
descriptor?.jarFiles = allResourceRoots.toList()
descriptor?.jarFiles = allResourceRootsList
return descriptor
}