From ea9f03e463bc8322522ba858447b868e7e205242 Mon Sep 17 00:00:00 2001 From: Nikolay Chashnikov Date: Fri, 22 Aug 2025 10:52:02 +0200 Subject: [PATCH] [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 --- .idea/modules.xml | 1 + build/bazel-generated-file-list.txt | 1 + .../generator/BUILD.bazel | 19 ++ ...vkit.runtimeModuleRepository.generator.iml | 33 +++ .../src/RuntimeModuleRepositoryGenerator.kt | 194 ++++++++++++++++++ .../generator/src/package-info.java | 5 + .../runtimeModuleRepository/jps/BUILD.bazel | 2 + ...lij.devkit.runtimeModuleRepository.jps.iml | 1 + .../build/RuntimeModuleRepositoryBuilder.kt | 182 +--------------- .../build/RuntimeModuleRepositoryTarget.kt | 3 +- .../build/RuntimeModuleRepositoryCheckers.kt | 3 +- 11 files changed, 262 insertions(+), 182 deletions(-) create mode 100644 plugins/devkit/runtimeModuleRepository/generator/BUILD.bazel create mode 100644 plugins/devkit/runtimeModuleRepository/generator/intellij.devkit.runtimeModuleRepository.generator.iml create mode 100644 plugins/devkit/runtimeModuleRepository/generator/src/RuntimeModuleRepositoryGenerator.kt create mode 100644 plugins/devkit/runtimeModuleRepository/generator/src/package-info.java diff --git a/.idea/modules.xml b/.idea/modules.xml index 198407bc188a..bec586940e06 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -370,6 +370,7 @@ + diff --git a/build/bazel-generated-file-list.txt b/build/bazel-generated-file-list.txt index 49d47ba6e43f..9f5a47b32e66 100644 --- a/build/bazel-generated-file-list.txt +++ b/build/bazel-generated-file-list.txt @@ -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 diff --git a/plugins/devkit/runtimeModuleRepository/generator/BUILD.bazel b/plugins/devkit/runtimeModuleRepository/generator/BUILD.bazel new file mode 100644 index 000000000000..52e524fd08d0 --- /dev/null +++ b/plugins/devkit/runtimeModuleRepository/generator/BUILD.bazel @@ -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 \ No newline at end of file diff --git a/plugins/devkit/runtimeModuleRepository/generator/intellij.devkit.runtimeModuleRepository.generator.iml b/plugins/devkit/runtimeModuleRepository/generator/intellij.devkit.runtimeModuleRepository.generator.iml new file mode 100644 index 000000000000..8e13513fd141 --- /dev/null +++ b/plugins/devkit/runtimeModuleRepository/generator/intellij.devkit.runtimeModuleRepository.generator.iml @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/devkit/runtimeModuleRepository/generator/src/RuntimeModuleRepositoryGenerator.kt b/plugins/devkit/runtimeModuleRepository/generator/src/RuntimeModuleRepositoryGenerator.kt new file mode 100644 index 000000000000..693934bd330a --- /dev/null +++ b/plugins/devkit/runtimeModuleRepository/generator/src/RuntimeModuleRepositoryGenerator.kt @@ -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 { + val descriptors = ArrayList() + generateDescriptorsForModules(descriptors, project) + val libraries = LinkedHashSet() + 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, 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() + val testModulesWithProductionRoots = HashSet() + 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() + 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() + val addedTransitiveLibraryDependencies = HashSet() + + 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() + val processedDummyTestDependencies = HashSet() + 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, + module: JpsModule, + processedDummyTestDependencies: HashSet, + addedTransitiveModuleDependencies: MutableSet, + addedTransitiveLibraryDependencies: MutableSet, + 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) +} diff --git a/plugins/devkit/runtimeModuleRepository/generator/src/package-info.java b/plugins/devkit/runtimeModuleRepository/generator/src/package-info.java new file mode 100644 index 000000000000..aaf5ea5277b5 --- /dev/null +++ b/plugins/devkit/runtimeModuleRepository/generator/src/package-info.java @@ -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; diff --git a/plugins/devkit/runtimeModuleRepository/jps/BUILD.bazel b/plugins/devkit/runtimeModuleRepository/jps/BUILD.bazel index f58ff4f2ea7f..7f4a48155364 100644 --- a/plugins/devkit/runtimeModuleRepository/jps/BUILD.bazel +++ b/plugins/devkit/runtimeModuleRepository/jps/BUILD.bazel @@ -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"] diff --git a/plugins/devkit/runtimeModuleRepository/jps/intellij.devkit.runtimeModuleRepository.jps.iml b/plugins/devkit/runtimeModuleRepository/jps/intellij.devkit.runtimeModuleRepository.jps.iml index 5bd917a44baf..c4e7bd5bc522 100644 --- a/plugins/devkit/runtimeModuleRepository/jps/intellij.devkit.runtimeModuleRepository.jps.iml +++ b/plugins/devkit/runtimeModuleRepository/jps/intellij.devkit.runtimeModuleRepository.jps.iml @@ -33,6 +33,7 @@ + \ No newline at end of file diff --git a/plugins/devkit/runtimeModuleRepository/jps/src/build/RuntimeModuleRepositoryBuilder.kt b/plugins/devkit/runtimeModuleRepository/jps/src/build/RuntimeModuleRepositoryBuilder.kt index cacdd8476978..9a76528a670d 100644 --- a/plugins/devkit/runtimeModuleRepository/jps/src/build/RuntimeModuleRepositoryBuilder.kt +++ b/plugins/devkit/runtimeModuleRepository/jps/src/build/RuntimeModuleRepositoryBuilder.kt @@ -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(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() - - 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 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 { - val descriptors = ArrayList() - generateDescriptorsForModules(descriptors, project) - val libraries = LinkedHashSet() - 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, 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() - val testModulesWithProductionRoots = HashSet() - 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() - 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() - val addedTransitiveLibraryDependencies = HashSet() - - 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() - val processedDummyTestDependencies = HashSet() - 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, - module: JpsModule, - processedDummyTestDependencies: HashSet, - addedTransitiveModuleDependencies: MutableSet, - addedTransitiveLibraryDependencies: MutableSet, - 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 { diff --git a/plugins/devkit/runtimeModuleRepository/jps/src/build/RuntimeModuleRepositoryTarget.kt b/plugins/devkit/runtimeModuleRepository/jps/src/build/RuntimeModuleRepositoryTarget.kt index 277717d3451e..b32fa406a163 100644 --- a/plugins/devkit/runtimeModuleRepository/jps/src/build/RuntimeModuleRepositoryTarget.kt +++ b/plugins/devkit/runtimeModuleRepository/jps/src/build/RuntimeModuleRepositoryTarget.kt @@ -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++ diff --git a/plugins/devkit/runtimeModuleRepository/jps/testSrc/build/RuntimeModuleRepositoryCheckers.kt b/plugins/devkit/runtimeModuleRepository/jps/testSrc/build/RuntimeModuleRepositoryCheckers.kt index ed98e301b560..0843e39f2a1e 100644 --- a/plugins/devkit/runtimeModuleRepository/jps/testSrc/build/RuntimeModuleRepositoryCheckers.kt +++ b/plugins/devkit/runtimeModuleRepository/jps/testSrc/build/RuntimeModuleRepositoryCheckers.kt @@ -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()) } }