[jps build devkit] refactoring: extract code which generates the runtime module repository to a separate module (IJPL-201730)

Currently, the runtime module repository is generated by a plugin inside the JPS build during compilation. Doing the same in Bazel doesn't look like a good option because generating something for all modules in the project contradicts the incremental nature of Bazel. So it's better to invoke generation of the runtime module repository by JPS project configuration inside build scripts. To do that and avoid having dependencies on the JPS build classes inside the build scripts, the code which generates the runtime module repository is moved to a separate module 'intellij.devkit.runtimeModuleRepository.generator'.

GitOrigin-RevId: f2596fd51c1c019d304de36ed93fe163cf519ae6
This commit is contained in:
Nikolay Chashnikov
2025-08-22 16:02:27 +00:00
committed by intellij-monorepo-bot
parent b5fd0cccff
commit ea9f03e463
11 changed files with 262 additions and 182 deletions
+1
View File
@@ -370,6 +370,7 @@
<module fileurl="file://$PROJECT_DIR$/plugins/devkit/intellij.devkit.modules/intellij.devkit.modules.iml" filepath="$PROJECT_DIR$/plugins/devkit/intellij.devkit.modules/intellij.devkit.modules.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/devkit/intellij.devkit.plugin.main.iml" filepath="$PROJECT_DIR$/plugins/devkit/intellij.devkit.plugin.main.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/devkit/intellij.devkit.plugin.main.noKotlin.iml" filepath="$PROJECT_DIR$/plugins/devkit/intellij.devkit.plugin.main.noKotlin.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/devkit/runtimeModuleRepository/generator/intellij.devkit.runtimeModuleRepository.generator.iml" filepath="$PROJECT_DIR$/plugins/devkit/runtimeModuleRepository/generator/intellij.devkit.runtimeModuleRepository.generator.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/devkit/runtimeModuleRepository/jps/intellij.devkit.runtimeModuleRepository.jps.iml" filepath="$PROJECT_DIR$/plugins/devkit/runtimeModuleRepository/jps/intellij.devkit.runtimeModuleRepository.jps.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/devkit/intellij.devkit.scaffolding/intellij.devkit.scaffolding.iml" filepath="$PROJECT_DIR$/plugins/devkit/intellij.devkit.scaffolding/intellij.devkit.scaffolding.iml" />
<module fileurl="file://$PROJECT_DIR$/plugins/devkit/intellij.devkit.smartupdate/intellij.devkit.smartupdate.iml" filepath="$PROJECT_DIR$/plugins/devkit/intellij.devkit.smartupdate/intellij.devkit.smartupdate.iml" />
+1
View File
@@ -779,6 +779,7 @@ plugins/devkit/intellij.kotlin.devkit
plugins/devkit/intellij.kotlin.devkit/k1
plugins/devkit/intellij.kotlin.devkit/k2
plugins/devkit/jps-plugin
plugins/devkit/runtimeModuleRepository/generator
plugins/devkit/runtimeModuleRepository/jps
plugins/eclipse
plugins/eclipse/common-eclipse-util
@@ -0,0 +1,19 @@
### auto-generated section `build intellij.devkit.runtimeModuleRepository.generator` start
load("@rules_jvm//:jvm.bzl", "jvm_library")
jvm_library(
name = "generator",
module_name = "intellij.devkit.runtimeModuleRepository.generator",
visibility = ["//visibility:public"],
srcs = glob(["src/**/*.kt", "src/**/*.java", "src/**/*.form"], allow_empty = True),
kotlinc_opts = "@community//:k11",
deps = [
"@lib//:kotlin-stdlib",
"//platform/util",
"//jps/model-api:model",
"//platform/runtime/repository",
"//jps/model-serialization",
"@lib//:jetbrains-annotations",
]
)
### auto-generated section `build intellij.devkit.runtimeModuleRepository.generator` end
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="5" platform="JVM 11" allPlatforms="JVM [11]" useProjectSettings="false">
<compilerSettings>
<option name="additionalArguments" value="-Xjvm-default=all -opt-in=com.intellij.openapi.util.IntellijInternalApi" />
</compilerSettings>
<compilerArguments>
<stringArguments>
<stringArg name="jvmTarget" arg="11" />
<stringArg name="apiVersion" arg="2.2" />
<stringArg name="languageVersion" arg="2.2" />
</stringArguments>
</compilerArguments>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_11" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" packagePrefix="com.intellij.devkit.runtimeModuleRepository.generator" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="kotlin-stdlib" level="project" />
<orderEntry type="module" module-name="intellij.platform.util" />
<orderEntry type="module" module-name="intellij.platform.jps.model" />
<orderEntry type="module" module-name="intellij.platform.runtime.repository" />
<orderEntry type="module" module-name="intellij.platform.jps.model.serialization" />
<orderEntry type="library" name="jetbrains-annotations" level="project" />
</component>
</module>
@@ -0,0 +1,194 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.runtimeModuleRepository.generator
import com.intellij.devkit.runtimeModuleRepository.generator.RuntimeModuleRepositoryGenerator.GENERATE_DESCRIPTORS_FOR_TEST_MODULES
import com.intellij.devkit.runtimeModuleRepository.generator.RuntimeModuleRepositoryGenerator.enumerateRuntimeDependencies
import com.intellij.platform.runtime.repository.RuntimeModuleId
import com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleDescriptor
import org.jetbrains.jps.model.JpsProject
import org.jetbrains.jps.model.ex.JpsElementBase
import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes
import org.jetbrains.jps.model.java.JpsJavaDependenciesEnumerator
import org.jetbrains.jps.model.java.JpsJavaExtensionService
import org.jetbrains.jps.model.library.JpsLibrary
import org.jetbrains.jps.model.library.JpsOrderRootType
import org.jetbrains.jps.model.module.JpsModule
import org.jetbrains.jps.model.module.JpsModuleDependency
object RuntimeModuleRepositoryGenerator {
/**
* Generates the runtime module descriptors for all modules and libraries in [project].
*/
fun generateRuntimeModuleDescriptors(project: JpsProject, relativizer: (String) -> String): List<RawRuntimeModuleDescriptor> {
val descriptors = ArrayList<RawRuntimeModuleDescriptor>()
generateDescriptorsForModules(descriptors, project)
val libraries = LinkedHashSet<JpsLibrary>()
for (module in project.modules) {
libraries.addAll(enumerateRuntimeDependencies(module).libraries)
}
for (library in libraries) {
val moduleId = getLibraryId(library)
val files = library.getFiles(JpsOrderRootType.COMPILED)
descriptors.add(RawRuntimeModuleDescriptor.create(moduleId.stringId, files.map { relativizer(it.absolutePath) }, emptyList()))
}
return descriptors
}
fun enumerateRuntimeDependencies(module: JpsModule): JpsJavaDependenciesEnumerator {
return JpsJavaExtensionService.dependencies(module).withoutSdk().withoutModuleSourceEntries().runtimeOnly()
}
/**
* Specifies whether descriptors for 'tests' parts of modules should be generated.
*/
const val GENERATE_DESCRIPTORS_FOR_TEST_MODULES: Boolean = true
}
private fun generateDescriptorsForModules(descriptors: MutableList<RawRuntimeModuleDescriptor>, project: JpsProject) {
//it's better to get rid of such modules, but until it's done, we need to have this workaround to avoid duplicating IDs
val productionModulesWithTestRoots = HashSet<String>()
val testModulesWithProductionRoots = HashSet<String>()
val allModuleNames = project.modules.mapTo(HashSet()) { it.name }
for (module in project.modules) {
if (module.name.endsWith(RuntimeModuleId.TESTS_NAME_SUFFIX) && module.hasProductionSources) {
testModulesWithProductionRoots.add(module.name)
}
if ((module.name + RuntimeModuleId.TESTS_NAME_SUFFIX) in allModuleNames && module.hasTestSources) {
productionModulesWithTestRoots.add(module.name)
}
}
fun getRuntimeModuleName(module: JpsModule, tests: Boolean): String {
val moduleName = module.name
if (tests) {
if (moduleName in productionModulesWithTestRoots) {
return moduleName + RuntimeModuleId.TESTS_NAME_SUFFIX + "2"
}
if (!moduleName.endsWith(RuntimeModuleId.TESTS_NAME_SUFFIX)) {
return moduleName + RuntimeModuleId.TESTS_NAME_SUFFIX
}
}
else {
if (moduleName in testModulesWithProductionRoots) {
return moduleName + "2"
}
}
return moduleName
}
for (module in project.modules) {
//if a module doesn't have production sources, it still makes sense to generate a descriptor for it, because it may be used from code
if (!module.name.endsWith(RuntimeModuleId.TESTS_NAME_SUFFIX) || module.hasProductionSources) {
descriptors.add(createProductionPartDescriptor(module, ::getRuntimeModuleName))
}
if (GENERATE_DESCRIPTORS_FOR_TEST_MODULES && module.hasTestSources) {
descriptors.add(createTestPartDescriptor(module, ::getRuntimeModuleName))
}
}
}
private val JpsModule.hasTestSources
get() = sourceRoots.any { it.rootType in JavaModuleSourceRootTypes.TESTS }
private val JpsModule.hasProductionSources
get() = sourceRoots.any { it.rootType in JavaModuleSourceRootTypes.PRODUCTION }
private fun createProductionPartDescriptor(module: JpsModule, runtimeModuleNameGenerator: (JpsModule, Boolean) -> String): RawRuntimeModuleDescriptor {
val dependencies = LinkedHashSet<String>()
enumerateRuntimeDependencies(module).productionOnly().processModuleAndLibraries(
{ dependencies.add(runtimeModuleNameGenerator(it, false)) },
{ dependencies.add(getLibraryId(it).stringId) }
)
val resourcePaths = if (module.hasProductionSources) listOf("production/${module.name}") else emptyList()
return RawRuntimeModuleDescriptor.create(runtimeModuleNameGenerator(module, false), resourcePaths, dependencies.toList())
}
/**
* Generates a descriptor for [module]'s tests.
* In JPS, tests are added to classpath transitively. For example, if module 'a' depends on 'b', and 'b' depends on 'c', then tests of
* module 'c' will be added to test classpath of module 'a', even if module 'b' has no test sources.
* If we generate synthetic descriptors for tests of each module, even if it doesn't have test sources, the size of the module repository
* will increase a lot. So here we add such transitive test dependencies directly to the module descriptors. To avoid adding too many
* dependencies, we add only those which aren't already available as transitive dependencies of explicitly added dependencies.
*/
private fun createTestPartDescriptor(module: JpsModule, runtimeModuleNameGenerator: (JpsModule, Boolean) -> String): RawRuntimeModuleDescriptor {
val addedTransitiveModuleDependencies = HashSet<JpsModule>()
val addedTransitiveLibraryDependencies = HashSet<JpsLibrary>()
fun JpsJavaDependenciesEnumerator.collectTransitiveDependencies() {
recursively().satisfying { dependency ->
(dependency as? JpsModuleDependency)?.module !in addedTransitiveModuleDependencies
}.processModuleAndLibraries(
{ addedTransitiveModuleDependencies.add(it) },
{ addedTransitiveLibraryDependencies.add(it) }
)
}
JpsJavaExtensionService.dependencies(module).runtimeOnly().processModules { directDependency ->
if (directDependency.hasTestSources) {
JpsJavaExtensionService.dependencies(module).withoutSdk().runtimeOnly().collectTransitiveDependencies()
}
}
JpsJavaExtensionService.dependencies(module).withoutSdk().runtimeOnly().productionOnly().collectTransitiveDependencies()
addedTransitiveModuleDependencies.remove(module)
val dependencies = LinkedHashSet<String>()
val processedDummyTestDependencies = HashSet<String>()
if (module.hasProductionSources) {
dependencies.add(runtimeModuleNameGenerator(module, false))
}
enumerateRuntimeDependencies(module).processModuleAndLibraries(
{ dependency ->
if (dependency.hasProductionSources) {
dependencies.add(runtimeModuleNameGenerator(dependency, false))
}
addTestDependency(dependencies, dependency, processedDummyTestDependencies, addedTransitiveModuleDependencies,
addedTransitiveLibraryDependencies, runtimeModuleNameGenerator)
},
{ dependencies.add(getLibraryId(it).stringId) }
)
val resourcePaths = if (module.hasTestSources) listOf("test/${module.name}") else emptyList()
return RawRuntimeModuleDescriptor.create(runtimeModuleNameGenerator(module, true), resourcePaths, dependencies.toList())
}
private fun addTestDependency(
result: MutableCollection<String>,
module: JpsModule,
processedDummyTestDependencies: HashSet<String>,
addedTransitiveModuleDependencies: MutableSet<JpsModule>,
addedTransitiveLibraryDependencies: MutableSet<JpsLibrary>,
runtimeModuleNameGenerator: (JpsModule, Boolean) -> String
) {
if (module.hasTestSources) {
result.add(runtimeModuleNameGenerator(module, true))
return
}
if (!processedDummyTestDependencies.add(module.name)) {
return
}
enumerateRuntimeDependencies(module).processModuleAndLibraries(
{
addTestDependency(result, it, processedDummyTestDependencies, addedTransitiveModuleDependencies,
addedTransitiveLibraryDependencies, runtimeModuleNameGenerator)
},
{
if (addedTransitiveLibraryDependencies.add(it)) {
result.add(getLibraryId(it).stringId)
}
}
)
}
private fun getLibraryId(library: JpsLibrary): RuntimeModuleId {
var name = library.name
val element = (library as JpsElementBase<*>).parent.parent
if (element is JpsModule) {
val files = library.getFiles(JpsOrderRootType.COMPILED)
if (name.startsWith("#") && files.size == 1) {
name = files[0].name
}
return RuntimeModuleId.moduleLibrary((element as JpsModule).name, name)
}
return RuntimeModuleId.projectLibrary(name)
}
@@ -0,0 +1,5 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@Internal
package com.intellij.devkit.runtimeModuleRepository.generator;
import org.jetbrains.annotations.ApiStatus.Internal;
@@ -30,6 +30,7 @@ jvm_library(
"//platform/runtime/repository",
"@lib//:kotlin-stdlib",
"//jps/model-serialization",
"//plugins/devkit/runtimeModuleRepository/generator",
"@lib//:hash4j",
],
runtime_deps = [":jps_resources"]
@@ -51,6 +52,7 @@ jvm_library(
"//platform/testFramework:testFramework_test_lib",
"//jps/jps-builders:build-tests_test_lib",
"//jps/model-serialization",
"//plugins/devkit/runtimeModuleRepository/generator",
"@lib//:hash4j",
],
runtime_deps = [":jps_resources"]
@@ -33,6 +33,7 @@
<orderEntry type="module" module-name="intellij.platform.testFramework" scope="TEST" />
<orderEntry type="module" module-name="intellij.platform.jps.build.tests" scope="TEST" />
<orderEntry type="module" module-name="intellij.platform.jps.model.serialization" />
<orderEntry type="module" module-name="intellij.devkit.runtimeModuleRepository.generator" />
<orderEntry type="library" name="hash4j" level="project" />
</component>
</module>
@@ -1,12 +1,12 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.runtimeModuleRepository.jps.build
import com.intellij.devkit.runtimeModuleRepository.generator.RuntimeModuleRepositoryGenerator
import com.intellij.devkit.runtimeModuleRepository.jps.build.RuntimeModuleRepositoryBuildConstants.COMPACT_REPOSITORY_FILE_NAME
import com.intellij.devkit.runtimeModuleRepository.jps.build.RuntimeModuleRepositoryBuildConstants.GENERATOR_VERSION
import com.intellij.devkit.runtimeModuleRepository.jps.build.RuntimeModuleRepositoryBuildConstants.JAR_REPOSITORY_FILE_NAME
import com.intellij.devkit.runtimeModuleRepository.jps.impl.DevkitRuntimeModuleRepositoryJpsBundle
import com.intellij.openapi.diagnostic.logger
import com.intellij.platform.runtime.repository.RuntimeModuleId
import com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleDescriptor
import com.intellij.platform.runtime.repository.serialization.RuntimeModuleRepositorySerialization
import com.intellij.platform.runtime.repository.serialization.impl.CompactFileWriter
@@ -20,16 +20,7 @@ import org.jetbrains.jps.incremental.TargetBuilder
import org.jetbrains.jps.incremental.messages.BuildMessage
import org.jetbrains.jps.incremental.messages.CompilerMessage
import org.jetbrains.jps.incremental.messages.ProgressMessage
import org.jetbrains.jps.incremental.relativizer.PathRelativizerService
import org.jetbrains.jps.model.JpsProject
import org.jetbrains.jps.model.ex.JpsElementBase
import org.jetbrains.jps.model.java.JavaModuleSourceRootTypes
import org.jetbrains.jps.model.java.JpsJavaDependenciesEnumerator
import org.jetbrains.jps.model.java.JpsJavaExtensionService
import org.jetbrains.jps.model.library.JpsLibrary
import org.jetbrains.jps.model.library.JpsOrderRootType
import org.jetbrains.jps.model.module.JpsModule
import org.jetbrains.jps.model.module.JpsModuleDependency
import org.jetbrains.jps.util.JpsPathUtil
import java.io.IOException
import java.nio.file.Path
@@ -41,15 +32,7 @@ import kotlin.system.measureTimeMillis
internal class RuntimeModuleRepositoryBuilder
: TargetBuilder<BuildRootDescriptor, RuntimeModuleRepositoryTarget>(listOf(RuntimeModuleRepositoryTarget)) {
companion object {
/**
* Specifies whether descriptors for 'tests' parts of modules should be generated.
*/
const val GENERATE_DESCRIPTORS_FOR_TEST_MODULES = true
private val LOG = logger<RuntimeModuleRepositoryBuilder>()
internal fun enumerateRuntimeDependencies(module: JpsModule): JpsJavaDependenciesEnumerator {
return JpsJavaExtensionService.dependencies(module).withoutSdk().withoutModuleSourceEntries().runtimeOnly()
}
}
override fun build(target: RuntimeModuleRepositoryTarget,
@@ -65,7 +48,7 @@ internal class RuntimeModuleRepositoryBuilder
val descriptors: List<RawRuntimeModuleDescriptor>
context.processMessage(ProgressMessage(DevkitRuntimeModuleRepositoryJpsBundle.message("progress.message.generating.intellij.modules.repository"), BuildTargetChunk(setOf(target))))
val timeToCreateDescriptors = measureTimeMillis {
descriptors = createDescriptors(project, context.projectDescriptor.dataManager.relativizer)
descriptors = RuntimeModuleRepositoryGenerator.generateRuntimeModuleDescriptors(project, { context.projectDescriptor.dataManager.relativizer.toRelative(it) } )
}
LOG.info("${descriptors.size} descriptors are created in ${timeToCreateDescriptors}ms")
@@ -103,167 +86,6 @@ internal class RuntimeModuleRepositoryBuilder
processMessage(CompilerMessage("intellij-runtime-repository", BuildMessage.Kind.ERROR, message))
}
private fun createDescriptors(project: JpsProject, relativizer: PathRelativizerService): List<RawRuntimeModuleDescriptor> {
val descriptors = ArrayList<RawRuntimeModuleDescriptor>()
generateDescriptorsForModules(descriptors, project)
val libraries = LinkedHashSet<JpsLibrary>()
for (module in project.modules) {
libraries.addAll(enumerateRuntimeDependencies(module).libraries)
}
for (library in libraries) {
val moduleId = getLibraryId(library)
val files = library.getFiles(JpsOrderRootType.COMPILED)
descriptors.add(RawRuntimeModuleDescriptor.create(moduleId.stringId, files.map { relativizer.toRelative(it.absolutePath) }, emptyList()))
}
return descriptors
}
private fun generateDescriptorsForModules(descriptors: MutableList<RawRuntimeModuleDescriptor>, project: JpsProject) {
//it's better to get rid of such modules, but until it's done, we need to have this workaround to avoid duplicating IDs
val productionModulesWithTestRoots = HashSet<String>()
val testModulesWithProductionRoots = HashSet<String>()
val allModuleNames = project.modules.mapTo(HashSet()) { it.name }
for (module in project.modules) {
if (module.name.endsWith(RuntimeModuleId.TESTS_NAME_SUFFIX) && module.hasProductionSources) {
testModulesWithProductionRoots.add(module.name)
}
if ((module.name + RuntimeModuleId.TESTS_NAME_SUFFIX) in allModuleNames && module.hasTestSources) {
productionModulesWithTestRoots.add(module.name)
}
}
fun getRuntimeModuleName(module: JpsModule, tests: Boolean): String {
val moduleName = module.name
if (tests) {
if (moduleName in productionModulesWithTestRoots) {
return moduleName + RuntimeModuleId.TESTS_NAME_SUFFIX + "2"
}
if (!moduleName.endsWith(RuntimeModuleId.TESTS_NAME_SUFFIX)) {
return moduleName + RuntimeModuleId.TESTS_NAME_SUFFIX
}
}
else {
if (moduleName in testModulesWithProductionRoots) {
return moduleName + "2"
}
}
return moduleName
}
for (module in project.modules) {
//if a module doesn't have production sources, it still makes sense to generate a descriptor for it, because it may be used from code
if (!module.name.endsWith(RuntimeModuleId.TESTS_NAME_SUFFIX) || module.hasProductionSources) {
descriptors.add(createProductionPartDescriptor(module, ::getRuntimeModuleName))
}
if (GENERATE_DESCRIPTORS_FOR_TEST_MODULES && module.hasTestSources) {
descriptors.add(createTestPartDescriptor(module, ::getRuntimeModuleName))
}
}
}
private val JpsModule.hasTestSources
get() = sourceRoots.any { it.rootType in JavaModuleSourceRootTypes.TESTS }
private val JpsModule.hasProductionSources
get() = sourceRoots.any { it.rootType in JavaModuleSourceRootTypes.PRODUCTION }
private fun createProductionPartDescriptor(module: JpsModule, runtimeModuleNameGenerator: (JpsModule, Boolean) -> String): RawRuntimeModuleDescriptor {
val dependencies = LinkedHashSet<String>()
enumerateRuntimeDependencies(module).productionOnly().processModuleAndLibraries(
{ dependencies.add(runtimeModuleNameGenerator(it, false)) },
{ dependencies.add(getLibraryId(it).stringId) }
)
val resourcePaths = if (module.hasProductionSources) listOf("production/${module.name}") else emptyList()
return RawRuntimeModuleDescriptor.create(runtimeModuleNameGenerator(module, false), resourcePaths, dependencies.toList())
}
/**
* Generates a descriptor for [module]'s tests.
* In JPS, tests are added to classpath transitively. For example, if module 'a' depends on 'b', and 'b' depends on 'c', then tests of
* module 'c' will be added to test classpath of module 'a', even if module 'b' has no test sources.
* If we generate synthetic descriptors for tests of each module, even if it doesn't have test sources, the size of the module repository
* will increase a lot. So here we add such transitive test dependencies directly to the module descriptors. To avoid adding too many
* dependencies, we add only those which aren't already available as transitive dependencies of explicitly added dependencies.
*/
private fun createTestPartDescriptor(module: JpsModule, runtimeModuleNameGenerator: (JpsModule, Boolean) -> String): RawRuntimeModuleDescriptor {
val addedTransitiveModuleDependencies = HashSet<JpsModule>()
val addedTransitiveLibraryDependencies = HashSet<JpsLibrary>()
fun JpsJavaDependenciesEnumerator.collectTransitiveDependencies() {
recursively().satisfying { dependency ->
(dependency as? JpsModuleDependency)?.module !in addedTransitiveModuleDependencies
}.processModuleAndLibraries(
{ addedTransitiveModuleDependencies.add(it) },
{ addedTransitiveLibraryDependencies.add(it) }
)
}
JpsJavaExtensionService.dependencies(module).runtimeOnly().processModules { directDependency ->
if (directDependency.hasTestSources) {
JpsJavaExtensionService.dependencies(module).withoutSdk().runtimeOnly().collectTransitiveDependencies()
}
}
JpsJavaExtensionService.dependencies(module).withoutSdk().runtimeOnly().productionOnly().collectTransitiveDependencies()
addedTransitiveModuleDependencies.remove(module)
val dependencies = LinkedHashSet<String>()
val processedDummyTestDependencies = HashSet<String>()
if (module.hasProductionSources) {
dependencies.add(runtimeModuleNameGenerator(module, false))
}
enumerateRuntimeDependencies(module).processModuleAndLibraries(
{ dependency ->
if (dependency.hasProductionSources) {
dependencies.add(runtimeModuleNameGenerator(dependency, false))
}
addTestDependency(dependencies, dependency, processedDummyTestDependencies, addedTransitiveModuleDependencies,
addedTransitiveLibraryDependencies, runtimeModuleNameGenerator)
},
{ dependencies.add(getLibraryId(it).stringId) }
)
val resourcePaths = if (module.hasTestSources) listOf("test/${module.name}") else emptyList()
return RawRuntimeModuleDescriptor.create(runtimeModuleNameGenerator(module, true), resourcePaths, dependencies.toList())
}
private fun addTestDependency(result: MutableCollection<String>,
module: JpsModule,
processedDummyTestDependencies: HashSet<String>,
addedTransitiveModuleDependencies: MutableSet<JpsModule>,
addedTransitiveLibraryDependencies: MutableSet<JpsLibrary>,
runtimeModuleNameGenerator: (JpsModule, Boolean) -> String) {
if (module.hasTestSources) {
result.add(runtimeModuleNameGenerator(module, true))
return
}
if (!processedDummyTestDependencies.add(module.name)) {
return
}
enumerateRuntimeDependencies(module).processModuleAndLibraries(
{
addTestDependency(result, it, processedDummyTestDependencies, addedTransitiveModuleDependencies,
addedTransitiveLibraryDependencies, runtimeModuleNameGenerator)
},
{
if (addedTransitiveLibraryDependencies.add(it)) {
result.add(getLibraryId(it).stringId)
}
}
)
}
private fun getLibraryId(library: JpsLibrary): RuntimeModuleId {
var name = library.name
val element = (library as JpsElementBase<*>).parent.parent
if (element is JpsModule) {
val files = library.getFiles(JpsOrderRootType.COMPILED)
if (name.startsWith("#") && files.size == 1) {
name = files[0].name
}
return RuntimeModuleId.moduleLibrary((element as JpsModule).name, name)
}
return RuntimeModuleId.projectLibrary(name)
}
override fun getPresentableName(): String {
@@ -4,6 +4,7 @@
package com.intellij.devkit.runtimeModuleRepository.jps.build
import com.dynatrace.hash4j.hashing.HashSink
import com.intellij.devkit.runtimeModuleRepository.generator.RuntimeModuleRepositoryGenerator
import com.intellij.devkit.runtimeModuleRepository.jps.build.RuntimeModuleRepositoryBuildConstants.COMPACT_REPOSITORY_FILE_NAME
import com.intellij.devkit.runtimeModuleRepository.jps.build.RuntimeModuleRepositoryBuildConstants.JAR_REPOSITORY_FILE_NAME
import com.intellij.devkit.runtimeModuleRepository.jps.impl.DevkitRuntimeModuleRepositoryJpsBundle
@@ -100,7 +101,7 @@ internal class RuntimeModuleRepositoryTarget(
hash.putInt(sourceRoots.size)
var counter = 0
RuntimeModuleRepositoryBuilder.enumerateRuntimeDependencies(module).processModuleAndLibraries(
RuntimeModuleRepositoryGenerator.enumerateRuntimeDependencies(module).processModuleAndLibraries(
{
hash.putString(it.name)
counter++
@@ -1,6 +1,7 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.devkit.runtimeModuleRepository.jps.build
import com.intellij.devkit.runtimeModuleRepository.generator.RuntimeModuleRepositoryGenerator
import com.intellij.platform.runtime.repository.RuntimeModuleId
import com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleDescriptor
import com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleRepositoryData
@@ -40,7 +41,7 @@ class RawDescriptorListBuilder {
fun testDescriptor(id: String,
vararg dependencies: String,
resourceDirName: String = id.removeSuffix(RuntimeModuleId.TESTS_NAME_SUFFIX)) {
if (RuntimeModuleRepositoryBuilder.GENERATE_DESCRIPTORS_FOR_TEST_MODULES) {
if (RuntimeModuleRepositoryGenerator.GENERATE_DESCRIPTORS_FOR_TEST_MODULES) {
descriptor(id, listOf("test/$resourceDirName"), dependencies.asList())
}
}