mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[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:
committed by
intellij-monorepo-bot
parent
b5fd0cccff
commit
ea9f03e463
Generated
+1
@@ -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" />
|
||||
|
||||
@@ -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
|
||||
+33
@@ -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>
|
||||
+194
@@ -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"]
|
||||
|
||||
+1
@@ -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>
|
||||
+2
-180
@@ -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 {
|
||||
|
||||
+2
-1
@@ -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++
|
||||
|
||||
+2
-1
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user