mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[dev launcher] provide a way to locate resource files in module sources in dev launcher (RDCT-1405)
To determine which modules should be compiled in IntellijDevLauncher, we need to load product-modules.xml and plugin.xml files. Currently, they are loaded via RuntimeModuleRepository from output directories, so obsolete variant may be loaded or file may not be found at all if modules containing these files aren't compiled yet. This change introduces the ModuleResourceFileFinder class, which can locate resource files in source directories instead. It doesn't use existing functionality for that to avoid adding additional modules to the system classloader. Also, it parses necessary *.iml files only to speed up the process. GitOrigin-RevId: d55083ba879a3ae8c7985ba6e5f0211ad3062959
This commit is contained in:
committed by
intellij-monorepo-bot
parent
019cdc28dd
commit
2192a0d35b
Generated
+1
@@ -942,6 +942,7 @@
|
||||
<module fileurl="file://$PROJECT_DIR$/tools/apiDump/intellij.tools.apiDump.iml" filepath="$PROJECT_DIR$/tools/apiDump/intellij.tools.apiDump.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/tools/apiDump/testData/intellij.tools.apiDump.testData.iml" filepath="$PROJECT_DIR$/tools/apiDump/testData/intellij.tools.apiDump.testData.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/tools/devLauncher/intellij.tools.devLauncher.iml" filepath="$PROJECT_DIR$/tools/devLauncher/intellij.tools.devLauncher.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/tools/devLauncher/tests/intellij.tools.devLauncher.tests.iml" filepath="$PROJECT_DIR$/tools/devLauncher/tests/intellij.tools.devLauncher.tests.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/tools/intellij.tools.ide.metrics.benchmark/intellij.tools.ide.metrics.benchmark.iml" filepath="$PROJECT_DIR$/tools/intellij.tools.ide.metrics.benchmark/intellij.tools.ide.metrics.benchmark.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/tools/intellij.tools.ide.metrics.collector/intellij.tools.ide.metrics.collector.iml" filepath="$PROJECT_DIR$/tools/intellij.tools.ide.metrics.collector/intellij.tools.ide.metrics.collector.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/plugins/performanceTesting/commands-model/intellij.tools.ide.performanceTesting.commands.iml" filepath="$PROJECT_DIR$/plugins/performanceTesting/commands-model/intellij.tools.ide.performanceTesting.commands.iml" />
|
||||
|
||||
@@ -208,6 +208,7 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.uast.tests" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.runtime.repository.tests" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.runtime.product.tests" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.tools.devLauncher.tests" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.html.tools.tests" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.lombok" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.xml.xmlbeans" scope="TEST" />
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
package com.intellij.tools.devLauncher
|
||||
|
||||
import java.nio.file.Path
|
||||
import javax.xml.stream.XMLInputFactory
|
||||
import javax.xml.stream.XMLStreamConstants
|
||||
import kotlin.io.path.*
|
||||
|
||||
/**
|
||||
* Provides a way to locate a resource file under source roots by its relative path in an IntelliJ project.
|
||||
*/
|
||||
class ModuleResourceFileFinder(private val projectDir: Path) {
|
||||
private val moduleFiles: Map<String, Path>
|
||||
|
||||
init {
|
||||
val modulesXmlFile = projectDir.resolve(".idea/modules.xml")
|
||||
require(modulesXmlFile.exists()) { ".idea/modules.xml not found in $projectDir"}
|
||||
modulesXmlFile.inputStream().buffered().use { input ->
|
||||
val moduleFilesMap = LinkedHashMap<String, Path>()
|
||||
val reader = XMLInputFactory.newDefaultFactory().createXMLStreamReader(input)
|
||||
while (reader.hasNext()) {
|
||||
val event = reader.next()
|
||||
if (event == XMLStreamConstants.START_ELEMENT && reader.localName == "module") {
|
||||
val attributeName = reader.getAttributeLocalName(0)
|
||||
require(attributeName == "fileurl") { "Unexpected first attribute in 'module' tag: $attributeName"}
|
||||
val imlUrl = reader.getAttributeValue(0)
|
||||
val prefix = "file://${'$'}PROJECT_DIR${'$'}/"
|
||||
require(imlUrl.startsWith(prefix)) { "Unexpected format of URL: $imlUrl"}
|
||||
val imlPath = projectDir.resolve(imlUrl.removePrefix(prefix))
|
||||
val fileName = imlPath.name
|
||||
val suffix = ".iml"
|
||||
require(fileName.endsWith(suffix)) { "Unexpected file extension in file path $imlPath" }
|
||||
val moduleName = fileName.removeSuffix(suffix)
|
||||
moduleFilesMap[moduleName] = imlPath
|
||||
}
|
||||
}
|
||||
moduleFiles = moduleFilesMap
|
||||
}
|
||||
}
|
||||
|
||||
fun findResourceFile(moduleName: String, relativePath: String): Path? {
|
||||
for ((prefix, rootPath) in loadRootsWithPrefixes(moduleName)) {
|
||||
val relativePathWithoutPrefix = when {
|
||||
prefix == null -> relativePath
|
||||
relativePath.startsWith("$prefix/") -> relativePath.removePrefix("$prefix/")
|
||||
else -> continue
|
||||
}
|
||||
val file = rootPath.resolve(relativePathWithoutPrefix)
|
||||
if (file.exists()) {
|
||||
return file
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun loadRootsWithPrefixes(moduleName: String): List<Pair<String?, Path>> {
|
||||
val imlPath = moduleFiles[moduleName] ?: error("Cannot find module '$moduleName' in project '$projectDir'")
|
||||
require(imlPath.exists()) { "Module file $imlPath doesn't exist" }
|
||||
val moduleDir = imlPath.parent
|
||||
val rootsWithPrefixes = ArrayList<Pair<String?, Path>>()
|
||||
imlPath.inputStream().buffered().use { input ->
|
||||
val reader = XMLInputFactory.newDefaultFactory().createXMLStreamReader(input)
|
||||
while (reader.hasNext()) {
|
||||
val event = reader.next()
|
||||
if (event == XMLStreamConstants.START_ELEMENT && reader.localName == "sourceFolder") {
|
||||
require(reader.attributeCount > 1) { "At least two attributes expected in 'sourceFolder' tag in $imlPath, but ${reader.attributeCount} found" }
|
||||
val attributeName = reader.getAttributeLocalName(0)
|
||||
require(attributeName == "url") { "Unexpected first attribute in 'sourceFolder' tag in $imlPath: $attributeName" }
|
||||
val rootUrl = reader.getAttributeValue(0)
|
||||
val prefix = "file://"
|
||||
require(rootUrl.startsWith(prefix)) { "Unexpected format of URL: $rootUrl" }
|
||||
val rootPath = Path(rootUrl.removePrefix(prefix).replace("${'$'}MODULE_DIR${'$'}", moduleDir.pathString))
|
||||
|
||||
val typeAttributeName = reader.getAttributeLocalName(1)
|
||||
val typeAttributeValue = reader.getAttributeValue(1)
|
||||
val directoryPrefix = when {
|
||||
typeAttributeName == "isTestSource" && typeAttributeValue == "false" -> {
|
||||
if (reader.attributeCount > 2 && reader.getAttributeLocalName(2) == "packagePrefix") {
|
||||
reader.getAttributeValue(2).replace('.', '/').takeIf { it.isNotEmpty() }
|
||||
}
|
||||
else {
|
||||
null
|
||||
}
|
||||
}
|
||||
typeAttributeName == "type" && typeAttributeValue == "java-resource" -> {
|
||||
if (reader.attributeCount > 2 && reader.getAttributeLocalName(2) == "relativeOutputPath") {
|
||||
reader.getAttributeValue(2).removeSuffix("/").takeIf { it.isNotEmpty() }
|
||||
}
|
||||
else {
|
||||
null
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
continue
|
||||
}
|
||||
}
|
||||
rootsWithPrefixes.add(directoryPrefix to rootPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
return rootsWithPrefixes
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/testSrc" isTestSource="true" packagePrefix="com.intellij.tools.devLauncher" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="module" module-name="intellij.tools.devLauncher" scope="TEST" />
|
||||
<orderEntry type="library" name="kotlin-stdlib" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.testFramework.junit5" scope="TEST" />
|
||||
<orderEntry type="library" scope="TEST" name="JUnit5" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.testFramework" scope="TEST" />
|
||||
</component>
|
||||
</module>
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/root.iml" filepath="$PROJECT_DIR$/root.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/simple/simple.iml" filepath="$PROJECT_DIR$/simple/simple.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/withPrefix/withPrefix.iml" filepath="$PROJECT_DIR$/withPrefix/withPrefix.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="KotlinJavaRuntime" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/testSrc" isTestSource="true" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$/../additional-resources">
|
||||
<sourceFolder url="file://$MODULE_DIR$/../additional-resources" type="java-resource" relativeOutputPath="prefix3" />
|
||||
</content>
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" relativeOutputPath="prefix1" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="prefix2" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.intellij.tools.devLauncher
|
||||
|
||||
import com.intellij.openapi.application.ex.PathManagerEx
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.invariantSeparatorsPathString
|
||||
import kotlin.io.path.relativeTo
|
||||
|
||||
class ModuleResourceFileFinderTest {
|
||||
private lateinit var projectDir: Path
|
||||
private lateinit var finder: ModuleResourceFileFinder
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
projectDir = Path(PathManagerEx.getCommunityHomePath()).resolve("tools/devLauncher/tests/testData/moduleResourceFinderProject")
|
||||
finder = ModuleResourceFileFinder(projectDir)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `simple roots`() {
|
||||
assertPath("simple/resources/a.txt", finder.findResourceFile("simple", "a.txt"))
|
||||
assertPath("simple/src/b/b.txt", finder.findResourceFile("simple", "b/b.txt"))
|
||||
assertPath(null, finder.findResourceFile("simple", "c.txt"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `roots with prefixes`() {
|
||||
assertPath("withPrefix/resources/a.txt", finder.findResourceFile("withPrefix", "prefix1/a.txt"))
|
||||
assertPath("withPrefix/src/b/b.txt", finder.findResourceFile("withPrefix", "prefix2/b/b.txt"))
|
||||
assertPath("additional-resources/c.txt", finder.findResourceFile("withPrefix", "prefix3/c.txt"))
|
||||
}
|
||||
|
||||
private fun assertPath(expectedPath: String?, file: Path?) {
|
||||
assertEquals(expectedPath, file?.relativeTo(projectDir)?.invariantSeparatorsPathString)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user