mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-15 02:59:33 +07:00
IJPL-149476 load product core plugin using pre-built descriptor file
GitOrigin-RevId: 433d5809bf45910e95c0e704d69a6e627ad586c9
This commit is contained in:
committed by
intellij-monorepo-bot
parent
155813717e
commit
9e54d54915
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.intellij.build
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@@ -101,6 +101,7 @@ suspend fun buildCommunityStandaloneJpsBuilder(targetDir: Path,
|
||||
platformLayout = null,
|
||||
isRootDir = false,
|
||||
isCodesignEnabled = false,
|
||||
moduleOutputPatcher = ModuleOutputPatcher(),
|
||||
dryRun = dryRun)
|
||||
|
||||
val targetFile = targetDir.resolve("standalone-jps-$buildNumber.zip")
|
||||
|
||||
@@ -57,9 +57,6 @@ abstract class ProductProperties {
|
||||
*/
|
||||
lateinit var applicationInfoModule: String
|
||||
|
||||
@ApiStatus.Internal
|
||||
var productPluginSourceModuleName: String? = null
|
||||
|
||||
/**
|
||||
* Enables fast activation of a running IDE instance from the launcher
|
||||
* (at the moment, it is only implemented in the native Windows one).
|
||||
|
||||
@@ -59,7 +59,7 @@ fun reorderJar(relativePath: String, file: Path) {
|
||||
|
||||
internal val excludedLibJars: Set<String> = java.util.Set.of(PlatformJarNames.TEST_FRAMEWORK_JAR, "junit.jar")
|
||||
|
||||
fun generateClasspath(homeDir: Path, libDir: Path): List<String> {
|
||||
internal fun generateClasspath(homeDir: Path, libDir: Path): List<String> {
|
||||
spanBuilder("generate classpath")
|
||||
.setAttribute("dir", homeDir.toString())
|
||||
.useWithoutActiveScope { span ->
|
||||
@@ -165,11 +165,23 @@ internal data class PluginBuildDescriptor(
|
||||
@JvmField val moduleNames: List<String>,
|
||||
)
|
||||
|
||||
fun writePluginClassPathHeader(out: DataOutputStream, isJarOnly: Boolean, pluginCount: Int) {
|
||||
internal fun writePluginClassPathHeader(out: DataOutputStream, isJarOnly: Boolean, pluginCount: Int, moduleOutputPatcher: ModuleOutputPatcher, context: BuildContext) {
|
||||
// format version
|
||||
out.write(1)
|
||||
out.write(2)
|
||||
// jarOnly
|
||||
out.write(if (isJarOnly) 1 else 0)
|
||||
|
||||
// main plugin
|
||||
val mainDescriptor = moduleOutputPatcher.getPatchedContent(context.productProperties.applicationInfoModule)
|
||||
.let { it.get("META-INF/plugin.xml") ?: it.get("META-INF/${context.productProperties.platformPrefix}Plugin.xml") }
|
||||
|
||||
val mainPluginDescriptorContent = requireNotNull(mainDescriptor) {
|
||||
"Cannot find core plugin descriptor (module=${context.productProperties.applicationInfoModule})"
|
||||
}
|
||||
out.writeInt(mainPluginDescriptorContent.size)
|
||||
out.write(mainPluginDescriptorContent)
|
||||
|
||||
// bundled plugin metadata
|
||||
out.writeShort(pluginCount)
|
||||
}
|
||||
|
||||
|
||||
@@ -116,6 +116,8 @@ internal suspend fun buildProduct(request: BuildRequest, createProductProperties
|
||||
compileIfNeeded(context)
|
||||
|
||||
coroutineScope {
|
||||
val moduleOutputPatcher = ModuleOutputPatcher()
|
||||
|
||||
val platformLayout = async {
|
||||
createPlatformLayout(pluginsToPublish = emptySet(), context = context)
|
||||
}
|
||||
@@ -136,7 +138,13 @@ internal suspend fun buildProduct(request: BuildRequest, createProductProperties
|
||||
}
|
||||
|
||||
val (platformDistributionEntries, classPath) = spanBuilder("layout platform").useWithScope {
|
||||
layoutPlatform(runDir = runDir, platformLayout = platformLayout.await(), searchableOptionSet = searchableOptionSet, context = context)
|
||||
layoutPlatform(
|
||||
runDir = runDir,
|
||||
platformLayout = platformLayout.await(),
|
||||
searchableOptionSet = searchableOptionSet,
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
context = context,
|
||||
)
|
||||
}
|
||||
|
||||
launch(Dispatchers.IO) {
|
||||
@@ -158,7 +166,6 @@ internal suspend fun buildProduct(request: BuildRequest, createProductProperties
|
||||
}
|
||||
}
|
||||
|
||||
val moduleOutputPatcher = ModuleOutputPatcher()
|
||||
val pluginDistributionEntriesDeferred = async {
|
||||
buildPlugins(
|
||||
request = request,
|
||||
@@ -175,13 +182,14 @@ internal suspend fun buildProduct(request: BuildRequest, createProductProperties
|
||||
launch {
|
||||
val (pluginEntries, additionalEntries) = pluginDistributionEntriesDeferred.await()
|
||||
spanBuilder("generate plugin classpath").useWithScope(Dispatchers.IO) {
|
||||
val mainData = generatePluginClassPath(pluginEntries, moduleOutputPatcher)
|
||||
val mainData = generatePluginClassPath(pluginEntries = pluginEntries, moduleOutputPatcher = moduleOutputPatcher)
|
||||
val additionalData = additionalEntries?.let { generatePluginClassPathFromPrebuiltPluginFiles(it) }
|
||||
|
||||
val byteOut = ByteArrayOutputStream()
|
||||
val out = DataOutputStream(byteOut)
|
||||
val pluginCount = pluginEntries.size + (additionalEntries?.size ?: 0)
|
||||
writePluginClassPathHeader(out = out, isJarOnly = !request.isUnpackedDist, pluginCount = pluginCount)
|
||||
platformDistributionEntriesDeferred.join()
|
||||
writePluginClassPathHeader(out = out, isJarOnly = !request.isUnpackedDist, pluginCount = pluginCount, moduleOutputPatcher = moduleOutputPatcher, context = context)
|
||||
out.write(mainData)
|
||||
additionalData?.let { out.write(it) }
|
||||
out.close()
|
||||
@@ -512,9 +520,10 @@ private suspend fun layoutPlatform(
|
||||
platformLayout: PlatformLayout,
|
||||
searchableOptionSet: SearchableOptionSetDescriptor?,
|
||||
context: BuildContext,
|
||||
moduleOutputPatcher: ModuleOutputPatcher,
|
||||
): Pair<List<DistributionFileEntry>, Set<Path>> {
|
||||
val entries = layoutPlatformDistribution(
|
||||
moduleOutputPatcher = ModuleOutputPatcher(),
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
targetDirectory = runDir,
|
||||
platform = platformLayout,
|
||||
searchableOptionSet = searchableOptionSet,
|
||||
|
||||
@@ -48,7 +48,7 @@ internal fun buildHelpPlugin(pluginVersion: String, context: BuildContext): Plug
|
||||
patcher.patchModuleOutput(moduleName = BUILT_IN_HELP_MODULE_NAME,
|
||||
path = "META-INF/plugin.xml",
|
||||
content = pluginXml(buildContext, pluginVersion),
|
||||
overwrite = true)
|
||||
overwrite = PatchOverwriteMode.TRUE)
|
||||
}
|
||||
LUCENE_LIBRARIES.forEach { spec.withProjectLibrary(it) }
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ internal suspend fun buildDistribution(
|
||||
val traceContext = Context.current().asContextElement()
|
||||
val entries = coroutineScope {
|
||||
// must be completed before plugin building
|
||||
val searchableOptionSetDescriptor = context.executeStep(spanBuilder("build searchable options index"), BuildOptions.SEARCHABLE_OPTIONS_INDEX_STEP) {
|
||||
val searchableOptionSet = context.executeStep(spanBuilder("build searchable options index"), BuildOptions.SEARCHABLE_OPTIONS_INDEX_STEP) {
|
||||
buildSearchableOptions(productRunner = productRunner, context = context)
|
||||
}
|
||||
|
||||
@@ -85,24 +85,14 @@ internal suspend fun buildDistribution(
|
||||
val moduleOutputPatcher = ModuleOutputPatcher()
|
||||
val buildPlatformJob: Deferred<List<DistributionFileEntry>> = async(traceContext) {
|
||||
spanBuilder("build platform lib").useWithScope {
|
||||
val result = buildLib(
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
platform = state.platform,
|
||||
searchableOptionSetDescriptor = searchableOptionSetDescriptor,
|
||||
context = context
|
||||
)
|
||||
val result = buildLib(moduleOutputPatcher = moduleOutputPatcher, platform = state.platform, searchableOptionSetDescriptor = searchableOptionSet, context = context)
|
||||
if (!isUpdateFromSources && context.productProperties.scrambleMainJar) {
|
||||
scramble(state.platform, context)
|
||||
}
|
||||
|
||||
val distAllDir = context.paths.distAllDir
|
||||
val libDir = distAllDir.resolve("lib")
|
||||
context.bootClassPathJarNames = if (context.useModularLoader) {
|
||||
listOf(PLATFORM_LOADER_JAR)
|
||||
}
|
||||
else {
|
||||
generateClasspath(homeDir = distAllDir, libDir = libDir)
|
||||
}
|
||||
context.bootClassPathJarNames = if (context.useModularLoader) listOf(PLATFORM_LOADER_JAR) else generateClasspath(homeDir = distAllDir, libDir = libDir)
|
||||
result
|
||||
}
|
||||
}
|
||||
@@ -113,7 +103,7 @@ internal suspend fun buildDistribution(
|
||||
compressPluginArchive = !isUpdateFromSources && context.options.compressZipFiles,
|
||||
buildPlatformLibJob = buildPlatformJob,
|
||||
state = state,
|
||||
searchableOptionSet = searchableOptionSetDescriptor,
|
||||
searchableOptionSet = searchableOptionSet,
|
||||
context = context,
|
||||
)
|
||||
}
|
||||
@@ -123,7 +113,8 @@ internal suspend fun buildDistribution(
|
||||
pluginLayouts = pluginLayouts,
|
||||
isUpdateFromSources = isUpdateFromSources,
|
||||
buildPlatformJob = buildPlatformJob,
|
||||
searchableOptionSetDescriptor = searchableOptionSetDescriptor,
|
||||
searchableOptionSetDescriptor = searchableOptionSet,
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
context = context,
|
||||
)
|
||||
|
||||
@@ -162,9 +153,9 @@ private suspend fun buildBundledPluginsForAllPlatforms(
|
||||
isUpdateFromSources: Boolean,
|
||||
buildPlatformJob: Deferred<List<DistributionFileEntry>>,
|
||||
searchableOptionSetDescriptor: SearchableOptionSetDescriptor?,
|
||||
moduleOutputPatcher: ModuleOutputPatcher,
|
||||
context: BuildContext,
|
||||
): List<DistributionFileEntry> {
|
||||
val moduleOutputPatcher = ModuleOutputPatcher()
|
||||
return coroutineScope {
|
||||
val commonDeferred = async {
|
||||
doBuildBundledPlugins(
|
||||
@@ -182,7 +173,7 @@ private suspend fun buildBundledPluginsForAllPlatforms(
|
||||
copyAdditionalPlugins(context = context, pluginDir = context.paths.distAllDir.resolve(PLUGINS_DIRECTORY))
|
||||
}
|
||||
|
||||
val pluginDirs = getPluginDirs(context, isUpdateFromSources)
|
||||
val pluginDirs = getPluginDirs(context = context, isUpdateFromSources = isUpdateFromSources)
|
||||
val specificDeferred = async {
|
||||
buildOsSpecificBundledPlugins(
|
||||
state = state,
|
||||
@@ -190,38 +181,55 @@ private suspend fun buildBundledPluginsForAllPlatforms(
|
||||
isUpdateFromSources = isUpdateFromSources,
|
||||
buildPlatformJob = buildPlatformJob,
|
||||
context = context,
|
||||
searchableOptionSetDescriptor = searchableOptionSetDescriptor,
|
||||
searchableOptionSet = searchableOptionSetDescriptor,
|
||||
pluginDirs = pluginDirs,
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
)
|
||||
}
|
||||
|
||||
val common = commonDeferred.await()
|
||||
val commonClassPath = generatePluginClassPath(common, moduleOutputPatcher = moduleOutputPatcher)
|
||||
|
||||
val additional = additionalDeferred.await()
|
||||
val additionalClassPath = additional?.let { generatePluginClassPathFromPrebuiltPluginFiles(it) }
|
||||
|
||||
val specific = specificDeferred.await()
|
||||
for ((supportedDist) in pluginDirs) {
|
||||
val specificList = specific[supportedDist]
|
||||
val specificClasspath = specificList?.let { generatePluginClassPath(pluginEntries = it, moduleOutputPatcher = moduleOutputPatcher) }
|
||||
|
||||
val byteOut = ByteArrayOutputStream()
|
||||
val out = DataOutputStream(byteOut)
|
||||
val pluginCount = common.size + (additional?.size ?: 0) + (specificList?.size ?: 0)
|
||||
writePluginClassPathHeader(out, isJarOnly = true, pluginCount)
|
||||
out.write(commonClassPath)
|
||||
additionalClassPath?.let { out.write(it) }
|
||||
specificClasspath?.let { out.write(it) }
|
||||
out.close()
|
||||
|
||||
context.addDistFile(DistFile(relativePath = PLUGIN_CLASSPATH, content = InMemoryDistFileContent(byteOut.toByteArray()), os = supportedDist.os, arch = supportedDist.arch))
|
||||
}
|
||||
|
||||
buildPlatformJob.join()
|
||||
writePluginInfo(
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
pluginDirs = pluginDirs,
|
||||
common = common,
|
||||
specific = specific,
|
||||
additional = additionalDeferred.await(),
|
||||
context = context,
|
||||
)
|
||||
listOf(common, specific.values.flatten())
|
||||
}.flatMap { list -> list.flatMap { it.second } }
|
||||
}
|
||||
|
||||
private fun writePluginInfo(
|
||||
moduleOutputPatcher: ModuleOutputPatcher,
|
||||
pluginDirs: List<Pair<SupportedDistribution, Path>>,
|
||||
common: List<Pair<PluginBuildDescriptor, List<DistributionFileEntry>>>,
|
||||
specific: Map<SupportedDistribution, List<Pair<PluginBuildDescriptor, List<DistributionFileEntry>>>>,
|
||||
additional: List<Pair<Path, List<Path>>>?,
|
||||
context: BuildContext,
|
||||
) {
|
||||
val commonClassPath = generatePluginClassPath(pluginEntries = common, moduleOutputPatcher = moduleOutputPatcher)
|
||||
val additionalClassPath = additional?.let { generatePluginClassPathFromPrebuiltPluginFiles(it) }
|
||||
|
||||
for ((supportedDist) in pluginDirs) {
|
||||
val specificList = specific.get(supportedDist)
|
||||
val specificClasspath = specificList?.let { generatePluginClassPath(pluginEntries = it, moduleOutputPatcher = moduleOutputPatcher) }
|
||||
|
||||
val byteOut = ByteArrayOutputStream()
|
||||
val out = DataOutputStream(byteOut)
|
||||
val pluginCount = common.size + (additional?.size ?: 0) + (specificList?.size ?: 0)
|
||||
writePluginClassPathHeader(out = out, isJarOnly = true, pluginCount = pluginCount, moduleOutputPatcher = moduleOutputPatcher, context = context)
|
||||
out.write(commonClassPath)
|
||||
additionalClassPath?.let { out.write(it) }
|
||||
specificClasspath?.let { out.write(it) }
|
||||
out.close()
|
||||
|
||||
context.addDistFile(DistFile(relativePath = PLUGIN_CLASSPATH, content = InMemoryDistFileContent(byteOut.toByteArray()), os = supportedDist.os, arch = supportedDist.arch))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates module structure to be ensure all module dependencies are included.
|
||||
*/
|
||||
@@ -231,15 +239,16 @@ fun validateModuleStructure(platform: PlatformLayout, context: BuildContext) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPluginDirs(context: BuildContext, isUpdateFromSources: Boolean): List<Pair<SupportedDistribution, Path>> =
|
||||
private fun getPluginDirs(context: BuildContext, isUpdateFromSources: Boolean): List<Pair<SupportedDistribution, Path>> {
|
||||
if (isUpdateFromSources) {
|
||||
listOf(SupportedDistribution(OsFamily.currentOs, JvmArchitecture.currentJvmArch) to context.paths.distAllDir.resolve(PLUGINS_DIRECTORY))
|
||||
return listOf(SupportedDistribution(OsFamily.currentOs, JvmArchitecture.currentJvmArch) to context.paths.distAllDir.resolve(PLUGINS_DIRECTORY))
|
||||
}
|
||||
else {
|
||||
SUPPORTED_DISTRIBUTIONS.map {
|
||||
it to getOsAndArchSpecificDistDirectory(it.os, it.arch, context).resolve(PLUGINS_DIRECTORY)
|
||||
return SUPPORTED_DISTRIBUTIONS.map {
|
||||
it to getOsAndArchSpecificDistDirectory(osFamily = it.os, arch = it.arch, context = context).resolve(PLUGINS_DIRECTORY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun buildBundledPlugins(
|
||||
state: DistributionBuilderState,
|
||||
@@ -308,8 +317,9 @@ private suspend fun buildOsSpecificBundledPlugins(
|
||||
isUpdateFromSources: Boolean,
|
||||
buildPlatformJob: Job?,
|
||||
context: BuildContext,
|
||||
searchableOptionSetDescriptor: SearchableOptionSetDescriptor?,
|
||||
searchableOptionSet: SearchableOptionSetDescriptor?,
|
||||
pluginDirs: List<Pair<SupportedDistribution, Path>>,
|
||||
moduleOutputPatcher: ModuleOutputPatcher,
|
||||
): Map<SupportedDistribution, List<Pair<PluginBuildDescriptor, List<DistributionFileEntry>>>> {
|
||||
return spanBuilder("build os-specific bundled plugins")
|
||||
.setAttribute("isUpdateFromSources", isUpdateFromSources)
|
||||
@@ -328,28 +338,27 @@ private suspend fun buildOsSpecificBundledPlugins(
|
||||
return@mapNotNull null
|
||||
}
|
||||
|
||||
async(Dispatchers.IO) {
|
||||
dist to async(Dispatchers.IO) {
|
||||
spanBuilder("build bundled plugins")
|
||||
.setAttribute("os", os.osName)
|
||||
.setAttribute("arch", arch.name)
|
||||
.setAttribute("count", osSpecificPlugins.size.toLong())
|
||||
.setAttribute("outDir", targetDir.toString())
|
||||
.useWithScope {
|
||||
dist to buildPlugins(
|
||||
moduleOutputPatcher = ModuleOutputPatcher(),
|
||||
buildPlugins(
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
plugins = osSpecificPlugins,
|
||||
targetDir = targetDir,
|
||||
state = state,
|
||||
context = context,
|
||||
buildPlatformJob = buildPlatformJob,
|
||||
searchableOptionSet = searchableOptionSetDescriptor,
|
||||
searchableOptionSet = searchableOptionSet,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.map { deferred -> deferred.getCompleted() }
|
||||
.associateBy(keySelector = { it.first }, valueTransform = { it.second })
|
||||
.associateBy(keySelector = { it.first }, valueTransform = { it.second.getCompleted() })
|
||||
}
|
||||
|
||||
suspend fun copyAdditionalPlugins(context: BuildContext, pluginDir: Path): List<Pair<Path, List<Path>>>? {
|
||||
@@ -925,6 +934,9 @@ fun satisfiesBundlingRequirements(plugin: PluginLayout, osFamily: OsFamily?, arc
|
||||
}
|
||||
|
||||
val bundlingRestrictions = plugin.bundlingRestrictions
|
||||
if (bundlingRestrictions == PluginBundlingRestrictions.MARKETPLACE) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (context.options.useReleaseCycleRelatedBundlingRestrictionsForContentReport) {
|
||||
val isNightly = context.options.isNightlyBuild
|
||||
@@ -940,10 +952,6 @@ fun satisfiesBundlingRequirements(plugin: PluginLayout, osFamily: OsFamily?, arc
|
||||
}
|
||||
}
|
||||
|
||||
if (bundlingRestrictions == PluginBundlingRestrictions.MARKETPLACE) {
|
||||
return false
|
||||
}
|
||||
|
||||
return when {
|
||||
osFamily == null && bundlingRestrictions.supportedOs != OsFamily.ALL -> false
|
||||
osFamily != null && (bundlingRestrictions.supportedOs == OsFamily.ALL || !bundlingRestrictions.supportedOs.contains(osFamily)) -> false
|
||||
|
||||
@@ -136,7 +136,7 @@ class JarPackager private constructor(
|
||||
isCodesignEnabled: Boolean = true,
|
||||
layout: BaseLayout?,
|
||||
platformLayout: PlatformLayout?,
|
||||
moduleOutputPatcher: ModuleOutputPatcher = ModuleOutputPatcher(),
|
||||
moduleOutputPatcher: ModuleOutputPatcher,
|
||||
dryRun: Boolean,
|
||||
searchableOptionSet: SearchableOptionSetDescriptor? = null,
|
||||
context: BuildContext,
|
||||
@@ -343,7 +343,7 @@ class JarPackager private constructor(
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (moduleName == (context.productProperties.productPluginSourceModuleName ?: context.productProperties.applicationInfoModule)) {
|
||||
else if (moduleName == context.productProperties.applicationInfoModule) {
|
||||
moduleSources.addAll(searchableOptionSet.createSourceByPlugin("com.intellij"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
@file:Suppress("ReplaceGetOrSet", "LiftReturnOrAssignment")
|
||||
@file:Suppress("ReplaceGetOrSet", "LiftReturnOrAssignment", "ReplacePutWithAssignment")
|
||||
|
||||
package org.jetbrains.intellij.build.impl
|
||||
|
||||
@@ -13,17 +13,27 @@ import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.CopyOnWriteArrayList
|
||||
|
||||
enum class PatchOverwriteMode {
|
||||
TRUE,
|
||||
FALSE,
|
||||
IF_EQUAL,
|
||||
}
|
||||
|
||||
class ModuleOutputPatcher {
|
||||
private val patchDirs = ConcurrentHashMap<String, CopyOnWriteArrayList<Path>>()
|
||||
private val patches = ConcurrentHashMap<String, MutableMap<String, ByteArray>>()
|
||||
|
||||
fun patchModuleOutput(moduleName: String, path: String, content: String, overwrite: Boolean = false) {
|
||||
fun patchModuleOutput(moduleName: String, path: String, content: String, overwrite: PatchOverwriteMode = PatchOverwriteMode.FALSE) {
|
||||
patchModuleOutput(moduleName = moduleName, path = path, content = content.toByteArray(StandardCharsets.UTF_8), overwrite = overwrite)
|
||||
}
|
||||
|
||||
fun patchModuleOutput(moduleName: String, path: String, content: ByteArray, overwrite: Boolean = false) {
|
||||
fun patchModuleOutput(moduleName: String, path: String, content: ByteArray, overwrite: Boolean) {
|
||||
patchModuleOutput(moduleName = moduleName, path = path, content = content, overwrite = if (overwrite) PatchOverwriteMode.TRUE else PatchOverwriteMode.FALSE)
|
||||
}
|
||||
|
||||
fun patchModuleOutput(moduleName: String, path: String, content: ByteArray, overwrite: PatchOverwriteMode = PatchOverwriteMode.FALSE) {
|
||||
val pathToData = patches.computeIfAbsent(moduleName) { Collections.synchronizedMap(LinkedHashMap()) }
|
||||
if (overwrite) {
|
||||
if (overwrite == PatchOverwriteMode.TRUE) {
|
||||
val overwritten = pathToData.put(path, content) != null
|
||||
Span.current().addEvent("patch module output", Attributes.of(
|
||||
AttributeKey.stringKey("module"), moduleName,
|
||||
@@ -36,12 +46,16 @@ class ModuleOutputPatcher {
|
||||
val existing = pathToData.putIfAbsent(path, content)
|
||||
val span = Span.current()
|
||||
if (existing != null) {
|
||||
span.addEvent("failed to patch because path is duplicated", Attributes.of(
|
||||
AttributeKey.stringKey("path"), path,
|
||||
AttributeKey.stringKey("oldContent"), byteArrayToTraceStringValue(existing),
|
||||
AttributeKey.stringKey("newContent"), byteArrayToTraceStringValue(content),
|
||||
))
|
||||
error("Patched directory $path is already added for module $moduleName")
|
||||
if (overwrite != PatchOverwriteMode.IF_EQUAL && !existing.contentEquals(content)) {
|
||||
span.addEvent("failed to patch because path is duplicated", Attributes.of(
|
||||
AttributeKey.stringKey("path"), path,
|
||||
AttributeKey.stringKey("oldContent"), byteArrayToTraceStringValue(existing),
|
||||
AttributeKey.stringKey("newContent"), byteArrayToTraceStringValue(content),
|
||||
))
|
||||
error("Patched directory $path is already added for module $moduleName")
|
||||
}
|
||||
|
||||
pathToData.put(path, content)
|
||||
}
|
||||
|
||||
span.addEvent("patch module output", Attributes.of(
|
||||
|
||||
@@ -282,7 +282,6 @@ internal suspend fun createPlatformLayout(addPlatformCoverage: Boolean, projectL
|
||||
context = context,
|
||||
validateImplicitPlatformModule = false,
|
||||
).asSequence().map { it.first } + explicitModuleNames).toList(),
|
||||
productPluginSourceModuleName = context.productProperties.productPluginSourceModuleName ?: context.productProperties.applicationInfoModule,
|
||||
)
|
||||
|
||||
val implicit = computeImplicitRequiredModules(
|
||||
@@ -490,12 +489,12 @@ private fun computeTransitive(
|
||||
// result _must be_ consistent, do not use Set.of or HashSet here
|
||||
private suspend fun processAndGetProductPluginContentModules(
|
||||
context: BuildContext,
|
||||
productPluginSourceModuleName: String,
|
||||
layout: PlatformLayout,
|
||||
includedPlatformModulesPartialList: List<String>,
|
||||
): Set<ModuleItem> {
|
||||
val xIncludePathResolver = createXIncludePathResolver(includedPlatformModulesPartialList, context)
|
||||
return withContext(Dispatchers.IO) {
|
||||
val productPluginSourceModuleName = context.productProperties.applicationInfoModule
|
||||
val file = requireNotNull(
|
||||
context.findFileInModuleSources(productPluginSourceModuleName, "META-INF/plugin.xml")
|
||||
?: context.findFileInModuleSources(moduleName = productPluginSourceModuleName, relativePath = "META-INF/${context.productProperties.platformPrefix}Plugin.xml")
|
||||
|
||||
@@ -88,7 +88,8 @@ internal fun patchPluginXml(
|
||||
catch (e: Throwable) {
|
||||
throw RuntimeException("Could not patch descriptor (module=${plugin.mainModule})", e)
|
||||
}
|
||||
moduleOutputPatcher.patchModuleOutput(moduleName = plugin.mainModule, path = "META-INF/plugin.xml", content = content)
|
||||
// os-specific plugins being built several times - we expect that plugin.xml must be the same
|
||||
moduleOutputPatcher.patchModuleOutput(moduleName = plugin.mainModule, path = "META-INF/plugin.xml", content = content, overwrite = PatchOverwriteMode.IF_EQUAL)
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
|
||||
@@ -16,13 +16,7 @@ class ClassPathXmlPathResolver(
|
||||
override val isFlat: Boolean
|
||||
get() = true
|
||||
|
||||
override fun loadXIncludeReference(
|
||||
readInto: RawPluginDescriptor,
|
||||
readContext: ReadModuleContext,
|
||||
dataLoader: DataLoader,
|
||||
base: String?,
|
||||
relativePath: String,
|
||||
): Boolean {
|
||||
override fun loadXIncludeReference(readInto: RawPluginDescriptor, readContext: ReadModuleContext, dataLoader: DataLoader, base: String?, relativePath: String): Boolean {
|
||||
val path = PluginXmlPathResolver.toLoadPath(relativePath, base)
|
||||
val reader: XMLStreamReader2
|
||||
if (classLoader is UrlClassLoader) {
|
||||
@@ -65,19 +59,22 @@ class ClassPathXmlPathResolver(
|
||||
if (resource == null) {
|
||||
val log = logger<ClassPathXmlPathResolver>()
|
||||
val moduleName = path.removeSuffix(".xml")
|
||||
if (isRunningFromSources && path.startsWith("intellij.") && dataLoader.emptyDescriptorIfCannotResolve) {
|
||||
log.trace("Cannot resolve $path (dataLoader=$dataLoader, classLoader=$classLoader). ")
|
||||
val descriptor = RawPluginDescriptor()
|
||||
descriptor.`package` = "unresolved.$moduleName"
|
||||
return descriptor
|
||||
when {
|
||||
isRunningFromSources && path.startsWith("intellij.") && dataLoader.emptyDescriptorIfCannotResolve -> {
|
||||
log.trace("Cannot resolve $path (dataLoader=$dataLoader, classLoader=$classLoader). ")
|
||||
val descriptor = RawPluginDescriptor()
|
||||
descriptor.`package` = "unresolved.$moduleName"
|
||||
return descriptor
|
||||
}
|
||||
ProductLoadingStrategy.strategy.isOptionalProductModule(moduleName) -> {
|
||||
// this check won't be needed when we are able to load optional modules directly from product-modules.xml
|
||||
log.debug { "Skip module '$path' since its descriptor cannot be found and it's optional" }
|
||||
return RawPluginDescriptor().apply { `package` = "unresolved.$moduleName" }
|
||||
}
|
||||
else -> {
|
||||
throw RuntimeException("Cannot resolve $path (dataLoader=$dataLoader, classLoader=$classLoader)")
|
||||
}
|
||||
}
|
||||
if (ProductLoadingStrategy.strategy.isOptionalProductModule(moduleName)) {
|
||||
// this check won't be needed when we are able to load optional modules directly from product-modules.xml
|
||||
log.debug { "Skip module '$path' since its descriptor cannot be found and it's optional" }
|
||||
return RawPluginDescriptor().apply { `package` = "unresolved.$moduleName" }
|
||||
}
|
||||
|
||||
throw RuntimeException("Cannot resolve $path (dataLoader=$dataLoader, classLoader=$classLoader)")
|
||||
}
|
||||
|
||||
return readModuleDescriptor(
|
||||
|
||||
@@ -111,7 +111,7 @@ fun loadDescriptorFromDir(
|
||||
useCoreClassLoader = useCoreClassLoader,
|
||||
)
|
||||
context.debugData?.recordDescriptorPath(descriptor = descriptor, rawPluginDescriptor = raw, path = descriptorRelativePath)
|
||||
initMainDescriptorByRaw(descriptor = descriptor, raw = raw, pathResolver = pathResolver, context = context, pluginDir = pluginDir ?: dir, dataLoader = dataLoader)
|
||||
initMainDescriptorByRaw(descriptor = descriptor, raw = raw, pathResolver = pathResolver, context = context, pluginDir = pluginDir ?: dir, dataLoader = dataLoader)
|
||||
descriptor.jarFiles = Collections.singletonList(dir)
|
||||
return descriptor
|
||||
}
|
||||
@@ -575,46 +575,71 @@ internal fun CoroutineScope.loadPluginDescriptorsImpl(
|
||||
else {
|
||||
val effectiveBundledPluginDir = bundledPluginDir ?: Paths.get(PathManager.getPreInstalledPluginsPath())
|
||||
val data = try {
|
||||
Files.readAllBytes(effectiveBundledPluginDir.resolve("plugin-classpath.txt"))
|
||||
// use only if the format is supported (first byte it is a version)
|
||||
Files.readAllBytes(effectiveBundledPluginDir.resolve("plugin-classpath.txt")).takeIf { it[0] == 2.toByte() }
|
||||
}
|
||||
catch (ignored: NoSuchFileException) {
|
||||
null
|
||||
}
|
||||
|
||||
result.addAll(loadCoreModules(
|
||||
context = context,
|
||||
platformPrefix = platformPrefix,
|
||||
isUnitTestMode = false,
|
||||
isInDevServerMode = AppMode.isDevServer(),
|
||||
isRunningFromSources = isRunningFromSources,
|
||||
classLoader = mainClassLoader,
|
||||
pool = zipFilePool,
|
||||
result = result,
|
||||
))
|
||||
|
||||
result.addAll(loadDescriptorsFromDir(dir = customPluginDir, context = context, isBundled = false, pool = zipFilePool))
|
||||
|
||||
if (data == null || data[0] != 1.toByte()) {
|
||||
if (data == null) {
|
||||
result.addAll(loadCoreModules(
|
||||
context = context,
|
||||
platformPrefix = platformPrefix,
|
||||
isUnitTestMode = false,
|
||||
isInDevServerMode = AppMode.isDevServer(),
|
||||
isRunningFromSources = isRunningFromSources,
|
||||
classLoader = mainClassLoader,
|
||||
pool = zipFilePool,
|
||||
result = result,
|
||||
))
|
||||
result.addAll(loadDescriptorsFromDir(dir = customPluginDir, context = context, isBundled = false, pool = zipFilePool))
|
||||
result.addAll(loadDescriptorsFromDir(dir = effectiveBundledPluginDir, context = context, isBundled = true, pool = zipFilePool))
|
||||
}
|
||||
else {
|
||||
result.addAll(loadFromPluginClasspathDescriptor(data = data, context = context, zipFilePool = zipFilePool, bundledPluginDir = effectiveBundledPluginDir, scope = this))
|
||||
val byteInput = ByteArrayInputStream(data, 2, data.size)
|
||||
val input = DataInputStream(byteInput)
|
||||
val descriptorSize = input.readInt()
|
||||
val descriptorStart = data.size - byteInput.available()
|
||||
input.skipBytes(descriptorSize)
|
||||
result.add(async {
|
||||
loadCoreProductPlugin(
|
||||
path = PluginManagerCore.PLUGIN_XML_PATH,
|
||||
context = context,
|
||||
pathResolver = ClassPathXmlPathResolver(classLoader = mainClassLoader, isRunningFromSources = false),
|
||||
useCoreClassLoader = platformPrefix.startsWith("CodeServer") || java.lang.Boolean.getBoolean("idea.force.use.core.classloader"),
|
||||
reader = createXmlStreamReader(data, descriptorStart, descriptorSize),
|
||||
)
|
||||
})
|
||||
|
||||
result.addAll(loadDescriptorsFromDir(dir = customPluginDir, context = context, isBundled = false, pool = zipFilePool))
|
||||
|
||||
loadFromPluginClasspathDescriptor(
|
||||
input = input,
|
||||
jarOnly = data[1] == 1.toByte(),
|
||||
context = context,
|
||||
zipFilePool = zipFilePool,
|
||||
bundledPluginDir = effectiveBundledPluginDir,
|
||||
scope = this,
|
||||
result = result,
|
||||
)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
private fun loadFromPluginClasspathDescriptor(
|
||||
data: ByteArray,
|
||||
input: DataInputStream,
|
||||
jarOnly: Boolean,
|
||||
context: DescriptorListLoadingContext,
|
||||
zipFilePool: ZipFilePool,
|
||||
bundledPluginDir: Path,
|
||||
scope: CoroutineScope,
|
||||
): Array<Deferred<IdeaPluginDescriptorImpl?>> {
|
||||
val jarOnly = data[1] == 1.toByte()
|
||||
val input = DataInputStream(ByteArrayInputStream(data, 2, data.size))
|
||||
result: ArrayList<Deferred<IdeaPluginDescriptorImpl?>>,
|
||||
) {
|
||||
val pluginCount = input.readUnsignedShort()
|
||||
return Array(pluginCount) {
|
||||
result.ensureCapacity(result.size + pluginCount)
|
||||
repeat(pluginCount) {
|
||||
val fileCount = input.readUnsignedShort()
|
||||
|
||||
val pluginDir = bundledPluginDir.resolve(input.readUTF())
|
||||
@@ -629,7 +654,7 @@ private fun loadFromPluginClasspathDescriptor(
|
||||
FileItem(file = file, path = path)
|
||||
}
|
||||
|
||||
scope.async {
|
||||
result.add(scope.async {
|
||||
try {
|
||||
loadPluginDescriptor(
|
||||
fileItems = fileItems,
|
||||
@@ -647,7 +672,7 @@ private fun loadFromPluginClasspathDescriptor(
|
||||
PluginManagerCore.logger.warn("Cannot load plugin descriptor, files:\n ${fileItems.joinToString(separator = "\n ")}", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -791,7 +816,17 @@ private fun CoroutineScope.loadCoreModules(
|
||||
): List<Deferred<IdeaPluginDescriptorImpl?>> {
|
||||
val pathResolver = ClassPathXmlPathResolver(classLoader = classLoader, isRunningFromSources = isRunningFromSources && !isInDevServerMode)
|
||||
val useCoreClassLoader = pathResolver.isRunningFromSources || platformPrefix.startsWith("CodeServer") || java.lang.Boolean.getBoolean("idea.force.use.core.classloader")
|
||||
if (loadCorePlugin(platformPrefix, isInDevServerMode, isUnitTestMode, isRunningFromSources, context, pathResolver, useCoreClassLoader, classLoader, result)) {
|
||||
if (loadCorePlugin(
|
||||
platformPrefix = platformPrefix,
|
||||
isInDevServerMode = isInDevServerMode,
|
||||
isUnitTestMode = isUnitTestMode,
|
||||
isRunningFromSources = isRunningFromSources,
|
||||
context = context,
|
||||
pathResolver = pathResolver,
|
||||
useCoreClassLoader = useCoreClassLoader,
|
||||
classLoader = classLoader,
|
||||
result = result,
|
||||
)) {
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -887,7 +922,7 @@ private fun loadCoreProductPlugin(
|
||||
override fun toString() = "product classpath"
|
||||
}
|
||||
|
||||
val raw = readModuleDescriptor(reader = reader, readContext = context, pathResolver = pathResolver, dataLoader = dataLoader, includeBase = null, readInto = null)
|
||||
val raw = readModuleDescriptor(reader = reader, readContext = context, pathResolver = pathResolver, dataLoader = dataLoader)
|
||||
val libDir = Paths.get(PathManager.getLibPath())
|
||||
val descriptor = IdeaPluginDescriptorImpl(raw = raw, path = libDir, isBundled = true, id = null, moduleName = null, useCoreClassLoader = useCoreClassLoader)
|
||||
context.debugData?.recordDescriptorPath(descriptor = descriptor, rawPluginDescriptor = raw, path = path)
|
||||
@@ -926,18 +961,13 @@ private fun loadModuleDescriptors(
|
||||
pathResolver = pathResolver,
|
||||
dataLoader = dataLoader,
|
||||
containerDescriptor = descriptor,
|
||||
)) {
|
||||
)) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
module.descriptor = descriptor.createSub(
|
||||
raw = pathResolver.resolveModuleFile(
|
||||
readContext = context,
|
||||
dataLoader = dataLoader,
|
||||
path = subDescriptorFile,
|
||||
readInto = null,
|
||||
),
|
||||
raw = pathResolver.resolveModuleFile(readContext = context, dataLoader = dataLoader, path = subDescriptorFile, readInto = null),
|
||||
descriptorPath = subDescriptorFile,
|
||||
context = context,
|
||||
moduleName = moduleName,
|
||||
@@ -1075,8 +1105,8 @@ fun loadDescriptorsFromOtherIde(
|
||||
bundledPluginDir = bundledPluginDir,
|
||||
zipFilePool = ZipFilePool.POOL ?: NonShareableJavaZipFilePool(),
|
||||
mainClassLoader = DescriptorListLoadingContext::class.java.classLoader,
|
||||
isRunningFromSources = false,
|
||||
isUnitTestMode = false,
|
||||
isRunningFromSources = PluginManagerCore.isRunningFromSources(),
|
||||
isUnitTestMode = PluginManagerCore.isUnitTestMode,
|
||||
)
|
||||
}, isMainProcess()),
|
||||
overrideUseIfCompatible = false,
|
||||
|
||||
@@ -23,7 +23,6 @@ import com.intellij.openapi.actionSystem.impl.ActionManagerImpl
|
||||
import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.application.ModernApplicationStarter
|
||||
import com.intellij.openapi.components.serviceAsync
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.extensions.PluginDescriptor
|
||||
import com.intellij.openapi.extensions.PluginId
|
||||
import com.intellij.openapi.keymap.impl.ui.KeymapPanel
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.fasterxml.aalto.`in`.ReaderConfig
|
||||
import com.fasterxml.aalto.stax.StreamReaderImpl
|
||||
import org.codehaus.stax2.XMLInputFactory2
|
||||
import org.codehaus.stax2.XMLStreamReader2
|
||||
import org.jetbrains.annotations.ApiStatus.Internal
|
||||
import java.io.InputStream
|
||||
import java.io.Reader
|
||||
import javax.xml.stream.XMLInputFactory
|
||||
@@ -43,6 +44,12 @@ fun createXmlStreamReader(bytes: ByteArray): XMLStreamReader2 {
|
||||
return StreamReaderImpl.construct(ByteSourceBootstrapper.construct(readerConfig, bytes, 0, bytes.size))
|
||||
}
|
||||
|
||||
@Internal
|
||||
fun createXmlStreamReader(bytes: ByteArray, start: Int, size: Int): XMLStreamReader2 {
|
||||
val readerConfig = configWithCoalescing.createNonShared(null, null, "UTF-8")
|
||||
return StreamReaderImpl.construct(ByteSourceBootstrapper.construct(readerConfig, bytes, start, size))
|
||||
}
|
||||
|
||||
@Throws(XMLStreamException::class)
|
||||
fun createNonCoalescingXmlStreamReader(input: InputStream, locationSource: String?): XMLStreamReader2 {
|
||||
return StreamReaderImpl.construct(ByteSourceBootstrapper.construct(config.createNonShared(null, locationSource, "UTF-8"), input))
|
||||
|
||||
Reference in New Issue
Block a user