mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
IJPL-217839 introduce javaIdeBaseFragment as a replacement for deprecated xi-include
GitOrigin-RevId: 7e02eec1ae4b27cfa318b780ce9e00c5dadee350
This commit is contained in:
committed by
intellij-monorepo-bot
parent
9b7fc15cbb
commit
bc38cfec45
@@ -230,7 +230,7 @@ fun intellijCommunityBaseFragment(): ProductModulesContentSpec = productModules
|
||||
alias("com.intellij.platform.ide.provisioner")
|
||||
|
||||
include(CommunityProductFragments.platformLangBaseFragment())
|
||||
deprecatedInclude("intellij.java.ide.resources", "META-INF/JavaIdePlugin.xml")
|
||||
include(CommunityProductFragments.javaIdeBaseFragment())
|
||||
deprecatedInclude("intellij.idea.community.customization", "META-INF/tips-intellij-idea-community.xml")
|
||||
|
||||
moduleSet(CommunityModuleSets.debuggerStreams())
|
||||
|
||||
@@ -2,14 +2,22 @@
|
||||
<!-- To regenerate, run 'Generate Product Layouts' or directly CommunityModuleSets.main() -->
|
||||
<!-- Source: org.jetbrains.intellij.build.IdeaCommunityProperties -->
|
||||
<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<module value="com.intellij.modules.all"/>
|
||||
<module value="com.intellij.modules.idea"/>
|
||||
<module value="com.intellij.modules.idea.community"/>
|
||||
<module value="com.intellij.modules.java-capable"/>
|
||||
<module value="com.intellij.modules.jsp.base"/>
|
||||
<module value="com.intellij.modules.python-core-capable"/>
|
||||
<module value="com.intellij.modules.python-in-non-pycharm-ide-capable"/>
|
||||
<module value="com.intellij.platform.ide.provisioner"/>
|
||||
|
||||
<xi:include href="/META-INF/PlatformLangPlugin.xml"/>
|
||||
<xi:include href="intellij.platform.remoteServers.impl.xml">
|
||||
<xi:fallback/>
|
||||
</xi:include>
|
||||
<xi:include href="/META-INF/DesignerCorePlugin.xml">
|
||||
<xi:fallback/>
|
||||
</xi:include>
|
||||
<xi:include href="/META-INF/JavaIdePlugin.xml"/>
|
||||
<xi:include href="/META-INF/tips-intellij-idea-community.xml"/>
|
||||
<xi:include href="/META-INF/community-customization.xml"/>
|
||||
|
||||
@@ -1,29 +1,4 @@
|
||||
<!--
|
||||
~ Copyright 2000-2014 JetBrains s.r.o.
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<module value="com.intellij.modules.all"/>
|
||||
<module value="com.intellij.modules.jsp.base"/>
|
||||
|
||||
<xi:include href="intellij.platform.remoteServers.impl.xml">
|
||||
<xi:fallback/>
|
||||
</xi:include>
|
||||
<xi:include href="/META-INF/DesignerCorePlugin.xml">
|
||||
<xi:fallback/>
|
||||
</xi:include>
|
||||
|
||||
<idea-plugin>
|
||||
<extensions defaultExtensionNs="com.intellij">
|
||||
<applicationService serviceInterface="com.intellij.openapi.application.IdeUrlTrackingParametersProvider"
|
||||
serviceImplementation="com.intellij.ide.customization.UtmIdeUrlTrackingParametersProvider"
|
||||
|
||||
@@ -3,9 +3,7 @@ package org.jetbrains.intellij.build.productLayout
|
||||
|
||||
import com.intellij.openapi.util.JDOMUtil
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.jdom.Element
|
||||
import org.jetbrains.intellij.build.productLayout.analysis.ProductSpec
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.isRegularFile
|
||||
@@ -201,7 +199,6 @@ object DuplicateIncludeDetector {
|
||||
return fileName.endsWith("-customization.xml") ||
|
||||
fileName == "ultimate.xml" ||
|
||||
fileName == "PlatformLangPlugin.xml" ||
|
||||
fileName == "JavaIdePlugin.xml" ||
|
||||
fileName == "structuralsearch.xml" ||
|
||||
fileName.endsWith("Plugin.xml")
|
||||
}
|
||||
@@ -210,33 +207,11 @@ object DuplicateIncludeDetector {
|
||||
* Represents a single xi:include element.
|
||||
*/
|
||||
private data class XiInclude(
|
||||
val href: String,
|
||||
val lineNumber: Int?
|
||||
@JvmField val href: String,
|
||||
@JvmField val lineNumber: Int?
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects and prints duplicate xi:include elements in product plugin.xml files.
|
||||
* This is a convenience function that takes discovered products and outputs JSON report.
|
||||
*
|
||||
* @param products List of discovered products with their plugin XML paths
|
||||
* @param projectRoot Project root directory for resolving relative paths
|
||||
*/
|
||||
fun detectAndPrintDuplicateIncludes(products: List<ProductSpec>, projectRoot: Path) {
|
||||
// Convert ProductSpec plugin paths to actual file paths
|
||||
val productFiles = products
|
||||
.mapNotNull { it.pluginXmlPath }
|
||||
.map { projectRoot.resolve(it) }
|
||||
.filter { it.exists() && it.isRegularFile() }
|
||||
|
||||
// Run detection
|
||||
val report = DuplicateIncludeDetector.detectDuplicates(productFiles, projectRoot)
|
||||
|
||||
// Output JSON
|
||||
val json = Json { prettyPrint = true }
|
||||
println(json.encodeToString(report))
|
||||
}
|
||||
|
||||
/**
|
||||
* Report containing all detected duplicate includes.
|
||||
*/
|
||||
|
||||
@@ -113,7 +113,7 @@ fun streamModuleAnalysisJson(
|
||||
}
|
||||
filter.filter == "duplicates" -> {
|
||||
gen.writeObjectFieldStart("duplicateAnalysis")
|
||||
writeDuplicateAnalysis(gen, allModuleSets)
|
||||
writeDuplicateAnalysis(gen, allModuleSets, enrichedProducts, projectRoot)
|
||||
gen.writeEndObject()
|
||||
}
|
||||
filter.filter == "product" && filter.value != null -> {
|
||||
@@ -219,7 +219,7 @@ private fun writeAllSections(
|
||||
|
||||
// Write duplicate analysis
|
||||
gen.writeObjectFieldStart("duplicateAnalysis")
|
||||
writeDuplicateAnalysis(gen, allModuleSets)
|
||||
writeDuplicateAnalysis(gen, allModuleSets, products, projectRoot)
|
||||
gen.writeEndObject()
|
||||
|
||||
// Write product composition analysis
|
||||
|
||||
@@ -29,8 +29,8 @@ internal fun StringBuilder.appendOpeningTag(
|
||||
// Determine if xi:include namespace is needed
|
||||
val hasXmlIncludes = !inlineXmlIncludes && spec.deprecatedXmlIncludes.isNotEmpty()
|
||||
val hasModuleSetIncludes = !inlineModuleSets && spec.moduleSets.isNotEmpty()
|
||||
val needsXiNamespace = hasXmlIncludes || hasModuleSetIncludes
|
||||
|
||||
// when we inline another some xi-include file, it can in turn have own xi-includes
|
||||
val needsXiNamespace = inlineXmlIncludes || hasXmlIncludes || hasModuleSetIncludes
|
||||
if (needsXiNamespace) {
|
||||
append("<idea-plugin xmlns:xi=\"http://www.w3.org/2001/XInclude\">\n")
|
||||
}
|
||||
@@ -62,7 +62,7 @@ internal fun generateXIncludes(
|
||||
isUltimateBuild: Boolean,
|
||||
) {
|
||||
for (include in spec.deprecatedXmlIncludes) {
|
||||
// When inlining: skip ultimate-only xi-includes in Community builds
|
||||
// When inlining: skip ultimate-only `xi-includes` in Community builds
|
||||
if (inlineXmlIncludes && include.ultimateOnly && !isUltimateBuild) {
|
||||
continue
|
||||
}
|
||||
@@ -111,7 +111,7 @@ internal fun generateXIncludes(
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a resource path to an xi:include href path.
|
||||
* Converts a resource path to an `xi:include` href path.
|
||||
*/
|
||||
internal fun resourcePathToXIncludePath(resourcePath: String): String {
|
||||
return if (isModuleNameLikeFilename(resourcePath)) resourcePath else "/$resourcePath"
|
||||
|
||||
@@ -2,10 +2,15 @@
|
||||
package org.jetbrains.intellij.build.productLayout.json
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator
|
||||
import org.jetbrains.intellij.build.productLayout.DuplicateIncludeDetector
|
||||
import org.jetbrains.intellij.build.productLayout.ModuleSet
|
||||
import org.jetbrains.intellij.build.productLayout.analysis.ModuleSetMetadata
|
||||
import org.jetbrains.intellij.build.productLayout.analysis.ProductSpec
|
||||
import org.jetbrains.intellij.build.productLayout.collectAllModuleNames
|
||||
import org.jetbrains.intellij.build.productLayout.collectAllModuleNamesFromSet
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.isRegularFile
|
||||
|
||||
/**
|
||||
* Writes a single module set to JSON.
|
||||
@@ -43,11 +48,13 @@ fun writeModuleSet(
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes duplicate analysis section.
|
||||
* Writes duplicate analysis section including both module duplicates and xi:include duplicates.
|
||||
*/
|
||||
fun writeDuplicateAnalysis(
|
||||
gen: JsonGenerator,
|
||||
allModuleSets: List<ModuleSetMetadata>
|
||||
allModuleSets: List<ModuleSetMetadata>,
|
||||
products: List<ProductSpec>,
|
||||
projectRoot: Path
|
||||
) {
|
||||
// Find modules that appear in multiple module sets
|
||||
val moduleToSets = mutableMapOf<String, MutableList<String>>()
|
||||
@@ -121,4 +128,17 @@ fun writeDuplicateAnalysis(
|
||||
}
|
||||
}
|
||||
gen.writeEndArray()
|
||||
|
||||
// xi:include duplicate detection
|
||||
val productFiles = products
|
||||
.mapNotNull { it.pluginXmlPath }
|
||||
.map { projectRoot.resolve(it) }
|
||||
.filter { it.exists() && it.isRegularFile() }
|
||||
|
||||
val report = DuplicateIncludeDetector.detectDuplicates(productFiles, projectRoot)
|
||||
|
||||
// Serialize using kotlinx.serialization and write raw JSON (consistent with ModuleSet pattern)
|
||||
val reportJson = kotlinxJson.encodeToString(report)
|
||||
gen.writeFieldName("xiIncludeDuplicates")
|
||||
gen.writeRawValue(reportJson)
|
||||
}
|
||||
|
||||
@@ -1,142 +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
|
||||
|
||||
import com.intellij.openapi.application.PathManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.jetbrains.intellij.build.productLayout.DuplicateIncludeDetector
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.isDirectory
|
||||
import kotlin.io.path.isRegularFile
|
||||
import kotlin.io.path.listDirectoryEntries
|
||||
import kotlin.io.path.readText
|
||||
import kotlin.io.path.walk
|
||||
|
||||
/**
|
||||
* Command-line tool to detect duplicate xi:include elements in product plugin.xml files.
|
||||
*
|
||||
* Usage:
|
||||
* bazel run //community/platform/build-scripts:DuplicateIncludeAnalyzer
|
||||
*
|
||||
* Output:
|
||||
* JSON report showing products with duplicate includes, where each duplicate comes from,
|
||||
* and summary statistics.
|
||||
*/
|
||||
object DuplicateIncludeAnalyzer {
|
||||
@JvmStatic
|
||||
fun main(args: Array<String>) {
|
||||
runBlocking(Dispatchers.Default) {
|
||||
val projectRoot = Path.of(PathManager.getHomePathFor(DuplicateIncludeAnalyzer::class.java)!!)
|
||||
|
||||
// Discover all product plugin.xml files
|
||||
val productFiles = discoverProductFiles(projectRoot)
|
||||
|
||||
// Run detection
|
||||
val report = DuplicateIncludeDetector.detectDuplicates(productFiles, projectRoot)
|
||||
|
||||
// Output JSON
|
||||
val json = Json { prettyPrint = true }
|
||||
println(json.encodeToString(report))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Discovers all product plugin.xml files in the project.
|
||||
* Searches in known product directories and looks for files ending with Plugin.xml or named plugin.xml.
|
||||
*/
|
||||
private fun discoverProductFiles(projectRoot: Path): List<Path> {
|
||||
val productFiles = mutableListOf<Path>()
|
||||
|
||||
// Known product directories to search
|
||||
val productDirs = listOf(
|
||||
projectRoot.resolve("community"),
|
||||
projectRoot.resolve("ultimate"),
|
||||
projectRoot.resolve("CIDR"),
|
||||
projectRoot.resolve("goland"),
|
||||
projectRoot.resolve("ruby"),
|
||||
projectRoot.resolve("WebStorm"),
|
||||
projectRoot.resolve("dbe"),
|
||||
projectRoot.resolve("aqua"),
|
||||
projectRoot.resolve("rider"),
|
||||
projectRoot.resolve("python"),
|
||||
projectRoot.resolve("plugins"),
|
||||
)
|
||||
|
||||
for (dir in productDirs) {
|
||||
if (!dir.exists() || !dir.isDirectory()) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Search for Plugin.xml files in resources/META-INF directories
|
||||
dir.walk()
|
||||
.filter { it.isRegularFile() }
|
||||
.filter { it.parent?.fileName?.toString() == "META-INF" }
|
||||
.filter {
|
||||
val name = it.fileName.toString()
|
||||
name.endsWith("Plugin.xml") || name == "plugin.xml"
|
||||
}
|
||||
.filter { isProductFile(it) }
|
||||
.forEach { productFiles.add(it) }
|
||||
}
|
||||
|
||||
return productFiles.distinct()
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an XML file is a product descriptor (not a plugin descriptor).
|
||||
* Products don't have their own <id> tag or have <id>com.intellij</id>.
|
||||
* Also filters out test files and non-product descriptors.
|
||||
*/
|
||||
private fun isProductFile(file: Path): Boolean {
|
||||
// Skip test resources
|
||||
if (file.toString().contains("/testResources/") ||
|
||||
file.toString().contains("/testSrc/") ||
|
||||
file.toString().contains("/test/")) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Skip toolbox
|
||||
if (file.toString().contains("/toolbox/")) {
|
||||
return false
|
||||
}
|
||||
|
||||
val fileName = file.fileName.toString()
|
||||
|
||||
// Skip module descriptor files (have dots in the name like intellij.platform.jewel.detektPlugin.xml)
|
||||
if (fileName != "plugin.xml" && fileName.contains(".") && !fileName.matches(Regex("^[A-Z][a-zA-Z]*Plugin\\.xml$"))) {
|
||||
return false
|
||||
}
|
||||
|
||||
try {
|
||||
val content = file.readText()
|
||||
|
||||
// Check for <id> tag that's NOT com.intellij
|
||||
val idMatch = Regex("""<id>([^<]+)</id>""").find(content)
|
||||
if (idMatch != null && idMatch.groupValues[1] != "com.intellij") {
|
||||
// This is a plugin with its own ID, not a product
|
||||
return false
|
||||
}
|
||||
|
||||
// Check if it has ApplicationInfo.xml nearby (strong indicator of a product)
|
||||
val resourceRoot = file.parent?.parent // Go up from META-INF to resources
|
||||
if (resourceRoot != null) {
|
||||
val ideaDir = resourceRoot.resolve("idea")
|
||||
if (ideaDir.exists() && ideaDir.isDirectory()) {
|
||||
val hasAppInfo = ideaDir.listDirectoryEntries()
|
||||
.any { it.fileName.toString().endsWith("ApplicationInfo.xml") }
|
||||
if (hasAppInfo) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If no <id> tag or has com.intellij, likely a product
|
||||
return true
|
||||
}
|
||||
catch (e: Exception) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
+24
@@ -18,4 +18,28 @@ object CommunityProductFragments {
|
||||
fun platformLangBaseFragment(): ProductModulesContentSpec = productModules {
|
||||
deprecatedInclude("intellij.platform.resources", "META-INF/PlatformLangPlugin.xml")
|
||||
}
|
||||
|
||||
/**
|
||||
* Java IDE base fragment: provides Java IDE module aliases and optional plugin includes.
|
||||
*
|
||||
* Includes:
|
||||
* - Module aliases for Java IDE capability detection
|
||||
* - Optional remote servers support
|
||||
* - Optional UI Designer support
|
||||
* - Extensions for IDEA-specific customization (UTM tracking, new UI onboarding)
|
||||
*
|
||||
* Use this fragment for products that include Java IDE functionality.
|
||||
*/
|
||||
fun javaIdeBaseFragment(): ProductModulesContentSpec = productModules {
|
||||
// Module capability aliases
|
||||
alias("com.intellij.modules.all")
|
||||
alias("com.intellij.modules.jsp.base")
|
||||
|
||||
// Optional plugin support (with fallback)
|
||||
deprecatedInclude("intellij.platform.remoteServers.impl", "intellij.platform.remoteServers.impl.xml", optional = true)
|
||||
deprecatedInclude("intellij.uiDesigner", "META-INF/DesignerCorePlugin.xml", optional = true)
|
||||
|
||||
// Extensions block (UTM tracking, new UI onboarding)
|
||||
deprecatedInclude("intellij.java.ide.resources", "META-INF/JavaIdePlugin.xml")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user