mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IJPL-217668 convert structuralsearch.xml to product module
GitOrigin-RevId: 2d2759d61b68f84690eab827fa4642dde3c67e28
This commit is contained in:
committed by
intellij-monorepo-bot
parent
5f36969dc8
commit
4252fbae15
@@ -65,10 +65,6 @@ open class IdeaCommunityProperties(private val communityHomeDir: Path) : JetBrai
|
||||
CommunityRepositoryModules.groovyPlugin(),
|
||||
)
|
||||
|
||||
productLayout.addPlatformSpec { layout, _ ->
|
||||
layout.withModule("intellij.platform.structuralSearch")
|
||||
}
|
||||
|
||||
productLayout.skipUnresolvedContentModules = true
|
||||
|
||||
mavenArtifacts.forIdeModules = true
|
||||
|
||||
@@ -25,9 +25,7 @@
|
||||
<xi:fallback/>
|
||||
</xi:include>
|
||||
|
||||
<xi:include href="/META-INF/structuralsearch.xml">
|
||||
<xi:fallback/>
|
||||
</xi:include>
|
||||
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<applicationService serviceInterface="com.intellij.openapi.application.IdeUrlTrackingParametersProvider"
|
||||
|
||||
@@ -12,16 +12,24 @@ Each module set is defined as a Kotlin function returning a `ModuleSet` object.
|
||||
|
||||
### Generating XML Files
|
||||
|
||||
To regenerate XML files from Kotlin code, run:
|
||||
```bash
|
||||
# For all products (community + ultimate)
|
||||
UltimateModuleSets.main()
|
||||
To regenerate XML files from Kotlin code:
|
||||
|
||||
# For community products only
|
||||
CommunityModuleSets.main()
|
||||
**Using JetBrains MCP (Recommended):**
|
||||
```kotlin
|
||||
mcp__jetbrains__execute_run_configuration(configurationName="Generate Product Layouts")
|
||||
```
|
||||
|
||||
Or use the IDE's "Generate Product Layouts" run configuration.
|
||||
**Using Gradle:**
|
||||
```bash
|
||||
# For all products (community + ultimate)
|
||||
./gradlew :platform.buildScripts:runIde -PmainClass=com.intellij.platform.commercial.buildScripts.productLayout.UltimateModuleSets
|
||||
|
||||
# For community products only
|
||||
./gradlew :intellij.platform.buildScripts:runIde -PmainClass=org.jetbrains.intellij.build.productLayout.CommunityModuleSets
|
||||
```
|
||||
|
||||
**From IDE:**
|
||||
Run the "Generate Product Layouts" run configuration.
|
||||
|
||||
### Querying Module Sets
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import com.intellij.platform.plugins.parser.impl.elements.ModuleLoadingRule
|
||||
*
|
||||
* @param spec The product modules specification
|
||||
* @param collectModuleSetAliases Whether to collect module set aliases during traversal (for inlineModuleSets mode)
|
||||
* @return Triple of (content blocks, module-to-set chain mapping, module set alias to source mapping)
|
||||
* @return Triple of (content blocks, module-to-set chain mapping, module set alias-to-source mapping)
|
||||
*/
|
||||
internal fun buildContentBlocksAndChainMapping(
|
||||
spec: ProductModulesContentSpec,
|
||||
@@ -22,7 +22,7 @@ internal fun buildContentBlocksAndChainMapping(
|
||||
val moduleToSets = mutableMapOf<String, MutableList<String>>()
|
||||
val aliasToSource = if (collectModuleSetAliases) mutableMapOf<String, String>() else null
|
||||
val processedSets = HashSet<String>()
|
||||
val contentBlockByName = mutableMapOf<String, ContentBlock>()
|
||||
val contentBlockByName = HashMap<String, ContentBlock>()
|
||||
|
||||
fun traverse(moduleSet: ModuleSet, chain: List<String>, overrides: Map<String, ModuleLoadingRule>) {
|
||||
val setName = "$MODULE_SET_PREFIX${moduleSet.name}"
|
||||
@@ -30,7 +30,7 @@ internal fun buildContentBlocksAndChainMapping(
|
||||
// Check if already processed
|
||||
val alreadyProcessed = !processedSets.add(setName)
|
||||
if (alreadyProcessed) {
|
||||
// If already processed but now we have overrides, update the existing content block
|
||||
// If already processed, but now we have overrides, update the existing content block
|
||||
if (overrides.isNotEmpty()) {
|
||||
val existingBlock = contentBlockByName[moduleSet.name]
|
||||
if (existingBlock != null) {
|
||||
@@ -69,13 +69,9 @@ internal fun buildContentBlocksAndChainMapping(
|
||||
}
|
||||
|
||||
val currentChain = chain + setName
|
||||
|
||||
// Get direct modules for this set
|
||||
val directModules = getDirectModules(moduleSet, spec.excludedModules)
|
||||
|
||||
// Build content block and track chains/duplicates in single pass
|
||||
val modulesWithLoading = mutableListOf<ModuleWithLoading>()
|
||||
for (module in directModules) {
|
||||
for (module in moduleSet.modules) {
|
||||
// Track for duplicate detection
|
||||
moduleToSets.computeIfAbsent(module.name) { mutableListOf() }.add(moduleSet.name)
|
||||
// Track chain
|
||||
@@ -104,7 +100,7 @@ internal fun buildContentBlocksAndChainMapping(
|
||||
|
||||
// Validate that all overridden modules exist as direct modules in their respective module sets
|
||||
for (moduleSetWithOverrides in spec.moduleSets) {
|
||||
validateModuleSetOverrides(moduleSetWithOverrides, spec)
|
||||
validateModuleSetOverrides(moduleSetWithOverrides)
|
||||
}
|
||||
|
||||
// Check for duplicates and FAIL if found
|
||||
@@ -113,9 +109,7 @@ internal fun buildContentBlocksAndChainMapping(
|
||||
// Add additional modules if any
|
||||
val additionalModulesWithLoading = mutableListOf<ModuleWithLoading>()
|
||||
for (module in spec.additionalModules) {
|
||||
if (module.name !in spec.excludedModules) {
|
||||
additionalModulesWithLoading.add(ModuleWithLoading(module.name, module.loading))
|
||||
}
|
||||
additionalModulesWithLoading.add(ModuleWithLoading(module.name, module.loading))
|
||||
}
|
||||
|
||||
if (additionalModulesWithLoading.isNotEmpty()) {
|
||||
@@ -137,7 +131,7 @@ internal fun collectAndValidateAliases(
|
||||
spec: ProductModulesContentSpec,
|
||||
moduleSetAliases: Map<String, String>
|
||||
): List<String> {
|
||||
val allAliases = moduleSetAliases.toMutableMap()
|
||||
val allAliases = HashMap(moduleSetAliases)
|
||||
|
||||
// Collect product-level aliases and check for conflicts with module set aliases
|
||||
for (alias in spec.productModuleAliases) {
|
||||
|
||||
@@ -70,15 +70,14 @@ class ModuleSetBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Include all modules from another ModuleSet.
|
||||
* Include another ModuleSet.
|
||||
*/
|
||||
fun moduleSet(set: ModuleSet) {
|
||||
modules.addAll(set.modules)
|
||||
nestedSets.add(set)
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
internal fun build(): Pair<List<ContentModule>, List<ModuleSet>> = Pair(modules, nestedSets)
|
||||
internal fun build(): Pair<List<ContentModule>, List<ModuleSet>> = Pair(java.util.List.copyOf(modules), java.util.List.copyOf(nestedSets))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,7 +123,7 @@ private fun appendModuleXml(sb: StringBuilder, module: ContentModule) {
|
||||
*/
|
||||
private fun appendModuleSetContent(sb: StringBuilder, moduleSet: ModuleSet, indent: String = " ", breadcrumb: String = "") {
|
||||
// Get direct modules (not from nested sets)
|
||||
val directModules = getDirectModules(moduleSet)
|
||||
val directModules = moduleSet.modules
|
||||
|
||||
// Recursively append nested sets first
|
||||
for (nestedSet in moduleSet.nestedSets) {
|
||||
@@ -167,9 +166,6 @@ private fun appendModuleSetContent(sb: StringBuilder, moduleSet: ModuleSet, inde
|
||||
* @return ModuleSetBuildResult containing XML and direct module count
|
||||
*/
|
||||
internal fun buildModuleSetXml(moduleSet: ModuleSet, label: String): ModuleSetBuildResult {
|
||||
// Count direct modules (excluding nested) - do this once upfront
|
||||
val directModuleCount = getDirectModules(moduleSet).size
|
||||
|
||||
val xml = buildString {
|
||||
// Add generated file header
|
||||
val mainClass = if (label == "community") "CommunityModuleSets" else "UltimateModuleSets"
|
||||
@@ -203,7 +199,7 @@ internal fun buildModuleSetXml(moduleSet: ModuleSet, label: String): ModuleSetBu
|
||||
append("</idea-plugin>")
|
||||
}
|
||||
|
||||
return ModuleSetBuildResult(xml, directModuleCount)
|
||||
return ModuleSetBuildResult(xml, moduleSet.modules.size)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -180,11 +180,6 @@ private fun enrichProductsWithMetrics(
|
||||
allModules.add(module.name)
|
||||
}
|
||||
|
||||
// Remove excluded modules
|
||||
for (excludedModule in contentSpec.excludedModules) {
|
||||
allModules.remove(excludedModule)
|
||||
}
|
||||
|
||||
val totalModuleCount = allModules.size
|
||||
val directModuleCount = contentSpec.additionalModules.size
|
||||
val moduleSetCount = contentSpec.moduleSets.size
|
||||
@@ -518,7 +513,7 @@ private fun writeDuplicateAnalysis(
|
||||
for ((moduleSet, _, _) in allModuleSets) {
|
||||
val allModules = collectAllModuleNames(moduleSet)
|
||||
for (moduleName in allModules) {
|
||||
moduleToSets.getOrPut(moduleName) { mutableListOf() }.add(moduleSet.name)
|
||||
moduleToSets.computeIfAbsent(moduleName) { mutableListOf() }.add(moduleSet.name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -674,10 +669,10 @@ private fun writeModuleDistribution(
|
||||
// Build module → {inModuleSets: [], inProducts: []} mapping
|
||||
val moduleMap = mutableMapOf<String, ModuleDistributionInfo>()
|
||||
|
||||
// Collect modules from module sets
|
||||
// Collect modules from module sets (recursively including nested sets)
|
||||
for ((moduleSet, _, _) in allModuleSets) {
|
||||
for (module in moduleSet.modules) {
|
||||
val info = moduleMap.getOrPut(module.name) { ModuleDistributionInfo() }
|
||||
visitAllModules(moduleSet) { module ->
|
||||
val info = moduleMap.computeIfAbsent(module.name) { ModuleDistributionInfo() }
|
||||
info.inModuleSets.add(moduleSet.name)
|
||||
}
|
||||
}
|
||||
@@ -702,7 +697,7 @@ private fun writeModuleDistribution(
|
||||
|
||||
// Add to module map
|
||||
for (moduleName in allModulesInProduct) {
|
||||
val info = moduleMap.getOrPut(moduleName) { ModuleDistributionInfo() }
|
||||
val info = moduleMap.computeIfAbsent(moduleName) { ModuleDistributionInfo() }
|
||||
if (product.name !in info.inProducts) {
|
||||
info.inProducts.add(product.name)
|
||||
}
|
||||
@@ -827,10 +822,10 @@ private fun writeModuleUsageIndex(
|
||||
// Build comprehensive usage index
|
||||
val usageIndex = mutableMapOf<String, ModuleUsageInfo>()
|
||||
|
||||
// Collect from module sets
|
||||
// Collect from module sets (recursively including nested sets)
|
||||
for ((moduleSet, location, sourceFile) in allModuleSets) {
|
||||
for (module in moduleSet.modules) {
|
||||
val info = usageIndex.getOrPut(module.name) { ModuleUsageInfo() }
|
||||
visitAllModules(moduleSet) { module ->
|
||||
val info = usageIndex.computeIfAbsent(module.name) { ModuleUsageInfo() }
|
||||
info.moduleSets.add(ModuleSetReference(moduleSet.name, location, sourceFile))
|
||||
}
|
||||
}
|
||||
@@ -855,7 +850,7 @@ private fun writeModuleUsageIndex(
|
||||
|
||||
// Add to index
|
||||
for (moduleName in allModulesInProduct) {
|
||||
val info = usageIndex.getOrPut(moduleName) { ModuleUsageInfo() }
|
||||
val info = usageIndex.computeIfAbsent(moduleName) { ModuleUsageInfo() }
|
||||
info.products.add(ProductReference(product.name, product.sourceFile))
|
||||
}
|
||||
}
|
||||
@@ -1402,7 +1397,9 @@ private fun suggestModuleSetUnification(
|
||||
p.contentSpec?.moduleSets?.any { it.moduleSet.name == msEntry.moduleSet.name } == true
|
||||
}
|
||||
|
||||
if (usedByProducts.size <= 1 && msEntry.moduleSet.modules.size <= 5) {
|
||||
// Use total module count (including nested sets) for inline candidate detection
|
||||
val totalModuleCount = collectAllModuleNames(msEntry.moduleSet).size
|
||||
if (usedByProducts.size <= 1 && totalModuleCount <= 5) {
|
||||
suggestions.add(UnificationSuggestion(
|
||||
priority = "low",
|
||||
strategy = "inline",
|
||||
@@ -1412,10 +1409,10 @@ private fun suggestModuleSetUnification(
|
||||
moduleSet2 = null,
|
||||
products = null,
|
||||
sharedModuleSets = null,
|
||||
reason = "Used by only ${usedByProducts.size} product(s) and contains only ${msEntry.moduleSet.modules.size} modules. Consider inlining into the product directly.",
|
||||
reason = "Used by only ${usedByProducts.size} product(s) and contains only $totalModuleCount modules. Consider inlining into the product directly.",
|
||||
impact = mapOf(
|
||||
"moduleSetsSaved" to 1,
|
||||
"moduleCount" to msEntry.moduleSet.modules.size,
|
||||
"moduleCount" to totalModuleCount,
|
||||
"affectedProducts" to usedByProducts.map { it.name }
|
||||
)
|
||||
))
|
||||
@@ -1449,7 +1446,9 @@ private fun suggestModuleSetUnification(
|
||||
// Strategy 4: Split large module sets
|
||||
if (strategy == "split" || strategy == "all") {
|
||||
for (msEntry in allModuleSets) {
|
||||
if (msEntry.moduleSet.modules.size > 200) {
|
||||
// Use total module count (including nested sets) for split suggestions
|
||||
val totalModuleCount = collectAllModuleNames(msEntry.moduleSet).size
|
||||
if (totalModuleCount > 200) {
|
||||
suggestions.add(UnificationSuggestion(
|
||||
priority = "low",
|
||||
strategy = "split",
|
||||
@@ -1459,8 +1458,8 @@ private fun suggestModuleSetUnification(
|
||||
moduleSet2 = null,
|
||||
products = null,
|
||||
sharedModuleSets = null,
|
||||
reason = "Module set contains ${msEntry.moduleSet.modules.size} modules. Consider splitting into smaller, more focused sets for better maintainability.",
|
||||
impact = mapOf("moduleCount" to msEntry.moduleSet.modules.size)
|
||||
reason = "Module set contains $totalModuleCount modules. Consider splitting into smaller, more focused sets for better maintainability.",
|
||||
impact = mapOf("moduleCount" to totalModuleCount)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,11 +115,6 @@ class ProductModulesContentSpec(
|
||||
*/
|
||||
@JvmField val additionalModules: List<ContentModule>,
|
||||
|
||||
/**
|
||||
* Module names to exclude from the final set (after resolving all module sets and additions).
|
||||
* This is useful to remove specific modules from included module sets.
|
||||
*/
|
||||
@JvmField val excludedModules: Set<String>,
|
||||
|
||||
/**
|
||||
* Composition graph tracking how this spec was assembled.
|
||||
@@ -198,7 +193,6 @@ class ProductModulesContentSpecBuilder @PublishedApi internal constructor() {
|
||||
xmlIncludes.addAll(spec.deprecatedXmlIncludes)
|
||||
moduleSets.addAll(spec.moduleSets)
|
||||
additionalModules.addAll(spec.additionalModules)
|
||||
excludedModules.addAll(spec.excludedModules)
|
||||
|
||||
// Also preserve the nested spec's composition graph for deep analysis
|
||||
compositionGraph.addAll(spec.compositionGraph)
|
||||
@@ -323,7 +317,6 @@ class ProductModulesContentSpecBuilder @PublishedApi internal constructor() {
|
||||
deprecatedXmlIncludes = java.util.List.copyOf(xmlIncludes),
|
||||
moduleSets = java.util.List.copyOf(moduleSets),
|
||||
additionalModules = java.util.List.copyOf(additionalModules),
|
||||
excludedModules = java.util.Set.copyOf(excludedModules),
|
||||
compositionGraph = java.util.List.copyOf(compositionGraph),
|
||||
metadata = metadata,
|
||||
)
|
||||
|
||||
@@ -30,15 +30,13 @@ internal fun formatValidationError(
|
||||
* Throws an error if invalid overrides are found.
|
||||
*
|
||||
* @param moduleSetWithOverrides The module set with overrides to validate
|
||||
* @param spec The product modules specification (for excluded modules)
|
||||
*/
|
||||
internal fun validateModuleSetOverrides(
|
||||
moduleSetWithOverrides: ModuleSetWithOverrides,
|
||||
spec: ProductModulesContentSpec
|
||||
moduleSetWithOverrides: ModuleSetWithOverrides
|
||||
) {
|
||||
if (moduleSetWithOverrides.loadingOverrides.isEmpty()) return
|
||||
|
||||
val directModules = getDirectModules(moduleSetWithOverrides.moduleSet, spec.excludedModules).map { it.name }.toSet()
|
||||
val directModules = moduleSetWithOverrides.moduleSet.modules.mapTo(LinkedHashSet()) { it.name }
|
||||
val invalidOverrides = moduleSetWithOverrides.loadingOverrides.keys.filter { it !in directModules }
|
||||
|
||||
if (invalidOverrides.isNotEmpty()) {
|
||||
@@ -135,7 +133,7 @@ internal fun validateAndRecordAlias(
|
||||
|
||||
/**
|
||||
* Validates that products don't reference redundant module sets.
|
||||
* A module set is redundant if it's already nested inside another module set the product uses
|
||||
* A module set is redundant if it's already nested inside another module set the product uses,
|
||||
* and the product doesn't apply any overrides to it.
|
||||
*
|
||||
* This validation ensures product specifications are correct and maintainable.
|
||||
|
||||
@@ -94,39 +94,19 @@ internal fun collectAllModuleNames(moduleSet: ModuleSet, excludedModules: Set<St
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets direct modules from a module set (excluding modules from nested sets and excluded modules).
|
||||
* Visits all modules recursively (including nested sets), applying the visitor function to each.
|
||||
* More efficient than collecting when you only need iteration (avoids intermediate collection).
|
||||
*
|
||||
* @param moduleSet The module set to get direct modules from
|
||||
* @param excludedModules Set of module names to exclude
|
||||
* @return List of direct modules
|
||||
* @param moduleSet The module set to visit
|
||||
* @param visitor Function to apply to each module
|
||||
*/
|
||||
internal fun getDirectModules(moduleSet: ModuleSet, excludedModules: Set<String> = emptySet()): List<ContentModule> {
|
||||
// Fast path: no filtering needed (very common for leaf nodes)
|
||||
if (moduleSet.nestedSets.isEmpty() && excludedModules.isEmpty()) {
|
||||
return moduleSet.modules
|
||||
}
|
||||
|
||||
// Fast path: only check exclusions (no nested sets)
|
||||
if (moduleSet.nestedSets.isEmpty()) {
|
||||
return moduleSet.modules.filter { it.name !in excludedModules }
|
||||
}
|
||||
|
||||
// Build set of module names from nested sets
|
||||
val nestedModuleNames = HashSet<String>()
|
||||
for (nestedSet in moduleSet.nestedSets) {
|
||||
for (module in nestedSet.modules) {
|
||||
nestedModuleNames.add(module.name)
|
||||
}
|
||||
}
|
||||
|
||||
// Full filtering: check both nested modules and exclusions
|
||||
val directModules = mutableListOf<ContentModule>()
|
||||
internal fun visitAllModules(moduleSet: ModuleSet, visitor: (ContentModule) -> Unit) {
|
||||
for (module in moduleSet.modules) {
|
||||
if (module.name !in nestedModuleNames && module.name !in excludedModules) {
|
||||
directModules.add(module)
|
||||
}
|
||||
visitor(module)
|
||||
}
|
||||
for (nestedSet in moduleSet.nestedSets) {
|
||||
visitAllModules(nestedSet, visitor)
|
||||
}
|
||||
return directModules
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -117,8 +117,7 @@ fun buildProductContentXml(
|
||||
isUltimateBuild: Boolean,
|
||||
): ProductContentBuildResult {
|
||||
// Build content blocks, chain mapping, and collect module set aliases in single traversal
|
||||
val (contentBlocks, moduleToSetChainMapping, moduleSetAliases) =
|
||||
buildContentBlocksAndChainMapping(spec, collectModuleSetAliases = inlineModuleSets)
|
||||
val (contentBlocks, moduleToSetChainMapping, moduleSetAliases) = buildContentBlocksAndChainMapping(spec, collectModuleSetAliases = inlineModuleSets)
|
||||
|
||||
val xml = buildString {
|
||||
appendXmlHeader(generatorCommand, productPropertiesClass)
|
||||
|
||||
+4
-3
@@ -12,7 +12,7 @@ interface ApplicationInfoProperties {
|
||||
val isEAP: Boolean
|
||||
val versionSuffix: String?
|
||||
/**
|
||||
* The first number from 'minor' part of the version. This property is temporary added because some products specify composite number (like '1.3')
|
||||
* The first number from 'minor' part of the version. This property is temporarily added because some products specify composite number (like '1.3')
|
||||
* in 'minor version' attribute instead of using 'micro version' (i.e. set minor='1' micro='3').
|
||||
*/
|
||||
val minorVersionMainPart: String
|
||||
@@ -39,5 +39,6 @@ interface ApplicationInfoProperties {
|
||||
* another product, to get the instance of the product currently being build, use [BuildContext.applicationInfo] instead.
|
||||
*/
|
||||
@Internal
|
||||
fun BuildContext.loadApplicationInfoPropertiesForProduct(productProperties: ProductProperties): ApplicationInfoProperties =
|
||||
ApplicationInfoPropertiesImpl(project, productProperties, options)
|
||||
fun loadApplicationInfoPropertiesForProduct(productProperties: ProductProperties, context: BuildContext): ApplicationInfoProperties {
|
||||
return ApplicationInfoPropertiesImpl(context.project, productProperties, context.options)
|
||||
}
|
||||
|
||||
+1
-18
@@ -35,7 +35,6 @@ object CommunityModuleSets : ModuleSetProvider {
|
||||
|
||||
/**
|
||||
* Essential platform modules required by most IDE products.
|
||||
* Corresponds to intellij.moduleSets.essential.xml and includes libraries.
|
||||
*/
|
||||
fun essential(): ModuleSet = moduleSet("essential") {
|
||||
// Include libraries first (they are xi:included in essential.xml)
|
||||
@@ -130,7 +129,6 @@ object CommunityModuleSets : ModuleSetProvider {
|
||||
|
||||
/**
|
||||
* All library module sets combined (meta-set that includes core, ktor, misc, temporaryBundled).
|
||||
* Corresponds to intellij.moduleSets.libraries.xml
|
||||
*/
|
||||
fun libraries(): ModuleSet = moduleSet("libraries") {
|
||||
moduleSet(librariesCore())
|
||||
@@ -141,7 +139,6 @@ object CommunityModuleSets : ModuleSetProvider {
|
||||
|
||||
/**
|
||||
* Core library modules.
|
||||
* Corresponds to intellij.moduleSets.libraries.core.xml
|
||||
*/
|
||||
fun librariesCore(): ModuleSet = moduleSet("libraries.core") {
|
||||
embeddedModule("intellij.libraries.kotlin.reflect")
|
||||
@@ -229,7 +226,6 @@ object CommunityModuleSets : ModuleSetProvider {
|
||||
|
||||
/**
|
||||
* Ktor library modules.
|
||||
* Corresponds to intellij.moduleSets.libraries.ktor.xml
|
||||
*/
|
||||
fun librariesKtor(): ModuleSet = moduleSet("libraries.ktor") {
|
||||
embeddedModule("intellij.libraries.ktor.io")
|
||||
@@ -241,7 +237,6 @@ object CommunityModuleSets : ModuleSetProvider {
|
||||
|
||||
/**
|
||||
* Miscellaneous library modules.
|
||||
* Corresponds to intellij.moduleSets.libraries.misc.xml
|
||||
*/
|
||||
fun librariesMisc(): ModuleSet = moduleSet("libraries.misc") {
|
||||
// all libs here must not be embedded, if it is embedded, it should be moved to libs-core.xml
|
||||
@@ -253,7 +248,6 @@ object CommunityModuleSets : ModuleSetProvider {
|
||||
|
||||
/**
|
||||
* Temporarily bundled library modules (planned to be removed).
|
||||
* Corresponds to intellij.moduleSets.libraries.temporaryBundled.xml
|
||||
*/
|
||||
fun librariesTemporaryBundled(): ModuleSet = moduleSet("libraries.temporaryBundled") {
|
||||
// Currently used only by DBE (see https://youtrack.jetbrains.com/issue/IJPL-211789/CNFE-org.codehaus.jettison.mapped.Configuration).
|
||||
@@ -268,7 +262,6 @@ object CommunityModuleSets : ModuleSetProvider {
|
||||
|
||||
/**
|
||||
* VCS (Version Control System) modules including shared and frontend parts.
|
||||
* Corresponds to intellij.moduleSets.vcs.xml
|
||||
*/
|
||||
fun vcs(): ModuleSet = moduleSet("vcs") {
|
||||
module("intellij.platform.vcs.impl")
|
||||
@@ -290,7 +283,6 @@ object CommunityModuleSets : ModuleSetProvider {
|
||||
|
||||
/**
|
||||
* VCS shared modules (used by both frontend and backend).
|
||||
* Corresponds to intellij.moduleSets.vcs.shared.xml
|
||||
*/
|
||||
fun vcsShared(): ModuleSet = moduleSet("vcs.shared") {
|
||||
embeddedModule("intellij.platform.vcs.core")
|
||||
@@ -301,7 +293,6 @@ object CommunityModuleSets : ModuleSetProvider {
|
||||
|
||||
/**
|
||||
* VCS frontend modules.
|
||||
* Corresponds to intellij.moduleSets.vcs.frontend.xml
|
||||
*/
|
||||
fun vcsFrontend(): ModuleSet = moduleSet("vcs.frontend") {
|
||||
module("intellij.platform.vcs.impl.frontend")
|
||||
@@ -309,7 +300,6 @@ object CommunityModuleSets : ModuleSetProvider {
|
||||
|
||||
/**
|
||||
* XML support modules.
|
||||
* Corresponds to intellij.moduleSets.xml.xml
|
||||
*/
|
||||
fun xml(): ModuleSet = moduleSet("xml", alias = "com.intellij.modules.xml") {
|
||||
embeddedModule("intellij.xml.dom")
|
||||
@@ -334,7 +324,6 @@ object CommunityModuleSets : ModuleSetProvider {
|
||||
|
||||
/**
|
||||
* Duplicates analysis modules.
|
||||
* Corresponds to intellij.moduleSets.duplicates.xml
|
||||
*/
|
||||
fun duplicates(): ModuleSet = moduleSet("duplicates") {
|
||||
embeddedModule("intellij.platform.duplicates.analysis")
|
||||
@@ -342,7 +331,6 @@ object CommunityModuleSets : ModuleSetProvider {
|
||||
|
||||
/**
|
||||
* Stream debugger modules.
|
||||
* Corresponds to intellij.moduleSets.debugger.streams.xml
|
||||
*/
|
||||
fun debuggerStreams(): ModuleSet = moduleSet("debugger.streams") {
|
||||
module("intellij.debugger.streams.core")
|
||||
@@ -352,7 +340,6 @@ object CommunityModuleSets : ModuleSetProvider {
|
||||
|
||||
/**
|
||||
* Process elevation support (for operations requiring elevated privileges).
|
||||
* Corresponds to intellij.moduleSets.elevation.xml
|
||||
*/
|
||||
fun elevation(): ModuleSet = moduleSet("elevation") {
|
||||
module("intellij.execution.process.elevation")
|
||||
@@ -363,7 +350,6 @@ object CommunityModuleSets : ModuleSetProvider {
|
||||
|
||||
/**
|
||||
* Compose UI modules.
|
||||
* Corresponds to intellij.moduleSets.compose.xml
|
||||
*/
|
||||
fun compose(): ModuleSet = moduleSet("compose") {
|
||||
module("intellij.libraries.skiko")
|
||||
@@ -386,7 +372,6 @@ object CommunityModuleSets : ModuleSetProvider {
|
||||
|
||||
/**
|
||||
* Grid/data viewer core modules.
|
||||
* Corresponds to intellij.moduleSets.grid.core.xml
|
||||
*/
|
||||
fun gridCore(): ModuleSet = moduleSet("grid.core") {
|
||||
module("intellij.grid")
|
||||
@@ -398,7 +383,6 @@ object CommunityModuleSets : ModuleSetProvider {
|
||||
|
||||
/**
|
||||
* Remote development common modules.
|
||||
* Corresponds to intellij.moduleSets.rd.common.xml
|
||||
*/
|
||||
fun rdCommon(): ModuleSet = moduleSet("rd.common") {
|
||||
module("intellij.rd.ide.model.generated")
|
||||
@@ -408,7 +392,6 @@ object CommunityModuleSets : ModuleSetProvider {
|
||||
|
||||
/**
|
||||
* IDE common modules (includes essential, compose, grid.core, vcs, xml, duplicates).
|
||||
* Corresponds to intellij.moduleSets.ide.common.xml
|
||||
*/
|
||||
fun ideCommon(): ModuleSet = moduleSet("ide.common") {
|
||||
// Include essential first (which includes libraries)
|
||||
@@ -454,10 +437,10 @@ object CommunityModuleSets : ModuleSetProvider {
|
||||
moduleSet(vcs())
|
||||
moduleSet(xml())
|
||||
moduleSet(duplicates())
|
||||
module("intellij.platform.structuralSearch")
|
||||
|
||||
// Note: rd.common is intentionally NOT included in ide.common
|
||||
// Reason: Rider uses custom module loading mode due to early backend startup requirements.
|
||||
// Products that need rd.common include it explicitly in their product files.
|
||||
}
|
||||
|
||||
}
|
||||
+34
-32
@@ -7,7 +7,7 @@ import kotlinx.serialization.json.Json
|
||||
import java.nio.file.Path
|
||||
|
||||
/**
|
||||
* Parses JSON argument from command line in the format --json or --json='{"filter":"...","value":"..."}'.
|
||||
* Parses JSON argument from command line in the format `--json` or `--json='{"filter":"...","value":"..."}'`.
|
||||
* Returns null for full JSON output, or JsonFilter for filtered output.
|
||||
*
|
||||
* @param arg The command line argument (e.g., "--json" or "--json={...}")
|
||||
@@ -36,12 +36,10 @@ fun parseJsonArgument(arg: String): JsonFilter? {
|
||||
* 1. JSON mode (--json): Outputs comprehensive analysis as JSON to stdout
|
||||
* 2. Default mode: Generates XML files for module sets and products
|
||||
*
|
||||
* This is the generic orchestration logic that was previously duplicated in UltimateModuleSets.kt.
|
||||
* Now module set providers (community, ultimate) can call this function with their specific data.
|
||||
*
|
||||
* @param args Command line arguments
|
||||
* @param communityModuleSets Module sets from community
|
||||
* @param ultimateModuleSets Module sets from ultimate (or empty for community-only)
|
||||
* @param testProducts Test product specifications (name to ProductModulesContentSpec pairs)
|
||||
* @param communitySourceFile Source file path for community module sets
|
||||
* @param ultimateSourceFile Source file path for ultimate module sets (or null for community-only)
|
||||
* @param projectRoot Project root path
|
||||
@@ -51,45 +49,49 @@ fun runModuleSetMain(
|
||||
args: Array<String>,
|
||||
communityModuleSets: List<ModuleSet>,
|
||||
ultimateModuleSets: List<ModuleSet>,
|
||||
testProducts: List<Pair<String, ProductModulesContentSpec>> = emptyList(),
|
||||
communitySourceFile: String,
|
||||
ultimateSourceFile: String?,
|
||||
projectRoot: Path,
|
||||
generateXmlImpl: suspend () -> Unit
|
||||
) {
|
||||
// Parse --json arg with optional filter
|
||||
generateXmlImpl: suspend () -> Unit,
|
||||
): Unit = runBlocking(Dispatchers.Default) {
|
||||
// Parse `--json` arg with optional filter
|
||||
val jsonArg = args.firstOrNull { it.startsWith("--json") }
|
||||
|
||||
when {
|
||||
jsonArg != null -> {
|
||||
runBlocking(Dispatchers.Default) {
|
||||
// Prepare all module sets with metadata
|
||||
val communityModuleSetsWithMeta = communityModuleSets.map {
|
||||
ModuleSetMetadata(it, "community", communitySourceFile)
|
||||
}
|
||||
val ultimateModuleSetsWithMeta = if (ultimateSourceFile != null) {
|
||||
ultimateModuleSets.map {
|
||||
ModuleSetMetadata(it, "ultimate", ultimateSourceFile)
|
||||
}
|
||||
} else {
|
||||
emptyList()
|
||||
}
|
||||
val allModuleSets = communityModuleSetsWithMeta + ultimateModuleSetsWithMeta
|
||||
|
||||
// Discover all products (reuse existing logic from productXmlFileGenerator)
|
||||
val products = discoverAllProductsForJson(projectRoot)
|
||||
|
||||
// Parse filter from --json='{"filter":"..."}' format
|
||||
val filter = parseJsonArgument(jsonArg)
|
||||
|
||||
// Stream JSON to stdout
|
||||
streamModuleAnalysisJson(allModuleSets, products, projectRoot, filter)
|
||||
// Prepare all module sets with metadata
|
||||
val communityModuleSetsWithMeta = communityModuleSets.map {
|
||||
ModuleSetMetadata(it, "community", communitySourceFile)
|
||||
}
|
||||
val ultimateModuleSetsWithMeta = if (ultimateSourceFile == null) {
|
||||
emptyList()
|
||||
}
|
||||
else {
|
||||
ultimateModuleSets.map {
|
||||
ModuleSetMetadata(it, "ultimate", ultimateSourceFile)
|
||||
}
|
||||
}
|
||||
val allModuleSets = communityModuleSetsWithMeta + ultimateModuleSetsWithMeta
|
||||
|
||||
// Discover regular products and add passed test products
|
||||
val regularProducts = discoverAllProductsForJson(projectRoot)
|
||||
val testProductSpecs = testProducts.asSequence().map { (name, spec) ->
|
||||
ProductSpec(
|
||||
name = name,
|
||||
className = "test-product",
|
||||
sourceFile = "test-product",
|
||||
pluginXmlPath = "ultimate/platform-ultimate/testResources/META-INF/${name}Plugin.xml",
|
||||
contentSpec = spec,
|
||||
buildModules = emptyList()
|
||||
)
|
||||
}
|
||||
|
||||
streamModuleAnalysisJson(allModuleSets = allModuleSets, products = (regularProducts + testProductSpecs).toList(), projectRoot = projectRoot, filter = parseJsonArgument(jsonArg))
|
||||
}
|
||||
else -> {
|
||||
// Default mode: Generate XML files
|
||||
runBlocking(Dispatchers.Default) {
|
||||
generateXmlImpl()
|
||||
}
|
||||
generateXmlImpl()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-106
@@ -1,106 +0,0 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.intellij.build.productLayout
|
||||
|
||||
/**
|
||||
* Product spec helper functions for reusable product content fragments.
|
||||
* These functions return ProductModulesContentSpec instances that can be composed using include().
|
||||
*
|
||||
* Use these helpers to reduce duplication across product specifications while keeping
|
||||
* ProductModulesContentSpec immutable and declarative (suitable for future YAML representation).
|
||||
*/
|
||||
|
||||
/**
|
||||
* Common capability aliases shared across most ultimate products.
|
||||
* Bundles frequently repeated capability declarations to reduce duplication.
|
||||
*
|
||||
* Includes:
|
||||
* - Run targets support
|
||||
* - Microservices capabilities
|
||||
* - ML inline completion
|
||||
* - IDE provisioner
|
||||
* - Marketplace integration
|
||||
*
|
||||
* Usage:
|
||||
* ```
|
||||
* override fun getProductContentDescriptor(): ProductModulesContentSpec = productModules {
|
||||
* include(commonCapabilityAliases())
|
||||
* // ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
fun commonCapabilityAliases(): ProductModulesContentSpec = productModules {
|
||||
alias("com.intellij.modules.run.targets")
|
||||
alias("com.intellij.modules.microservices")
|
||||
alias("com.intellij.ml.inline.completion")
|
||||
alias("com.intellij.platform.ide.provisioner")
|
||||
alias("com.intellij.marketplace")
|
||||
}
|
||||
|
||||
/**
|
||||
* Python capability aliases for non-PyCharm products.
|
||||
* Enables Python support in multi-language IDEs like GoLand, DataGrip, CLion, RustRover, etc.
|
||||
*
|
||||
* Includes:
|
||||
* - Python core capabilities
|
||||
* - Python in mini-IDE capabilities
|
||||
* - Python in non-PyCharm IDE capabilities
|
||||
*
|
||||
* Usage:
|
||||
* ```
|
||||
* override fun getProductContentDescriptor(): ProductModulesContentSpec = productModules {
|
||||
* include(pythonMiniIdeCapabilities())
|
||||
* // ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
fun pythonMiniIdeCapabilities(): ProductModulesContentSpec = productModules {
|
||||
alias("com.intellij.modules.python-core-capable")
|
||||
alias("com.intellij.modules.python-in-mini-ide-capable")
|
||||
alias("com.intellij.modules.python-in-non-pycharm-ide-capable")
|
||||
}
|
||||
|
||||
/**
|
||||
* Common platform includes repeated across most ultimate products.
|
||||
* Bundles deprecatedInclude statements for legacy XML resource inclusion.
|
||||
*
|
||||
* Includes:
|
||||
* - Platform lang plugin resources
|
||||
* - Structural search resources
|
||||
* - Remote servers implementation
|
||||
* - Ultimate edition resources
|
||||
*
|
||||
* Usage:
|
||||
* ```
|
||||
* override fun getProductContentDescriptor(): ProductModulesContentSpec = productModules {
|
||||
* include(platformCommonIncludes())
|
||||
* // ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
fun platformCommonIncludes(): ProductModulesContentSpec = productModules {
|
||||
deprecatedInclude("intellij.platform.resources", "META-INF/PlatformLangPlugin.xml")
|
||||
deprecatedInclude("intellij.platform.structuralSearch", "META-INF/structuralsearch.xml")
|
||||
deprecatedInclude("intellij.platform.remoteServers.impl", "intellij.platform.remoteServers.impl.xml")
|
||||
deprecatedInclude("intellij.platform.commercial", "META-INF/ultimate.xml")
|
||||
}
|
||||
|
||||
/**
|
||||
* Extensions for native development IDEs (CLion, GoLand, RustRover).
|
||||
* Combines process elevation support with native debugger capability.
|
||||
*
|
||||
* Includes:
|
||||
* - Process elevation module set (for operations requiring elevated privileges)
|
||||
* - Native debugger plugin capability alias
|
||||
*
|
||||
* Usage:
|
||||
* ```
|
||||
* override fun getProductContentDescriptor(): ProductModulesContentSpec = productModules {
|
||||
* include(nativeDevExtensions())
|
||||
* // ...
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
fun nativeDevExtensions(): ProductModulesContentSpec = productModules {
|
||||
moduleSet(CommunityModuleSets.elevation())
|
||||
alias("com.intellij.modules.nativeDebug-plugin-capable")
|
||||
}
|
||||
+41
-69
@@ -17,11 +17,11 @@ import java.nio.file.Path
|
||||
* Test products have properties = null (they don't have ProductProperties classes).
|
||||
*/
|
||||
internal data class DiscoveredProduct(
|
||||
val name: String,
|
||||
val config: ProductConfiguration,
|
||||
val properties: ProductProperties?,
|
||||
val spec: ProductModulesContentSpec?,
|
||||
val pluginXmlPath: String?
|
||||
@JvmField val name: String,
|
||||
@JvmField val config: ProductConfiguration,
|
||||
@JvmField val properties: ProductProperties?,
|
||||
@JvmField val spec: ProductModulesContentSpec?,
|
||||
@JvmField val pluginXmlPath: String?,
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -31,11 +31,12 @@ internal data class DiscoveredProduct(
|
||||
*/
|
||||
internal fun DiscoveredProduct.toProductSpec(projectRoot: Path): ProductSpec {
|
||||
// For test products (properties = null), use "test-product" as source file
|
||||
val sourceFile = if (properties != null) {
|
||||
getProductPropertiesSourceFile(properties.javaClass, projectRoot)
|
||||
} else {
|
||||
val sourceFile = if (properties == null) {
|
||||
"test-product"
|
||||
}
|
||||
else {
|
||||
getProductPropertiesSourceFile(properties.javaClass, projectRoot)
|
||||
}
|
||||
|
||||
return ProductSpec(
|
||||
name = name,
|
||||
@@ -74,7 +75,7 @@ private suspend fun discoverAllProductsInternal(projectRoot: Path): List<Discove
|
||||
platformPrefix = null
|
||||
)
|
||||
val spec = productProperties.getProductContentDescriptor()
|
||||
|
||||
|
||||
products.add(
|
||||
DiscoveredProduct(
|
||||
name = productName,
|
||||
@@ -85,74 +86,22 @@ private suspend fun discoverAllProductsInternal(projectRoot: Path): List<Discove
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
return products
|
||||
}
|
||||
|
||||
/**
|
||||
* Discovers test products from known locations.
|
||||
* These are products used for testing that shouldn't be in dev-build.json.
|
||||
* Retrieves contentSpec from module set registries (UltimateModuleSets).
|
||||
*
|
||||
* @param projectRoot The project root path
|
||||
* @return List of test products as DiscoveredProduct with contentSpec
|
||||
*/
|
||||
private fun discoverTestProducts(projectRoot: Path): List<DiscoveredProduct> {
|
||||
// Build a registry of test product name -> (xmlPath, contentSpec)
|
||||
val testProductRegistry = mutableMapOf<String, Pair<String, ProductModulesContentSpec>>()
|
||||
|
||||
// Get ultimate test product specs (only if ultimate directory exists)
|
||||
if (Files.exists(projectRoot.resolve("ultimate"))) {
|
||||
try {
|
||||
// Load UltimateModuleSets via reflection to avoid hard dependency
|
||||
val ultimateModuleSetsClass = Class.forName("com.intellij.platform.commercial.buildScripts.productLayout.UltimateModuleSets")
|
||||
val instanceField = ultimateModuleSetsClass.getDeclaredField("INSTANCE")
|
||||
val ultimateModuleSetsInstance = instanceField.get(null)
|
||||
val getTestProductSpecsMethod = ultimateModuleSetsClass.getDeclaredMethod("getTestProductSpecs")
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val ultimateSpecs = getTestProductSpecsMethod.invoke(ultimateModuleSetsInstance) as List<Pair<String, ProductModulesContentSpec>>
|
||||
|
||||
for ((name, spec) in ultimateSpecs) {
|
||||
val xmlPath = "ultimate/platform-ultimate/testResources/META-INF/${name}Plugin.xml"
|
||||
testProductRegistry[name] = xmlPath to spec
|
||||
}
|
||||
} catch (e: ClassNotFoundException) {
|
||||
// Ultimate module not available, skip ultimate test products
|
||||
}
|
||||
}
|
||||
|
||||
// Build DiscoveredProduct instances for test products that exist on disk
|
||||
return testProductRegistry.mapNotNull { (name, pair) ->
|
||||
val (xmlPath, spec) = pair
|
||||
val xmlFile = projectRoot.resolve(xmlPath)
|
||||
if (!Files.exists(xmlFile)) return@mapNotNull null
|
||||
|
||||
DiscoveredProduct(
|
||||
name = name,
|
||||
config = ProductConfiguration(
|
||||
className = "test-product", // test products don't have Properties class
|
||||
modules = emptyList(),
|
||||
pluginXmlPath = xmlPath
|
||||
),
|
||||
properties = null, // test products don't have ProductProperties
|
||||
spec = spec,
|
||||
pluginXmlPath = xmlPath
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Discovers all products from dev-build.json registry and converts to ProductSpec for JSON output.
|
||||
* Public function that can be called from other modules (like ultimate buildScripts).
|
||||
* Test products should be passed separately via runModuleSetMain's testProducts parameter.
|
||||
*
|
||||
* @param projectRoot The project root path
|
||||
* @return List of products as ProductSpec (simple data class with no internal dependencies)
|
||||
*/
|
||||
suspend fun discoverAllProductsForJson(projectRoot: Path): List<ProductSpec> {
|
||||
suspend fun discoverAllProductsForJson(projectRoot: Path): Sequence<ProductSpec> {
|
||||
val regularProducts = discoverAllProductsInternal(projectRoot)
|
||||
val testProducts = discoverTestProducts(projectRoot)
|
||||
val allProducts = regularProducts + testProducts
|
||||
return allProducts.map { it.toProductSpec(projectRoot) }
|
||||
return regularProducts.asSequence().map { it.toProductSpec(projectRoot) }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,14 +118,37 @@ suspend fun discoverAllProductsForValidation(projectRoot: Path): List<Pair<Strin
|
||||
|
||||
/**
|
||||
* Generates product XMLs for all products using programmatic content.
|
||||
* Discovers products from dev-build.json and test products, then generates complete plugin.xml files.
|
||||
* Discovers products from dev-build.json and accepts test products as parameter, then generates complete plugin.xml files.
|
||||
*
|
||||
* @param projectRoot The project root path
|
||||
* @param testProductSpecs Test product specifications (name to ProductModulesContentSpec pairs)
|
||||
* @return Result containing generation statistics
|
||||
*/
|
||||
suspend fun generateAllProductXmlFiles(projectRoot: Path): ProductGenerationResult {
|
||||
suspend fun generateAllProductXmlFiles(
|
||||
projectRoot: Path,
|
||||
testProductSpecs: List<Pair<String, ProductModulesContentSpec>> = emptyList(),
|
||||
): ProductGenerationResult {
|
||||
val regularProducts = discoverAllProductsInternal(projectRoot)
|
||||
val testProducts = discoverTestProducts(projectRoot)
|
||||
|
||||
// Convert test product specs to DiscoveredProduct instances
|
||||
val testProducts = testProductSpecs.mapNotNull { (name, spec) ->
|
||||
val xmlPath = "ultimate/platform-ultimate/testResources/META-INF/${name}Plugin.xml"
|
||||
val xmlFile = projectRoot.resolve(xmlPath)
|
||||
if (!Files.exists(xmlFile)) return@mapNotNull null
|
||||
|
||||
DiscoveredProduct(
|
||||
name = name,
|
||||
config = ProductConfiguration(
|
||||
className = "test-product",
|
||||
modules = emptyList(),
|
||||
pluginXmlPath = xmlPath
|
||||
),
|
||||
properties = null,
|
||||
spec = spec,
|
||||
pluginXmlPath = xmlPath
|
||||
)
|
||||
}
|
||||
|
||||
val products = regularProducts + testProducts
|
||||
|
||||
// Detect if this is an Ultimate build (projectRoot != communityRoot)
|
||||
@@ -193,7 +165,7 @@ suspend fun generateAllProductXmlFiles(projectRoot: Path): ProductGenerationResu
|
||||
.loadProject(projectRoot.toString(), mapOf("MAVEN_REPOSITORY" to JpsMavenSettings.getMavenRepositoryPath()), false)
|
||||
.modules
|
||||
)
|
||||
|
||||
|
||||
generateProductXml(
|
||||
pluginXmlPath = pluginXmlPath,
|
||||
spec = spec,
|
||||
|
||||
@@ -15,8 +15,10 @@ private val RIDER_MODULE_ID = PluginModuleId("intellij.rider", PluginModuleId.JE
|
||||
private val JSON_ALIAS_ID = PluginId.getId("com.intellij.modules.json")
|
||||
private val JSON_BACKEND_MODULE_ID = PluginModuleId("intellij.json.backend", PluginModuleId.JETBRAINS_NAMESPACE)
|
||||
|
||||
internal class ModulesWithDependencies(val modules: List<PluginModuleDescriptor>,
|
||||
val directDependencies: Map<PluginModuleDescriptor, List<PluginModuleDescriptor>>) {
|
||||
internal class ModulesWithDependencies(
|
||||
@JvmField val modules: List<PluginModuleDescriptor>,
|
||||
@JvmField val directDependencies: Map<PluginModuleDescriptor, List<PluginModuleDescriptor>>,
|
||||
) {
|
||||
internal fun sorted(topologicalComparator: Comparator<PluginModuleDescriptor>): ModulesWithDependencies {
|
||||
return ModulesWithDependencies(
|
||||
modules = modules.sortedWith(topologicalComparator),
|
||||
@@ -59,7 +61,10 @@ internal fun createModulesWithDependenciesAndAdditionalEdges(plugins: Collection
|
||||
// and is loaded only in IntelliJ IDEA, so it may use classes from Java plugin.
|
||||
val implicitDep = if (hasAllModules && PluginCompatibilityUtils.isLegacyPluginWithoutPlatformAliasDependencies(module)) {
|
||||
pluginIdToDescriptor.get(PluginManagerCore.JAVA_PLUGIN_ALIAS_ID)
|
||||
} else null
|
||||
}
|
||||
else {
|
||||
null
|
||||
}
|
||||
if (implicitDep != null) {
|
||||
if (module === implicitDep) {
|
||||
PluginManagerCore.logger.error("Plugin $module depends on self")
|
||||
@@ -108,7 +113,7 @@ internal fun createModulesWithDependenciesAndAdditionalEdges(plugins: Collection
|
||||
dependenciesCollector.add(main)
|
||||
}
|
||||
|
||||
/* if the plugin containing the module is incompatible with some other plugins, make sure that the module is processed after that plugins (and all their required modules)
|
||||
/* if the plugin containing the module is incompatible with some other plugins, make sure that the module is processed after these plugins (and all their required modules)
|
||||
to ensure that the proper module is disabled in case of package conflict */
|
||||
for (incompatibility in main.incompatiblePlugins) {
|
||||
val incompatibleDescriptor = pluginIdToDescriptor.get(incompatibility)
|
||||
@@ -137,7 +142,7 @@ internal fun createModulesWithDependenciesAndAdditionalEdges(plugins: Collection
|
||||
) to additionalEdges
|
||||
}
|
||||
|
||||
// alias in most cases points to Core plugin, so, we cannot use computed dependencies to check
|
||||
// alias in most cases points to Core plugin, so we cannot use computed dependencies to check
|
||||
private fun doesDependOnPluginAlias(plugin: IdeaPluginDescriptorImpl, @Suppress("SameParameterValue") aliasId: PluginId): Boolean {
|
||||
return plugin.dependencies.any { it.pluginId == aliasId } || plugin.moduleDependencies.plugins.any { it == aliasId }
|
||||
}
|
||||
@@ -164,7 +169,7 @@ internal fun toCoreAwareComparator(comparator: Comparator<PluginModuleDescriptor
|
||||
* `<depends>com.intellij.modules.platform</depends>` or `<depends>com.intellij.modules.lang</depends>` tags.
|
||||
* See [this article](https://youtrack.jetbrains.com/articles/IJPL-A-956#keep-compatibility-with-external-plugins) for more details.
|
||||
*/
|
||||
private val contentModulesExtractedInCorePluginWhichCanBeUsedFromExternalPlugins = listOf(
|
||||
private val contentModulesExtractedInCorePluginWhichCanBeUsedFromExternalPlugins = arrayOf(
|
||||
"intellij.platform.collaborationTools.auth",
|
||||
"intellij.platform.collaborationTools.auth.base",
|
||||
"intellij.platform.tasks",
|
||||
@@ -175,13 +180,14 @@ private val contentModulesExtractedInCorePluginWhichCanBeUsedFromExternalPlugins
|
||||
"intellij.spellchecker.xml",
|
||||
"intellij.relaxng",
|
||||
"intellij.spellchecker",
|
||||
"intellij.platform.structuralSearch",
|
||||
).map { PluginModuleId(it, PluginModuleId.JETBRAINS_NAMESPACE) }
|
||||
|
||||
/**
|
||||
* List of content modules from the core plugin which should be automatically added as dependencies third-party plugins and plugins with dependency on `com.intellij.modules.vcs`
|
||||
* plugin alias for compatibility.
|
||||
*/
|
||||
private val vcsApiContentModules = listOf(
|
||||
private val vcsApiContentModules = arrayOf(
|
||||
"intellij.platform.vcs.impl",
|
||||
"intellij.platform.vcs.dvcs",
|
||||
"intellij.platform.vcs.dvcs.impl",
|
||||
@@ -196,7 +202,7 @@ private val COLLABORATION_TOOLS_MODULE_ID = PluginModuleId("intellij.platform.co
|
||||
* List of content modules from the core plugin which should be automatically added as dependencies to all plugins with dependency on `org.jetbrains.completion.full.line` plugin
|
||||
* alias for compatibility.
|
||||
*/
|
||||
private val fullLineApiContentModules = listOf(
|
||||
private val fullLineApiContentModules = arrayOf(
|
||||
"intellij.fullLine.core",
|
||||
"intellij.fullLine.local",
|
||||
"intellij.fullLine.core.impl",
|
||||
@@ -222,8 +228,10 @@ private fun collectDirectDependenciesInOldFormat(
|
||||
}
|
||||
}
|
||||
else {
|
||||
// e.g. `.env` plugin in an old format and doesn't explicitly specify dependency on a new extracted modules
|
||||
dependenciesCollector.addAll(dep.contentModules)
|
||||
// e.g. `.env` plugin in an old format and doesn't explicitly specify dependency on new extracted modules
|
||||
if (dep is PluginMainDescriptor) {
|
||||
dependenciesCollector.addAll(dep.contentModules)
|
||||
}
|
||||
|
||||
dependenciesCollector.add(dep)
|
||||
}
|
||||
@@ -290,7 +298,7 @@ private fun collectDirectDependenciesInNewFormat(
|
||||
}
|
||||
}
|
||||
|
||||
if (module.pluginId != PluginManagerCore.CORE_ID) {
|
||||
if (module.pluginId != PluginManagerCore.CORE_ID && module is PluginMainDescriptor) {
|
||||
/* Add edges to all required content modules.
|
||||
This is needed to ensure that the main plugin module is processed after them, and at that point we can determine whether the plugin
|
||||
can be loaded or not. */
|
||||
|
||||
@@ -280,6 +280,7 @@
|
||||
<module name="intellij.platform.langInjection.backend"/>
|
||||
<module name="intellij.libraries.grpc"/>
|
||||
<module name="intellij.libraries.grpc.netty.shaded"/>
|
||||
<module name="intellij.platform.structuralSearch"/>
|
||||
<!-- </editor-fold> -->
|
||||
</content>
|
||||
</idea-plugin>
|
||||
@@ -0,0 +1,3 @@
|
||||
- name: dist.all/lib/intellij.platform.structuralSearch.jar
|
||||
modules:
|
||||
- name: intellij.platform.structuralSearch
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
<idea-plugin>
|
||||
<idea-plugin visibility="public">
|
||||
<module value="com.intellij.modules.structuralsearch"/>
|
||||
|
||||
<extensionPoints>
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
<idea-plugin package="org.jetbrains.kotlin.idea.k2.codeinsight.structuralsearch">
|
||||
<dependencies>
|
||||
<plugin id="com.intellij.modules.structuralsearch"/>
|
||||
<module name="intellij.platform.structuralSearch"/>
|
||||
<module name="kotlin.code-insight.live-templates.shared"/>
|
||||
</dependencies>
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<module name="intellij.properties.psi"/>
|
||||
<module name="intellij.properties.backend.psi"/>
|
||||
<module name="intellij.spellchecker"/>
|
||||
<module name="intellij.platform.structuralSearch"/>
|
||||
</dependencies>
|
||||
|
||||
<extensionPoints>
|
||||
|
||||
@@ -5,9 +5,7 @@
|
||||
<module value="com.intellij.modules.pycharm"/>
|
||||
|
||||
<xi:include href="/META-INF/PlatformLangPlugin.xml"/>
|
||||
<xi:include href="/META-INF/structuralsearch.xml">
|
||||
<xi:fallback/>
|
||||
</xi:include>
|
||||
|
||||
<xi:include href="intellij.platform.remoteServers.impl.xml"/>
|
||||
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
|
||||
Reference in New Issue
Block a user