IJPL-234358 refactor: use RuntimeModuleId instance instead of String in runtime module repository classes

This is needed to add `namespace` property in RuntimeModuleId.

GitOrigin-RevId: 817b800f462a95f093049349f7b161947c577e3e
This commit is contained in:
Nikolay Chashnikov
2026-02-12 20:37:58 +00:00
committed by intellij-monorepo-bot
parent 46cef88f37
commit fe76e2f705
23 changed files with 297 additions and 200 deletions
@@ -303,9 +303,9 @@ internal class ModuleBasedProductLoadingStrategy(internal val moduleRepository:
*/
val descriptors = ArrayList<RuntimeModuleDescriptor>()
descriptors.add(mainModule)
repositoryData.allIds.asSequence()
.filter { it != mainModuleId }
.mapTo(descriptors) { moduleRepository.getModule(RuntimeModuleId.raw(it)) }
repositoryData.allModuleIds.asSequence()
.filter { it != mainModule.moduleId }
.mapTo(descriptors) { moduleRepository.getModule(it) }
val moduleGroup = CustomPluginModuleGroup(descriptors, mainModule)
loadPluginDescriptorFromRuntimeModule(
pluginModuleGroup = moduleGroup,
@@ -110,15 +110,15 @@ internal fun generateCrossPlatformRepository(distAllPath: Path, osSpecificDistPa
}
RuntimeModuleRepositorySerialization.loadFromCompactFile(repositoryFile)
}
val commonIds = repositories.map { it.allIds }.reduce { a, b -> a.intersect(b) }
val commonIds = repositories.map { it.allModuleIds }.reduce { a, b -> a.intersect(b) }
val commonDescriptors = ArrayList<RawRuntimeModuleDescriptor>()
for (moduleId in commonIds) {
val descriptors = repositories.map { it.findDescriptor(moduleId)!! }
val commonResourcePaths = descriptors.map { it.resourcePaths.toSet() }.reduce { a, b -> a.intersect(b) }
val commonDependencies = descriptors.first().dependencies
val commonDependencies = descriptors.first().dependencyIds
for (descriptor in descriptors) {
if (descriptor.dependencies != commonDependencies) {
context.messages.logErrorAndThrow("Cannot generate runtime module repository for cross-platform distribution: different dependencies for module '$moduleId', ${descriptor.dependencies} and $commonDependencies")
if (descriptor.dependencyIds != commonDependencies) {
context.messages.logErrorAndThrow("Cannot generate runtime module repository for cross-platform distribution: different dependencies for module '${moduleId.presentableName}', ${descriptor.dependencyIds} and $commonDependencies")
}
}
commonDescriptors.add(RawRuntimeModuleDescriptor.create(moduleId, commonResourcePaths.toList(), commonDependencies))
@@ -188,15 +188,15 @@ private suspend fun generateRepositoryForDistribution(
resourcePathsSchema = DistributionResourcePathsSchema(moduleProductionPaths, moduleTestPaths, libraryPaths),
).map { descriptor ->
//this is a temporary workaround to skip optional dependencies which aren't included in the distribution
val dependenciesToSkip = dependenciesToSkip[descriptor.id] ?: return@map descriptor
val actualDependencies = descriptor.dependencies.filterNot { it in dependenciesToSkip}
RawRuntimeModuleDescriptor.create(descriptor.id, descriptor.resourcePaths, actualDependencies)
val dependenciesToSkip = dependenciesToSkip[descriptor.moduleId] ?: return@map descriptor
val actualDependencies = descriptor.dependencyIds.filterNot { it in dependenciesToSkip}
RawRuntimeModuleDescriptor.create(descriptor.moduleId, descriptor.resourcePaths, actualDependencies)
}
val errors = ArrayList<String>()
val errorReporter = object : RuntimeModuleRepositoryValidator.ErrorReporter {
override fun reportDuplicatingId(moduleId: String) {
errors.add("Module '$moduleId' is included several times in the runtime module repository")
override fun reportDuplicatingId(moduleId: RuntimeModuleId) {
errors.add("Module '${moduleId.presentableName}' is included several times in the runtime module repository")
}
}
RuntimeModuleRepositoryValidator.validate(distDescriptors, errorReporter)
@@ -344,7 +344,7 @@ private fun collectTransitiveDependencies(moduleIds: Collection<RuntimeModuleId>
if (result.add(moduleId)) {
val descriptor = descriptorMap[moduleId]
if (descriptor != null) {
collectTransitiveDependencies(descriptor.dependencies.map { RuntimeModuleId.raw(it) }, descriptorMap, result)
collectTransitiveDependencies(descriptor.dependencyIds, descriptorMap, result)
}
}
}
@@ -356,5 +356,5 @@ const val MODULE_DESCRIPTORS_COMPACT_PATH: String = "$RUNTIME_REPOSITORY_MODULES
private val dependenciesToSkip = mapOf(
//may be removed when IJPL-125 is fixed
"intellij.platform.buildScripts.downloader" to setOf("lib.zstd-jni"),
RuntimeModuleId.module("intellij.platform.buildScripts.downloader") to setOf(RuntimeModuleId.projectLibrary("zstd-jni")),
)
@@ -194,13 +194,12 @@ internal class RuntimeModuleRepositoryChecker private constructor(
repository.getModule(moduleId).resourceRootPaths.map { it to moduleId }
}.groupBy({ it.first }, { it.second })
for (rawModuleId in moduleRepositoryData.allIds) {
val moduleId = RuntimeModuleId.raw(rawModuleId)
if (rawModuleId.startsWith(RuntimeModuleId.LIB_NAME_PREFIX)) {
for (moduleId in moduleRepositoryData.allModuleIds) {
if (moduleId.stringId.startsWith(RuntimeModuleId.LIB_NAME_PREFIX)) {
//additional libraries shouldn't cause problems because their resources should not be loaded unless they are requested from modules
continue
}
val module = context.outputProvider.findModule(rawModuleId)
val module = context.outputProvider.findModule(moduleId.stringId)
if (module != null && hasModuleOutputPath(module = module, relativePath = "${module.name}.xml", outputProvider = context.outputProvider)) {
// such a descriptor indicates that it's a module in plugin model V2, and its ClassLoader ignores classes from irrelevant packages,
// so including its JAR to classpath should not cause problems
@@ -4,8 +4,8 @@ package com.intellij.platform.runtime.product.serialization
import com.intellij.platform.runtime.product.RuntimeModuleLoadingRule
import com.intellij.platform.runtime.product.serialization.impl.loadPluginModules
import com.intellij.platform.runtime.repository.RuntimeModuleId
import com.intellij.platform.runtime.repository.createModuleDescriptor
import com.intellij.platform.runtime.repository.createRepository
import com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleDescriptor
import com.intellij.platform.runtime.repository.writePluginXml
import com.intellij.testFramework.rules.TempDirectoryExtension
import org.junit.jupiter.api.Assertions.assertEquals
@@ -22,7 +22,7 @@ class PluginXmlReaderTest {
fun `single module`() {
val repository = createRepository(
tempDirectory.rootPath,
RawRuntimeModuleDescriptor.create("plugin.main", listOf("plugin"), emptyList()),
createModuleDescriptor("plugin.main", listOf("plugin"), emptyList()),
)
writePluginXml(tempDirectory.rootPath / "plugin",
"""
@@ -42,12 +42,12 @@ class PluginXmlReaderTest {
fun `multiple modules`() {
val repository = createRepository(
tempDirectory.rootPath,
RawRuntimeModuleDescriptor.create("plugin.main", listOf("plugin"), emptyList()),
RawRuntimeModuleDescriptor.create("plugin.optional", emptyList(), listOf("plugin.main")),
RawRuntimeModuleDescriptor.create("plugin.optional.explicit", emptyList(), listOf("plugin.main")),
RawRuntimeModuleDescriptor.create("plugin.on_demand", emptyList(), emptyList()),
RawRuntimeModuleDescriptor.create("plugin.required", emptyList(), emptyList()),
RawRuntimeModuleDescriptor.create("plugin.embedded", emptyList(), emptyList()),
createModuleDescriptor("plugin.main", listOf("plugin"), emptyList()),
createModuleDescriptor("plugin.optional", emptyList(), listOf("plugin.main")),
createModuleDescriptor("plugin.optional.explicit", emptyList(), listOf("plugin.main")),
createModuleDescriptor("plugin.on_demand", emptyList(), emptyList()),
createModuleDescriptor("plugin.required", emptyList(), emptyList()),
createModuleDescriptor("plugin.embedded", emptyList(), emptyList()),
)
@Suppress("XmlUnusedNamespaceDeclaration")
writePluginXml(tempDirectory.rootPath / "plugin",
@@ -6,8 +6,8 @@ import com.intellij.platform.runtime.product.RuntimeModuleLoadingRule
import com.intellij.platform.runtime.product.impl.ServiceModuleMapping
import com.intellij.platform.runtime.repository.MalformedRepositoryException
import com.intellij.platform.runtime.repository.RuntimeModuleId
import com.intellij.platform.runtime.repository.createModuleDescriptor
import com.intellij.platform.runtime.repository.createRepository
import com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleDescriptor
import com.intellij.platform.runtime.repository.writePluginXml
import com.intellij.platform.runtime.repository.xml
import com.intellij.testFramework.rules.TempDirectoryExtension
@@ -30,9 +30,9 @@ class ProductModulesLoaderTest {
@Test
fun simple() {
val repository = createRepository(tempDirectory.rootPath,
RawRuntimeModuleDescriptor.create("util", emptyList(), emptyList()),
RawRuntimeModuleDescriptor.create("root", emptyList(), listOf("util")),
RawRuntimeModuleDescriptor.create("plugin", listOf("plugin"), emptyList()),
createModuleDescriptor("util", emptyList(), emptyList()),
createModuleDescriptor("root", emptyList(), listOf("util")),
createModuleDescriptor("plugin", listOf("plugin"), emptyList()),
)
writePluginXmlWithModules(tempDirectory.rootPath / "plugin", "<idea-plugin><id>plugin</id></idea-plugin>")
val xml = generateProductModulesWithPlugin()
@@ -53,10 +53,10 @@ class ProductModulesLoaderTest {
@Test
fun `optional modules in main module group`() {
val repository = createRepository(tempDirectory.rootPath,
RawRuntimeModuleDescriptor.create("util", emptyList(), emptyList()),
RawRuntimeModuleDescriptor.create("root", emptyList(), emptyList()),
RawRuntimeModuleDescriptor.create("required", emptyList(), emptyList()),
RawRuntimeModuleDescriptor.create("optional", emptyList(), listOf("root")),
createModuleDescriptor("util", emptyList(), emptyList()),
createModuleDescriptor("root", emptyList(), emptyList()),
createModuleDescriptor("required", emptyList(), emptyList()),
createModuleDescriptor("optional", emptyList(), listOf("root")),
)
val xml = directoryContent {
xml(FILE_NAME, """
@@ -87,9 +87,9 @@ class ProductModulesLoaderTest {
fun `multiple modules in plugin module group`() {
val repository = createRepository(
tempDirectory.rootPath,
RawRuntimeModuleDescriptor.create("root", emptyList(), emptyList()),
RawRuntimeModuleDescriptor.create("plugin", listOf("plugin"), emptyList()),
RawRuntimeModuleDescriptor.create("optional", emptyList(), listOf("plugin")),
createModuleDescriptor("root", emptyList(), emptyList()),
createModuleDescriptor("plugin", listOf("plugin"), emptyList()),
createModuleDescriptor("optional", emptyList(), listOf("plugin")),
)
writePluginXmlWithModules(tempDirectory.rootPath / "plugin", "plugin", "optional", "unknown")
@@ -110,9 +110,9 @@ class ProductModulesLoaderTest {
fun `unresolved plugin module`() {
val repository = createRepository(
tempDirectory.rootPath,
RawRuntimeModuleDescriptor.create("root", emptyList(), emptyList()),
RawRuntimeModuleDescriptor.create("plugin", listOf("plugin"), listOf("plugin.util")),
RawRuntimeModuleDescriptor.create("plugin.util", emptyList(), listOf("unresolved.module")),
createModuleDescriptor("root", emptyList(), emptyList()),
createModuleDescriptor("plugin", listOf("plugin"), listOf("plugin.util")),
createModuleDescriptor("plugin.util", emptyList(), listOf("unresolved.module")),
)
writePluginXmlWithModules(tempDirectory.rootPath / "plugin", "plugin")
val xml = generateProductModulesWithPlugin()
@@ -132,14 +132,14 @@ class ProductModulesLoaderTest {
fun `enable plugin modules in relevant modes`() {
val repository = createRepository(
tempDirectory.rootPath,
RawRuntimeModuleDescriptor.create("root", emptyList(), emptyList()),
RawRuntimeModuleDescriptor.create("intellij.platform.frontend.split", emptyList(), emptyList()),
RawRuntimeModuleDescriptor.create("intellij.platform.backend", emptyList(), emptyList()),
RawRuntimeModuleDescriptor.create("intellij.platform.monolith", emptyList(), listOf("intellij.platform.backend")),
RawRuntimeModuleDescriptor.create("plugin", listOf("plugin"), emptyList()),
RawRuntimeModuleDescriptor.create("plugin.common", emptyList(), listOf("plugin")),
RawRuntimeModuleDescriptor.create("plugin.frontend", emptyList(), listOf("plugin", "intellij.platform.frontend.split")),
RawRuntimeModuleDescriptor.create("plugin.localIde", emptyList(), listOf("plugin", "intellij.platform.monolith")),
createModuleDescriptor("root", emptyList(), emptyList()),
createModuleDescriptor("intellij.platform.frontend.split", emptyList(), emptyList()),
createModuleDescriptor("intellij.platform.backend", emptyList(), emptyList()),
createModuleDescriptor("intellij.platform.monolith", emptyList(), listOf("intellij.platform.backend")),
createModuleDescriptor("plugin", listOf("plugin"), emptyList()),
createModuleDescriptor("plugin.common", emptyList(), listOf("plugin")),
createModuleDescriptor("plugin.frontend", emptyList(), listOf("plugin", "intellij.platform.frontend.split")),
createModuleDescriptor("plugin.localIde", emptyList(), listOf("plugin", "intellij.platform.monolith")),
)
writePluginXmlWithModules(tempDirectory.rootPath / "plugin", "plugin", "plugin.common", "plugin.frontend", "plugin.localIde")
@@ -162,10 +162,10 @@ class ProductModulesLoaderTest {
fun inclusion() {
val repository = createRepository(
tempDirectory.rootPath,
RawRuntimeModuleDescriptor.create("root", listOf("root"), emptyList()),
RawRuntimeModuleDescriptor.create("common.plugin", listOf("common.plugin"), emptyList()),
RawRuntimeModuleDescriptor.create("additional", emptyList(), emptyList()),
RawRuntimeModuleDescriptor.create("plugin", listOf("plugin"), emptyList()),
createModuleDescriptor("root", listOf("root"), emptyList()),
createModuleDescriptor("common.plugin", listOf("common.plugin"), emptyList()),
createModuleDescriptor("additional", emptyList(), emptyList()),
createModuleDescriptor("plugin", listOf("plugin"), emptyList()),
)
writePluginXmlWithModules(tempDirectory.rootPath.resolve("common.plugin"), "common")
writePluginXmlWithModules(tempDirectory.rootPath.resolve("plugin"), "plugin")
@@ -198,10 +198,10 @@ class ProductModulesLoaderTest {
fun `inclusion without some modules`() {
val repository = createRepository(
tempDirectory.rootPath,
RawRuntimeModuleDescriptor.create("root", listOf("root"), emptyList()),
RawRuntimeModuleDescriptor.create("additional", emptyList(), emptyList()),
RawRuntimeModuleDescriptor.create("plugin", listOf("plugin"), emptyList()),
RawRuntimeModuleDescriptor.create("plugin2", listOf("plugin2"), emptyList()),
createModuleDescriptor("root", listOf("root"), emptyList()),
createModuleDescriptor("additional", emptyList(), emptyList()),
createModuleDescriptor("plugin", listOf("plugin"), emptyList()),
createModuleDescriptor("plugin2", listOf("plugin2"), emptyList()),
)
writePluginXmlWithModules(tempDirectory.rootPath.resolve("plugin"), "plugin")
writePluginXmlWithModules(tempDirectory.rootPath.resolve("plugin2"), "plugin2")
@@ -233,11 +233,11 @@ class ProductModulesLoaderTest {
fun `service module mapping`() {
val repository = createRepository(
tempDirectory.rootPath,
RawRuntimeModuleDescriptor.create("root", listOf("root"), emptyList()),
RawRuntimeModuleDescriptor.create("additional1", emptyList(), emptyList()),
RawRuntimeModuleDescriptor.create("lib.common", emptyList(), emptyList()),
RawRuntimeModuleDescriptor.create("plugin1", listOf("plugin1"), listOf("additional1", "lib.common")),
RawRuntimeModuleDescriptor.create("plugin2", listOf("plugin2"), listOf("lib.common")),
createModuleDescriptor("root", listOf("root"), emptyList()),
createModuleDescriptor("additional1", emptyList(), emptyList()),
createModuleDescriptor("lib.common", emptyList(), emptyList()),
createModuleDescriptor("plugin1", listOf("plugin1"), listOf("additional1", "lib.common")),
createModuleDescriptor("plugin2", listOf("plugin2"), listOf("lib.common")),
)
writePluginXmlWithModules(tempDirectory.rootPath.resolve("plugin1"), "plugin1")
writePluginXmlWithModules(tempDirectory.rootPath.resolve("plugin2"), "plugin2")
@@ -257,10 +257,10 @@ class ProductModulesLoaderTest {
fun `service module mapping reports error about ambiguous module`() {
val repository = createRepository(
tempDirectory.rootPath,
RawRuntimeModuleDescriptor.create("root", listOf("root"), emptyList()),
RawRuntimeModuleDescriptor.create("additional", emptyList(), emptyList()),
RawRuntimeModuleDescriptor.create("plugin1", listOf("plugin1"), listOf("additional")),
RawRuntimeModuleDescriptor.create("plugin2", listOf("plugin2"), listOf("additional")),
createModuleDescriptor("root", listOf("root"), emptyList()),
createModuleDescriptor("additional", emptyList(), emptyList()),
createModuleDescriptor("plugin1", listOf("plugin1"), listOf("additional")),
createModuleDescriptor("plugin2", listOf("plugin2"), listOf("additional")),
)
writePluginXmlWithModules(tempDirectory.rootPath.resolve("plugin1"), "plugin1")
writePluginXmlWithModules(tempDirectory.rootPath.resolve("plugin2"), "plugin2")
@@ -279,10 +279,10 @@ class ProductModulesLoaderTest {
fun `without module should exclude module from the nested included module`() {
val repository = createRepository(
tempDirectory.rootPath,
RawRuntimeModuleDescriptor.create("root", listOf("root"), listOf("plugin1")),
RawRuntimeModuleDescriptor.create("plugin1", listOf("plugin1"), listOf("plugin2")),
RawRuntimeModuleDescriptor.create("plugin2", listOf("plugin2"), listOf("plugin3")),
RawRuntimeModuleDescriptor.create("plugin3", listOf("plugin3"), listOf()),
createModuleDescriptor("root", listOf("root"), listOf("plugin1")),
createModuleDescriptor("plugin1", listOf("plugin1"), listOf("plugin2")),
createModuleDescriptor("plugin2", listOf("plugin2"), listOf("plugin3")),
createModuleDescriptor("plugin3", listOf("plugin3"), listOf()),
)
val plugins = listOf("plugin1", "plugin2", "plugin3")
plugins.forEach { writePluginXmlWithModules(tempDirectory.rootPath.resolve(it), it) }
@@ -26,15 +26,20 @@
- a:getResolvedModule():com.intellij.platform.runtime.repository.RuntimeModuleDescriptor
*f:com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleDescriptor
- <init>(java.lang.String,java.util.List,java.util.List):V
- s:create(com.intellij.platform.runtime.repository.RuntimeModuleId,java.util.List,java.util.List):com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleDescriptor
- s:create(java.lang.String,java.util.List,java.util.List):com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleDescriptor
- equals(java.lang.Object):Z
- getDependencies():java.util.List
- getDependencyIds():java.util.List
- getId():java.lang.String
- getModuleId():com.intellij.platform.runtime.repository.RuntimeModuleId
- getResourcePaths():java.util.List
- hashCode():I
*f:com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleRepositoryData
- findDescriptor(com.intellij.platform.runtime.repository.RuntimeModuleId):com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleDescriptor
- findDescriptor(java.lang.String):com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleDescriptor
- getAllIds():java.util.Set
- getAllModuleIds():java.util.Set
- getBasePath():java.nio.file.Path
- getMainPluginModuleId():java.lang.String
*f:com.intellij.platform.runtime.repository.serialization.RuntimeModuleRepositorySerialization
@@ -26,7 +26,6 @@ public class RuntimeModuleRepositoryImpl implements RuntimeModuleRepository {
private volatile RawRuntimeModuleRepositoryData myMainData;
private volatile List<RawRuntimeModuleRepositoryData> myAdditionalData;
private final Path myDescriptorsFilePath;
private final Map<String, RuntimeModuleId> myInternedModuleIds;
public RuntimeModuleRepositoryImpl(@NotNull Path descriptorsFilePath) {
this(descriptorsFilePath, null);
@@ -35,7 +34,6 @@ public class RuntimeModuleRepositoryImpl implements RuntimeModuleRepository {
public RuntimeModuleRepositoryImpl(@NotNull Path descriptorsFilePath, @Nullable RawRuntimeModuleRepositoryData preloadedMainData) {
myDescriptorsFilePath = descriptorsFilePath;
myResolveResults = new ConcurrentHashMap<>();
myInternedModuleIds = new ConcurrentHashMap<>();
myMainData = preloadedMainData;
}
@@ -53,11 +51,11 @@ public class RuntimeModuleRepositoryImpl implements RuntimeModuleRepository {
if (cached != null) return cached;
RawRuntimeModuleRepositoryData rawData = getMainData();
RawRuntimeModuleDescriptor rawDescriptor = rawData.findDescriptor(moduleId.getStringId());
RawRuntimeModuleDescriptor rawDescriptor = rawData.findDescriptor(moduleId);
if (rawDescriptor == null) {
if (myAdditionalData != null) {
for (RawRuntimeModuleRepositoryData data : myAdditionalData) {
rawDescriptor = data.findDescriptor(moduleId.getStringId());
rawDescriptor = data.findDescriptor(moduleId);
if (rawDescriptor != null) {
rawData = data;
break;
@@ -72,12 +70,11 @@ public class RuntimeModuleRepositoryImpl implements RuntimeModuleRepository {
}
}
List<String> rawDependencies = rawDescriptor.getDependencies();
List<RuntimeModuleId> rawDependencies = rawDescriptor.getDependencyIds();
List<RuntimeModuleDescriptor> resolvedDependencies = new ArrayList<>(rawDependencies.size());
RuntimeModuleDescriptorImpl descriptor = new RuntimeModuleDescriptorImpl(moduleId, rawData.getBasePath(), rawDescriptor.getResourcePaths(), resolvedDependencies);
dependencyPath.put(moduleId, descriptor);
for (String dependency : rawDependencies) {
RuntimeModuleId dependencyId = myInternedModuleIds.computeIfAbsent(dependency, RuntimeModuleId::raw);
for (RuntimeModuleId dependencyId : rawDependencies) {
RuntimeModuleDescriptor circularDependency = dependencyPath.get(dependencyId);
if (circularDependency != null) {
//the circularDependency instance isn't fully constructed, but it's ok given that RuntimeModuleDescriptorImpl's constructor just stores the passed values
@@ -124,11 +121,11 @@ public class RuntimeModuleRepositoryImpl implements RuntimeModuleRepository {
@Override
public @NotNull List<Path> getModuleResourcePaths(@NotNull RuntimeModuleId moduleId) {
RawRuntimeModuleRepositoryData rawData = getMainData();
RawRuntimeModuleDescriptor rawDescriptor = rawData.findDescriptor(moduleId.getStringId());
RawRuntimeModuleDescriptor rawDescriptor = rawData.findDescriptor(moduleId);
if (rawDescriptor == null) {
if (myAdditionalData != null) {
for (RawRuntimeModuleRepositoryData repository : myAdditionalData) {
rawDescriptor = repository.findDescriptor(moduleId.getStringId());
rawDescriptor = repository.findDescriptor(moduleId);
if (rawDescriptor != null) {
rawData = repository;
break;
@@ -1,45 +1,74 @@
// 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.platform.runtime.repository.serialization;
import com.intellij.platform.runtime.repository.RuntimeModuleId;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* Describes raw data of a runtime module descriptor. This class is used in code which generates the module repository, if you need to
* get information about modules in IDE, use {@link com.intellij.platform.runtime.repository.RuntimeModuleDescriptor} instead.
*/
public final class RawRuntimeModuleDescriptor {
private final String myId;
private final RuntimeModuleId myId;
private final List<String> myResourcePaths;
private final List<String> myDependencies;
private final List<RuntimeModuleId> myDependencies;
/**
* @deprecated use {@link #create(String, List, List)} instead
* @deprecated use {@link #create(RuntimeModuleId, List, List)} instead
*/
@Deprecated(forRemoval = true)
public RawRuntimeModuleDescriptor(@NotNull String id, @NotNull List<String> resourcePaths, @NotNull List<String> dependencies) {
myId = RuntimeModuleId.raw(id);
myResourcePaths = resourcePaths;
myDependencies = new ArrayList<>(dependencies.size());
for (String dependency : dependencies) {
myDependencies.add(RuntimeModuleId.raw(dependency));
}
}
private RawRuntimeModuleDescriptor(@NotNull RuntimeModuleId id, @NotNull List<String> resourcePaths, @NotNull List<RuntimeModuleId> dependencies) {
myId = id;
myResourcePaths = resourcePaths;
myDependencies = dependencies;
}
public @NotNull String getId() {
public @NotNull RuntimeModuleId getModuleId() {
return myId;
}
/**
* @deprecated use {@link #getModuleId()} instead
*/
@Deprecated(forRemoval = true)
public @NotNull String getId() {
return myId.getStringId();
}
public @NotNull List<String> getResourcePaths() {
return myResourcePaths;
}
/**
* @deprecated use {@link #getDependencyIds()} instead
*/
@Deprecated(forRemoval = true)
public @NotNull List<String> getDependencies() {
//noinspection SSBasedInspection
return myDependencies.stream().map(RuntimeModuleId::getStringId).collect(Collectors.toList());
}
public @NotNull List<RuntimeModuleId> getDependencyIds() {
return myDependencies;
}
@Override
public String toString() {
return "RawRuntimeModuleDescriptor{" +
"id='" + myId + '\'' +
"id='" + myId.getPresentableName() + '\'' +
", resourcePaths=" + myResourcePaths +
", dependencies=" + myDependencies +
'}';
@@ -67,6 +96,14 @@ public final class RawRuntimeModuleDescriptor {
return result;
}
public static @NotNull RawRuntimeModuleDescriptor create(@NotNull RuntimeModuleId id, @NotNull List<String> resourcePaths, @NotNull List<RuntimeModuleId> dependencies) {
return new RawRuntimeModuleDescriptor(id, resourcePaths, dependencies);
}
/**
* @deprecated use {@link #create(RuntimeModuleId, List, List)} instead
*/
@Deprecated(forRemoval = true)
public static @NotNull RawRuntimeModuleDescriptor create(@NotNull String id, @NotNull List<String> resourcePaths, @NotNull List<String> dependencies) {
return new RawRuntimeModuleDescriptor(id, resourcePaths, dependencies);
}
@@ -1,50 +1,93 @@
// 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.platform.runtime.repository.serialization;
import com.intellij.platform.runtime.repository.RuntimeModuleId;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.nio.file.Path;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Describes raw data read from the module repository JAR. This class is used in code which parses the module repository, if you need to
* get information about modules in IDE, use {@link com.intellij.platform.runtime.repository.RuntimeModuleRepository} instead.
*/
public final class RawRuntimeModuleRepositoryData {
private final Map<String, RawRuntimeModuleDescriptor> myDescriptors;
private final Map<RuntimeModuleId, RawRuntimeModuleDescriptor> myDescriptors;
private final Path myBasePath;
private final String myMainPluginModuleId;
private final RuntimeModuleId myMainPluginModuleId;
/**
* Use {@link RuntimeModuleRepositorySerialization#loadFromJar(Path)} to create an instance in production code.
*/
@ApiStatus.Internal
public RawRuntimeModuleRepositoryData(@NotNull Map<String, RawRuntimeModuleDescriptor> descriptors, @NotNull Path basePath, @Nullable String mainPluginModuleId) {
private RawRuntimeModuleRepositoryData(@NotNull Map<RuntimeModuleId, RawRuntimeModuleDescriptor> descriptors,
@NotNull Path basePath,
@Nullable RuntimeModuleId mainPluginModuleId) {
myDescriptors = descriptors;
myBasePath = basePath;
myMainPluginModuleId = mainPluginModuleId;
}
public @Nullable RawRuntimeModuleDescriptor findDescriptor(@NotNull String id) {
/**
* @deprecated use {@link RuntimeModuleRepositorySerialization#loadFromJar(Path)} or {@link #create(Map, Path, RuntimeModuleId)} instead
*/
@Deprecated(forRemoval = true)
@ApiStatus.Internal
public RawRuntimeModuleRepositoryData(@NotNull Map<String, RawRuntimeModuleDescriptor> descriptors, @NotNull Path basePath, @Nullable String mainPluginModuleId) {
myDescriptors = new LinkedHashMap<>(descriptors.size());
for (Map.Entry<String, RawRuntimeModuleDescriptor> entry : descriptors.entrySet()) {
myDescriptors.put(RuntimeModuleId.raw(entry.getKey()), entry.getValue());
}
myBasePath = basePath;
myMainPluginModuleId = mainPluginModuleId != null ? RuntimeModuleId.raw(mainPluginModuleId) : null;
}
public @Nullable RawRuntimeModuleDescriptor findDescriptor(@NotNull RuntimeModuleId id) {
return myDescriptors.get(id);
}
/**
* @deprecated use {@link #findDescriptor(RuntimeModuleId)} instead
*/
@Deprecated(forRemoval = true)
public @Nullable RawRuntimeModuleDescriptor findDescriptor(@NotNull String id) {
return myDescriptors.get(RuntimeModuleId.raw(id));
}
public @NotNull Path getBasePath() {
return myBasePath;
}
public @NotNull Set<String> getAllIds() {
public @NotNull Set<RuntimeModuleId> getAllModuleIds() {
return myDescriptors.keySet();
}
/**
* @deprecated use {@link #getAllModuleIds()} instead
*/
@Deprecated(forRemoval = true)
public @NotNull Set<String> getAllIds() {
return myDescriptors.keySet().stream().map(RuntimeModuleId::getStringId).collect(Collectors.toSet());
}
/**
* Returns ID of the main plugin module for an additional module repository describing a custom plugin.
* For the main module repository (describing the IDE distribution) it returns {@code null}.
*/
public @Nullable String getMainPluginModuleId() {
return myMainPluginModuleId;
return myMainPluginModuleId != null ? myMainPluginModuleId.getStringId() : null;
}
/**
* Use {@link RuntimeModuleRepositorySerialization#loadFromCompactFile} to create an instance in production code.
*/
@ApiStatus.Internal
public static @NotNull RawRuntimeModuleRepositoryData create(
@NotNull Map<RuntimeModuleId, RawRuntimeModuleDescriptor> descriptors,
@NotNull Path basePath,
@Nullable RuntimeModuleId mainPluginModuleId
) {
return new RawRuntimeModuleRepositoryData(descriptors, basePath, mainPluginModuleId);
}
}
@@ -1,6 +1,7 @@
// 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.platform.runtime.repository.serialization.impl;
import com.intellij.platform.runtime.repository.RuntimeModuleId;
import com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleDescriptor;
import org.jetbrains.annotations.NotNull;
@@ -13,25 +14,25 @@ import java.util.Set;
final class CachedClasspathComputation {
static @NotNull Collection<String> computeClasspath(Collection<RawRuntimeModuleDescriptor> descriptors, String moduleName) {
static @NotNull Collection<String> computeClasspath(Collection<RawRuntimeModuleDescriptor> descriptors, RuntimeModuleId moduleName) {
Set<String> classpath = new LinkedHashSet<>();
Map<String, RawRuntimeModuleDescriptor> descriptorMap = new HashMap<>();
Map<RuntimeModuleId, RawRuntimeModuleDescriptor> descriptorMap = new HashMap<>();
for (RawRuntimeModuleDescriptor descriptor : descriptors) {
descriptorMap.put(descriptor.getId(), descriptor);
descriptorMap.put(descriptor.getModuleId(), descriptor);
}
collectClasspathEntries(moduleName, descriptorMap, new HashSet<>(), classpath);
return classpath;
}
private static void collectClasspathEntries(String moduleName,
Map<String, RawRuntimeModuleDescriptor> descriptorMap,
Set<String> processedModules,
private static void collectClasspathEntries(RuntimeModuleId moduleId,
Map<RuntimeModuleId, RawRuntimeModuleDescriptor> descriptorMap,
Set<RuntimeModuleId> processedModules,
Set<String> classpath) {
if (!processedModules.add(moduleName)) return;
RawRuntimeModuleDescriptor descriptor = descriptorMap.get(moduleName);
if (!processedModules.add(moduleId)) return;
RawRuntimeModuleDescriptor descriptor = descriptorMap.get(moduleId);
if (descriptor == null) return;
classpath.addAll(descriptor.getResourcePaths());
for (String dependency : descriptor.getDependencies()) {
for (RuntimeModuleId dependency : descriptor.getDependencyIds()) {
collectClasspathEntries(dependency, descriptorMap, processedModules, classpath);
}
}
@@ -2,6 +2,7 @@
package com.intellij.platform.runtime.repository.serialization.impl;
import com.intellij.platform.runtime.repository.MalformedRepositoryException;
import com.intellij.platform.runtime.repository.RuntimeModuleId;
import com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleDescriptor;
import com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleRepositoryData;
import org.jetbrains.annotations.NotNull;
@@ -39,25 +40,26 @@ public final class CompactFileReader {
boolean hasMainPluginModule = in.readBoolean();
String mainPluginModuleName = hasMainPluginModule? in.readUTF() : null;
RuntimeModuleId mainPluginModuleId = mainPluginModuleName != null ? RuntimeModuleId.module(mainPluginModuleName) : null;
Map<String, RawRuntimeModuleDescriptor> descriptors = new HashMap<>();
Map<RuntimeModuleId, RawRuntimeModuleDescriptor> descriptors = new HashMap<>();
int descriptorsCount = in.readInt();
int unresolvedDependenciesCount = in.readInt();
int totalIdCount = descriptorsCount + unresolvedDependenciesCount;
String[] descriptorIds = new String[totalIdCount];
RuntimeModuleId[] descriptorIds = new RuntimeModuleId[totalIdCount];
for (int i = 0; i < totalIdCount; i++) {
descriptorIds[i] = in.readUTF();
descriptorIds[i] = RuntimeModuleId.raw(in.readUTF());
}
for (int i = 0; i < descriptorsCount; i++) {
String descriptorId = descriptorIds[i];
RuntimeModuleId descriptorId = descriptorIds[i];
int dependenciesCount = in.readInt();
List<String> dependencies = new ArrayList<>(dependenciesCount);
List<RuntimeModuleId> dependencies = new ArrayList<>(dependenciesCount);
for (int j = 0; j < dependenciesCount; j++) {
int dependencyIndex = in.readInt();
if (dependencyIndex < 0 || dependencyIndex >= totalIdCount) {
throw new MalformedRepositoryException("Invalid dependency index '" + dependencyIndex + "' in '" + descriptorId + "'");
throw new MalformedRepositoryException("Invalid dependency index '" + dependencyIndex + "' in '" + descriptorId.getPresentableName() + "'");
}
dependencies.add(descriptorIds[dependencyIndex]);
}
@@ -69,7 +71,7 @@ public final class CompactFileReader {
descriptors.put(descriptorId, RawRuntimeModuleDescriptor.create(descriptorId, resourcePaths, dependencies));
}
return new RawRuntimeModuleRepositoryData(descriptors, filePath.getParent(), mainPluginModuleName);
return RawRuntimeModuleRepositoryData.create(descriptors, filePath.getParent(), mainPluginModuleId);
}
}
@@ -1,6 +1,7 @@
// 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.platform.runtime.repository.serialization.impl;
import com.intellij.platform.runtime.repository.RuntimeModuleId;
import com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleDescriptor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -31,7 +32,7 @@ public final class CompactFileWriter {
out.writeBoolean(hasBootstrap);
if (hasBootstrap) {
out.writeUTF(bootstrapModuleName);
Collection<String> bootstrapClasspath = CachedClasspathComputation.computeClasspath(originalDescriptors, bootstrapModuleName);
Collection<String> bootstrapClasspath = CachedClasspathComputation.computeClasspath(originalDescriptors, RuntimeModuleId.module(bootstrapModuleName));
out.writeInt(bootstrapClasspath.size());
for (String path : bootstrapClasspath) {
out.writeUTF(path);
@@ -45,14 +46,14 @@ public final class CompactFileWriter {
}
List<RawRuntimeModuleDescriptor> descriptors = new ArrayList<>(originalDescriptors);
Collections.sort(descriptors, Comparator.comparing(RawRuntimeModuleDescriptor::getId));
Map<String, Integer> indexes = new HashMap<>(descriptors.size());
Collections.sort(descriptors, Comparator.comparing(descriptor -> descriptor.getModuleId().getStringId()));
Map<RuntimeModuleId, Integer> indexes = new HashMap<>(descriptors.size());
for (int i = 0; i < descriptors.size(); i++) {
indexes.put(descriptors.get(i).getId(), i);
indexes.put(descriptors.get(i).getModuleId(), i);
}
List<String> unresolvedDependencies = new ArrayList<>();
List<RuntimeModuleId> unresolvedDependencies = new ArrayList<>();
for (RawRuntimeModuleDescriptor descriptor : descriptors) {
for (String dependency : descriptor.getDependencies()) {
for (RuntimeModuleId dependency : descriptor.getDependencyIds()) {
if (!indexes.containsKey(dependency)) {
unresolvedDependencies.add(dependency);
int nextId = indexes.size();
@@ -64,19 +65,19 @@ public final class CompactFileWriter {
out.writeInt(descriptors.size());
out.writeInt(unresolvedDependencies.size());
for (RawRuntimeModuleDescriptor descriptor : descriptors) {
out.writeUTF(descriptor.getId());
out.writeUTF(descriptor.getModuleId().getStringId());
}
for (String dependency : unresolvedDependencies) {
out.writeUTF(dependency);
for (RuntimeModuleId dependency : unresolvedDependencies) {
out.writeUTF(dependency.getStringId());
}
for (RawRuntimeModuleDescriptor descriptor : descriptors) {
out.writeInt(descriptor.getDependencies().size());
for (String dependency : descriptor.getDependencies()) {
out.writeInt(descriptor.getDependencyIds().size());
for (RuntimeModuleId dependency : descriptor.getDependencyIds()) {
Integer index = indexes.get(dependency);
if (index == null) {
throw new AssertionError("Unknown dependency '" + dependency + "' in '" + descriptor.getId() + "'");
throw new AssertionError("Unknown dependency '" + dependency.getPresentableName() + "' in '" + descriptor.getModuleId().getPresentableName() + "'");
}
out.writeInt(index);
}
@@ -1,6 +1,7 @@
// 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.platform.runtime.repository.serialization.impl;
import com.intellij.platform.runtime.repository.RuntimeModuleId;
import com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleDescriptor;
import com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleRepositoryData;
import org.jetbrains.annotations.NotNull;
@@ -33,8 +34,8 @@ public final class JarFileSerializer {
private static final Attributes.Name BOOTSTRAP_CLASSPATH_ATTRIBUTE_NAME = new Attributes.Name("Bootstrap-Class-Path");
public static @NotNull RawRuntimeModuleRepositoryData loadFromJar(@NotNull Path jarPath) throws IOException, XMLStreamException {
Map<String, RawRuntimeModuleDescriptor> rawData = new HashMap<>();
String mainPluginModuleId;
Map<RuntimeModuleId, RawRuntimeModuleDescriptor> rawData = new HashMap<>();
String mainPluginModuleName;
try (JarInputStream input = new JarInputStream(new BufferedInputStream(Files.newInputStream(jarPath)))) {
Manifest manifest = input.getManifest();
if (manifest == null) {
@@ -48,18 +49,19 @@ public final class JarFileSerializer {
if (!version.equals(SPECIFICATION_VERSION)) {
throw new IOException("'" + jarPath + "' has unsupported version '" + version + "' ('" + SPECIFICATION_VERSION + "' is expected)");
}
mainPluginModuleId = mainAttributes.getValue(MAIN_PLUGIN_MODULE_ATTRIBUTE_NAME);
mainPluginModuleName = mainAttributes.getValue(MAIN_PLUGIN_MODULE_ATTRIBUTE_NAME);
JarEntry entry;
XMLInputFactory factory = XMLInputFactory.newDefaultFactory();
while ((entry = input.getNextJarEntry()) != null) {
String name = entry.getName();
if (name.endsWith(".xml")) {
RawRuntimeModuleDescriptor data = ModuleXmlSerializer.parseModuleXml(factory, input);
rawData.put(data.getId(), data);
rawData.put(data.getModuleId(), data);
}
}
}
return new RawRuntimeModuleRepositoryData(rawData, jarPath.getParent(), mainPluginModuleId);
RuntimeModuleId mainPluginModuleId = mainPluginModuleName != null ? RuntimeModuleId.module(mainPluginModuleName) : null;
return RawRuntimeModuleRepositoryData.create(rawData, jarPath.getParent(), mainPluginModuleId);
}
public static @NotNull String @Nullable [] loadBootstrapClasspath(@NotNull Path jarPath, @NotNull String bootstrapModuleName)
@@ -97,7 +99,7 @@ public final class JarFileSerializer {
attributes.put(Attributes.Name.IMPLEMENTATION_VERSION, SPECIFICATION_VERSION + "." + generatorVersion);
if (bootstrapModuleName != null) {
attributes.put(BOOTSTRAP_MODULE_ATTRIBUTE_NAME, bootstrapModuleName);
Collection<String> bootstrapClasspath = CachedClasspathComputation.computeClasspath(descriptors, bootstrapModuleName);
Collection<String> bootstrapClasspath = CachedClasspathComputation.computeClasspath(descriptors, RuntimeModuleId.module(bootstrapModuleName));
attributes.put(BOOTSTRAP_CLASSPATH_ATTRIBUTE_NAME, String.join(" ", bootstrapClasspath));
}
if (mainPluginModuleId != null) {
@@ -106,7 +108,7 @@ public final class JarFileSerializer {
try (JarOutputStream jarOutput = new JarOutputStream(new BufferedOutputStream(Files.newOutputStream(jarFile)), manifest)) {
XMLOutputFactory factory = XMLOutputFactory.newDefaultFactory();
for (RawRuntimeModuleDescriptor descriptor : descriptors) {
String id = descriptor.getId();
String id = descriptor.getModuleId().getStringId();
jarOutput.putNextEntry(new JarEntry(id + ".xml"));
PrintWriter output = new PrintWriter(jarOutput, false, StandardCharsets.UTF_8);
ModuleXmlSerializer.writeModuleXml(descriptor, output, factory);
@@ -1,6 +1,7 @@
// 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.platform.runtime.repository.serialization.impl;
import com.intellij.platform.runtime.repository.RuntimeModuleId;
import com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleDescriptor;
import org.jetbrains.annotations.NotNull;
@@ -27,15 +28,15 @@ final class ModuleXmlSerializer {
writer.writeStartDocument("UTF-8", "1.0");
writeEolAndIndent(writer, 0);
writer.writeStartElement(MODULE_TAG);
writer.writeAttribute(NAME_ATTRIBUTE, descriptor.getId());
List<String> dependencies = descriptor.getDependencies();
writer.writeAttribute(NAME_ATTRIBUTE, descriptor.getModuleId().getStringId());
List<RuntimeModuleId> dependencies = descriptor.getDependencyIds();
if (!dependencies.isEmpty()) {
writeEolAndIndent(writer, 1);
writer.writeStartElement("dependencies");
for (String dependency : dependencies) {
for (RuntimeModuleId dependency : dependencies) {
writeEolAndIndent(writer, 2);
writer.writeEmptyElement(MODULE_TAG);
writer.writeAttribute(NAME_ATTRIBUTE, dependency);
writer.writeAttribute(NAME_ATTRIBUTE, dependency.getStringId());
}
writeEolAndIndent(writer, 1);
writer.writeEndElement();
@@ -67,7 +68,7 @@ final class ModuleXmlSerializer {
public static RawRuntimeModuleDescriptor parseModuleXml(XMLInputFactory factory, InputStream inputStream) throws XMLStreamException {
XMLStreamReader reader = factory.createXMLStreamReader(inputStream);
ArrayList<String> dependencies = new ArrayList<>();
ArrayList<RuntimeModuleId> dependencies = new ArrayList<>();
ArrayList<String> resources = new ArrayList<>();
String moduleName = null;
int level = 0;
@@ -80,7 +81,8 @@ final class ModuleXmlSerializer {
moduleName = XmlStreamUtil.readFirstAttribute(reader, NAME_ATTRIBUTE);
}
else if (level == 3 & tagName.equals(MODULE_TAG)) {
dependencies.add(XmlStreamUtil.readFirstAttribute(reader, NAME_ATTRIBUTE));
String dependencyName = XmlStreamUtil.readFirstAttribute(reader, NAME_ATTRIBUTE);
dependencies.add(RuntimeModuleId.raw(dependencyName));
}
else if (level == 3 && tagName.equals(RESOURCE_ROOT_TAG)) {
String relativePath = XmlStreamUtil.readFirstAttribute(reader, PATH_ATTRIBUTE);
@@ -98,6 +100,6 @@ final class ModuleXmlSerializer {
if (moduleName == null) {
throw new XMLStreamException("Required attribute 'module' is not specified");
}
return RawRuntimeModuleDescriptor.create(moduleName, resources, dependencies);
return RawRuntimeModuleDescriptor.create(RuntimeModuleId.raw(moduleName), resources, dependencies);
}
}
@@ -27,8 +27,8 @@ class RepositoryTest {
fun `resolved dependencies`() {
val repository = createRepository(
tempDirectory.rootPath,
RawRuntimeModuleDescriptor.create("ij.foo", emptyList(), emptyList()),
RawRuntimeModuleDescriptor.create("ij.bar", emptyList(), listOf("ij.foo")),
createModuleDescriptor("ij.foo", emptyList(), emptyList()),
createModuleDescriptor("ij.bar", emptyList(), listOf("ij.foo")),
)
val bar = repository.getModule(RuntimeModuleId.raw("ij.bar"))
val foo = repository.getModule(RuntimeModuleId.raw("ij.foo"))
@@ -39,9 +39,9 @@ class RepositoryTest {
fun `unresolved dependency`() {
val repository = createRepository(
tempDirectory.rootPath,
RawRuntimeModuleDescriptor.create("ij.foo", emptyList(), emptyList()),
RawRuntimeModuleDescriptor.create("ij.bar", emptyList(), listOf("ij.foo", "unresolved")),
RawRuntimeModuleDescriptor.create("ij.baz", emptyList(), listOf("ij.bar")),
createModuleDescriptor("ij.foo", emptyList(), emptyList()),
createModuleDescriptor("ij.bar", emptyList(), listOf("ij.foo", "unresolved")),
createModuleDescriptor("ij.baz", emptyList(), listOf("ij.bar")),
)
fun RuntimeModuleId.assertUnresolved(vararg pathToFailed: RuntimeModuleId) {
val result = repository.resolveModule(this)
@@ -65,9 +65,9 @@ class RepositoryTest {
fun `circular dependency`() {
val repository = createRepository(
tempDirectory.rootPath,
RawRuntimeModuleDescriptor.create("ij.foo", emptyList(), listOf("ij.bar")),
RawRuntimeModuleDescriptor.create("ij.bar", emptyList(), listOf("ij.foo")),
RawRuntimeModuleDescriptor.create("ij.baz", emptyList(), listOf("ij.bar")),
createModuleDescriptor("ij.foo", emptyList(), listOf("ij.bar")),
createModuleDescriptor("ij.bar", emptyList(), listOf("ij.foo")),
createModuleDescriptor("ij.baz", emptyList(), listOf("ij.bar")),
)
val baz = repository.getModule(RuntimeModuleId.raw("ij.baz"))
val bar = repository.getModule(RuntimeModuleId.raw("ij.bar"))
@@ -81,8 +81,8 @@ class RepositoryTest {
fun `relative path`() {
val repository = createRepository(
tempDirectory.rootPath,
RawRuntimeModuleDescriptor.create("ij.foo", listOf("foo.jar"), emptyList()),
RawRuntimeModuleDescriptor.create("ij.bar", listOf("../bar/bar.jar"), emptyList()),
createModuleDescriptor("ij.foo", listOf("foo.jar"), emptyList()),
createModuleDescriptor("ij.bar", listOf("../bar/bar.jar"), emptyList()),
)
val foo = repository.getModule(RuntimeModuleId.raw("ij.foo"))
assertEquals(listOf(tempDirectory.rootPath.resolve("foo.jar")), foo.resourceRootPaths)
@@ -94,7 +94,7 @@ class RepositoryTest {
fun `compute resource paths without resolving`() {
val repository = createRepository(
tempDirectory.rootPath,
RawRuntimeModuleDescriptor.create("ij.foo", listOf("foo.jar"), listOf("unresolved")),
createModuleDescriptor("ij.foo", listOf("foo.jar"), listOf("unresolved")),
)
assertEquals(listOf(tempDirectory.rootPath.resolve("foo.jar")),
repository.getModuleResourcePaths(RuntimeModuleId.raw("ij.foo")))
@@ -104,8 +104,8 @@ class RepositoryTest {
fun `resource path macros`() {
val repository = createRepository(
tempDirectory.rootPath,
RawRuntimeModuleDescriptor.create("ij.foo", listOf("\$PROJECT_DIR$/foo.jar"), emptyList()),
RawRuntimeModuleDescriptor.create("ij.bar", listOf("${getLocalMavenRepo()}/bar/bar.jar"), emptyList()),
createModuleDescriptor("ij.foo", listOf("\$PROJECT_DIR$/foo.jar"), emptyList()),
createModuleDescriptor("ij.bar", listOf("${getLocalMavenRepo()}/bar/bar.jar"), emptyList()),
)
//ensure that tempDirectory will be treated as the project root if 'idea.home.path' isn't specified explicitly
@@ -135,7 +135,7 @@ class RepositoryTest {
for (path in incorrectPaths) {
val repository = createRepository(
tempDirectory.rootPath,
RawRuntimeModuleDescriptor.create("ij.foo", listOf(path), emptyList())
createModuleDescriptor("ij.foo", listOf(path), emptyList())
)
val module = repository.getModule(RuntimeModuleId.raw("ij.foo"))
assertThrows(MalformedRepositoryException::class.java, { module.resourceRootPaths }, "Path $path is incorrect")
@@ -146,10 +146,10 @@ class RepositoryTest {
fun `module classpath`() {
val repository = createRepository(
tempDirectory.rootPath,
RawRuntimeModuleDescriptor.create("ij.foo", listOf("foo.jar"), emptyList()),
RawRuntimeModuleDescriptor.create("ij.bar", listOf("bar.jar"), listOf("ij.foo")),
RawRuntimeModuleDescriptor.create("ij.baz", listOf("baz.jar"), listOf("ij.foo")),
RawRuntimeModuleDescriptor.create("ij.main", emptyList(), listOf("ij.bar", "ij.baz")),
createModuleDescriptor("ij.foo", listOf("foo.jar"), emptyList()),
createModuleDescriptor("ij.bar", listOf("bar.jar"), listOf("ij.foo")),
createModuleDescriptor("ij.baz", listOf("baz.jar"), listOf("ij.foo")),
createModuleDescriptor("ij.main", emptyList(), listOf("ij.bar", "ij.baz")),
)
val classpath = repository.getModule(RuntimeModuleId.raw("ij.main")).moduleClasspath
assertEquals(listOf("bar.jar", "foo.jar", "baz.jar").map { tempDirectory.rootPath.resolve(it) }, classpath)
@@ -161,8 +161,8 @@ class RepositoryTest {
@CartesianTest.Values(booleans = [true, false]) loadFromCompact: Boolean
) {
val descriptors = arrayOf(
RawRuntimeModuleDescriptor.create("ij.foo", listOf("foo.jar"), emptyList()),
RawRuntimeModuleDescriptor.create("ij.bar", listOf("bar.jar"), listOf("ij.foo")),
createModuleDescriptor("ij.foo", listOf("foo.jar"), emptyList()),
createModuleDescriptor("ij.bar", listOf("bar.jar"), listOf("ij.foo")),
)
val basePath = tempDirectory.rootPath
val bootstrapModuleName = storedBootstrapModule.takeIf { it.isNotEmpty() }
@@ -183,18 +183,18 @@ class RepositoryTest {
fun `additional repositories`() {
val main = createRepository(
tempDirectory.rootPath,
RawRuntimeModuleDescriptor.create("ij.foo", listOf("foo.jar"), emptyList()),
createModuleDescriptor("ij.foo", listOf("foo.jar"), emptyList()),
) as RuntimeModuleRepositoryImpl
val additional1Path = tempDirectory.rootPath.resolve("additional1")
val additional1 = createRawRepository(
additional1Path,
RawRuntimeModuleDescriptor.create("custom1.foo", listOf("custom1-foo.jar"), listOf("ij.foo")),
RawRuntimeModuleDescriptor.create("custom1.bar", listOf("custom1-bar.jar"), listOf("custom1.foo")),
createModuleDescriptor("custom1.foo", listOf("custom1-foo.jar"), listOf("ij.foo")),
createModuleDescriptor("custom1.bar", listOf("custom1-bar.jar"), listOf("custom1.foo")),
)
val additional2Path = tempDirectory.rootPath.resolve("additional2")
val additional2 = createRawRepository(
additional2Path,
RawRuntimeModuleDescriptor.create("custom2", listOf("custom2.jar"), listOf("custom1.bar")),
createModuleDescriptor("custom2", listOf("custom2.jar"), listOf("custom1.bar")),
)
main.loadAdditionalRepositories(listOf(additional1, additional2))
val moduleId = RuntimeModuleId.raw("custom2")
@@ -209,6 +209,6 @@ class RepositoryTest {
}
private fun createRawRepository(basePath: Path, vararg descriptors: RawRuntimeModuleDescriptor): RawRuntimeModuleRepositoryData {
return RawRuntimeModuleRepositoryData(descriptors.associateBy { it.id }, basePath, null)
return RawRuntimeModuleRepositoryData.create(descriptors.associateBy { it.moduleId }, basePath, null)
}
}
@@ -18,7 +18,11 @@ fun DirectoryContentBuilder.xml(name: String, @Language("XML") content: String)
fun createRepository(basePath: Path, vararg descriptors: RawRuntimeModuleDescriptor): RuntimeModuleRepository {
val moduleDescriptorsPath = basePath.resolve("module-descriptors.dat")
return RuntimeModuleRepositoryImpl(moduleDescriptorsPath,
RawRuntimeModuleRepositoryData(descriptors.associateBy { it.id }, basePath, null))
RawRuntimeModuleRepositoryData.create(descriptors.associateBy { it.moduleId }, basePath, null))
}
fun createModuleDescriptor(id: String, resourcePaths: List<String>, dependencies: List<String> = emptyList()): RawRuntimeModuleDescriptor {
return RawRuntimeModuleDescriptor.create(RuntimeModuleId.raw(id), resourcePaths, dependencies.map { RuntimeModuleId.raw(it) })
}
fun writePluginXml(resourceRoot: Path, @Language("XM") content: String) {
@@ -1,6 +1,7 @@
// 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.platform.runtime.repository.serialization
import com.intellij.platform.runtime.repository.createModuleDescriptor
import com.intellij.platform.runtime.repository.serialization.impl.JarFileSerializer
import com.intellij.platform.runtime.repository.xml
import com.intellij.testFramework.UsefulTestCase
@@ -20,7 +21,7 @@ class JarRepositorySerializationTest {
@Test
fun `empty module`() {
check(listOf(RawRuntimeModuleDescriptor.create("ij.platform.util", emptyList(), emptyList()))) {
check(listOf(createModuleDescriptor("ij.platform.util", emptyList(), emptyList()))) {
xml("ij.platform.util.xml", """
<module name="ij.platform.util">
</module>
@@ -30,7 +31,7 @@ class JarRepositorySerializationTest {
@Test
fun `single module`() {
check(listOf(RawRuntimeModuleDescriptor.create("ij.platform.util", listOf("ij-util.jar"), emptyList()))) {
check(listOf(createModuleDescriptor("ij.platform.util", listOf("ij-util.jar"), emptyList()))) {
xml("ij.platform.util.xml", """
<module name="ij.platform.util">
<resources>
@@ -44,8 +45,8 @@ class JarRepositorySerializationTest {
@Test
fun `two modules`() {
check(listOf(
RawRuntimeModuleDescriptor.create("ij.platform.util.rt", listOf("ij-util-rt.jar"), emptyList()),
RawRuntimeModuleDescriptor.create("ij.platform.util", emptyList(), listOf("ij.platform.util.rt")),
createModuleDescriptor("ij.platform.util.rt", listOf("ij-util-rt.jar"), emptyList()),
createModuleDescriptor("ij.platform.util", emptyList(), listOf("ij.platform.util.rt")),
)) {
xml("ij.platform.util.xml", """
<module name="ij.platform.util">
@@ -67,8 +68,8 @@ class JarRepositorySerializationTest {
@Test
fun `bootstrap module classpath`() {
check(listOf(
RawRuntimeModuleDescriptor.create("foo", listOf("foo.jar"), emptyList()),
RawRuntimeModuleDescriptor.create("bar", listOf("bar.jar"), listOf("foo")),
createModuleDescriptor("foo", listOf("foo.jar"), emptyList()),
createModuleDescriptor("bar", listOf("bar.jar"), listOf("foo")),
), "bar", "bar.jar foo.jar") {
xml("foo.xml", """
<module name="foo">
@@ -93,8 +94,8 @@ class JarRepositorySerializationTest {
@Test
fun `unresolved dependency`() {
val descriptors = listOf(
RawRuntimeModuleDescriptor.create("ij.foo", emptyList(), emptyList()),
RawRuntimeModuleDescriptor.create("ij.bar", emptyList(), listOf("ij.foo", "unresolved")),
createModuleDescriptor("ij.foo", emptyList(), emptyList()),
createModuleDescriptor("ij.bar", emptyList(), listOf("ij.foo", "unresolved")),
)
check(descriptors) {
xml("ij.foo.xml", """
@@ -147,13 +148,13 @@ class JarRepositorySerializationTest {
private fun checkLoadingFromCompactFile(filePath: Path, expectedDescriptors: List<RawRuntimeModuleDescriptor>) {
val repositoryData = RuntimeModuleRepositorySerialization.loadFromCompactFile(filePath)
val actualDescriptors = repositoryData.allIds.map { repositoryData.findDescriptor(it)!! }
val actualDescriptors = repositoryData.allModuleIds.map { repositoryData.findDescriptor(it)!! }
UsefulTestCase.assertSameElements(actualDescriptors, expectedDescriptors)
}
private fun checkLoadingFromJar(zipFileSpec: DirectoryContentSpec, expectedDescriptors: List<RawRuntimeModuleDescriptor>) {
val repositoryData = RuntimeModuleRepositorySerialization.loadFromJar(zipFileSpec.generateInTempDir())
val actualDescriptors = repositoryData.allIds.map { repositoryData.findDescriptor(it)!! }
val actualDescriptors = repositoryData.allModuleIds.map { repositoryData.findDescriptor(it)!! }
UsefulTestCase.assertSameElements(actualDescriptors, expectedDescriptors)
}
}
@@ -42,7 +42,7 @@ fun generateRuntimeModuleRepositoryForTests(monorepoProject: JpsProject): Runtim
//the repository won't be saved on disk so the actual location of the directory doesn't matter much
val outputDirectory = JpsModelSerializationDataService.getBaseDirectoryPath(monorepoProject)!!.resolve("out/module-descriptors-for-tests")
val repositoryData = RawRuntimeModuleRepositoryData(moduleDescriptors.associateBy { it.id }, outputDirectory, null)
val repositoryData = RawRuntimeModuleRepositoryData.create(moduleDescriptors.associateBy { it.moduleId }, outputDirectory, null)
return RuntimeModuleRepositoryImpl(outputDirectory.resolve(RuntimeModuleRepositoryGenerator.COMPACT_REPOSITORY_FILE_NAME), repositoryData)
}
@@ -53,7 +53,7 @@ object RuntimeModuleRepositoryGenerator {
generateDescriptorsForModules(descriptors, includedProduction, includedTests, resourcePathsSchema)
for (library in includedProjectLibraries) {
val moduleId = getProjectLibraryId(library) ?: error("Project-level library expected, but found: $library")
descriptors.add(RawRuntimeModuleDescriptor.create(moduleId.stringId, resourcePathsSchema.libraryPaths(library), emptyList()))
descriptors.add(RawRuntimeModuleDescriptor.create(moduleId, resourcePathsSchema.libraryPaths(library), emptyList()))
}
return descriptors
}
@@ -94,22 +94,22 @@ private fun generateDescriptorsForModules(
}
}
fun getRuntimeModuleName(module: JpsModule, tests: Boolean): String {
fun getRuntimeModuleName(module: JpsModule, tests: Boolean): RuntimeModuleId {
val moduleName = module.name
if (tests) {
if (moduleName in productionModulesWithTestRoots) {
return moduleName + RuntimeModuleId.TESTS_NAME_SUFFIX + "2"
return RuntimeModuleId.raw(moduleName + RuntimeModuleId.TESTS_NAME_SUFFIX + "2")
}
if (!moduleName.endsWith(RuntimeModuleId.TESTS_NAME_SUFFIX)) {
return moduleName + RuntimeModuleId.TESTS_NAME_SUFFIX
return RuntimeModuleId.moduleTests(moduleName)
}
}
else {
if (moduleName in testModulesWithProductionRoots) {
return moduleName + "2"
return RuntimeModuleId.raw(moduleName + "2")
}
}
return moduleName
return RuntimeModuleId.module(moduleName)
}
for (module in includedProduction) {
@@ -142,15 +142,15 @@ private val JpsModule.hasTestSources
private val JpsModule.hasProductionSources
get() = sourceRoots.any { it.rootType in JavaModuleSourceRootTypes.PRODUCTION }
private fun createProductionPartDescriptor(module: JpsModule, runtimeModuleNameGenerator: (JpsModule, Boolean) -> String, resourcePathsSchema: ResourcePathsSchema): RawRuntimeModuleDescriptor {
val dependencies = LinkedHashSet<String>()
private fun createProductionPartDescriptor(module: JpsModule, runtimeModuleNameGenerator: (JpsModule, Boolean) -> RuntimeModuleId, resourcePathsSchema: ResourcePathsSchema): RawRuntimeModuleDescriptor {
val dependencies = LinkedHashSet<RuntimeModuleId>()
val resourcePaths = if (module.hasProductionSources) resourcePathsSchema.moduleOutputPaths(module).toMutableSet() else mutableSetOf()
enumerateRuntimeDependencies(module).productionOnly().processModuleAndLibraries(
{ dependencies.add(runtimeModuleNameGenerator(it, false)) },
{ library ->
val projectLibraryId = getProjectLibraryId(library)
if (projectLibraryId != null) {
dependencies.add(projectLibraryId.stringId)
dependencies.add(projectLibraryId)
}
else {
resourcePaths.addAll(resourcePathsSchema.libraryPaths(library))
@@ -169,7 +169,7 @@ private fun createProductionPartDescriptor(module: JpsModule, runtimeModuleNameG
*/
private fun createTestPartDescriptor(
module: JpsModule,
runtimeModuleNameGenerator: (JpsModule, Boolean) -> String,
runtimeModuleNameGenerator: (JpsModule, Boolean) -> RuntimeModuleId,
additionalDependenciesForTestsCache: MutableMap<JpsModule, DependenciesAndResources>,
productionDependenciesCache: MutableMap<JpsModule, DependenciesAndResources>,
resourcePathsSchema: ResourcePathsSchema,
@@ -187,7 +187,7 @@ private fun createTestPartDescriptor(
resourcePathsSchema
)
forTests.copyTo(dependencies, resourcePaths)
return RawRuntimeModuleDescriptor.create(runtimeModuleNameGenerator(module, true), resourcePaths.toList(), dependencies.map { it.stringId })
return RawRuntimeModuleDescriptor.create(runtimeModuleNameGenerator(module, true), resourcePaths.toList(), dependencies.toList())
}
/**
@@ -196,7 +196,7 @@ private fun createTestPartDescriptor(
private fun collectProductionDependenciesForModule(
module: JpsModule,
productionDependenciesCache: MutableMap<JpsModule, DependenciesAndResources>,
runtimeModuleNameGenerator: (JpsModule, Boolean) -> String,
runtimeModuleNameGenerator: (JpsModule, Boolean) -> RuntimeModuleId,
resourcePathsSchema: ResourcePathsSchema,
) : DependenciesAndResources {
val cached = productionDependenciesCache[module]
@@ -204,7 +204,7 @@ private fun collectProductionDependenciesForModule(
return cached
}
if (module.hasDescriptorForProduction) {
val result = DependenciesAndResources(setOf(RuntimeModuleId.raw(runtimeModuleNameGenerator(module, false))), emptySet())
val result = DependenciesAndResources(setOf(runtimeModuleNameGenerator(module, false)), emptySet())
productionDependenciesCache[module] = result
return result
}
@@ -256,7 +256,7 @@ private fun collectAdditionalRuntimeDependenciesAndResourcesForTests(
module: JpsModule,
productionDependenciesCache: MutableMap<JpsModule, DependenciesAndResources>,
additionalDependenciesForTestsCache: MutableMap<JpsModule, DependenciesAndResources>,
runtimeModuleNameGenerator: (JpsModule, Boolean) -> String,
runtimeModuleNameGenerator: (JpsModule, Boolean) -> RuntimeModuleId,
resourcePathsSchema: ResourcePathsSchema
): DependenciesAndResources {
val cached = additionalDependenciesForTestsCache[module]
@@ -274,7 +274,7 @@ private fun collectAdditionalRuntimeDependenciesAndResourcesForTests(
if (scope == JpsJavaDependencyScope.PROVIDED) continue
if (dependencyModule.hasTestSources) {
dependencies.add(RuntimeModuleId.raw(runtimeModuleNameGenerator(dependencyModule, true)))
dependencies.add(runtimeModuleNameGenerator(dependencyModule, true))
}
else {
if (scope == JpsJavaDependencyScope.TEST) {
@@ -1,18 +1,19 @@
// 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.platform.runtime.repository.RuntimeModuleId
import com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleDescriptor
object RuntimeModuleRepositoryValidator {
interface ErrorReporter {
fun reportDuplicatingId(moduleId: String)
fun reportDuplicatingId(moduleId: RuntimeModuleId)
}
fun validate(descriptors: List<RawRuntimeModuleDescriptor>, errorReporter: ErrorReporter) {
val moduleIDs = HashSet<String>()
val moduleIDs = HashSet<RuntimeModuleId>()
for (descriptor in descriptors) {
if (!moduleIDs.add(descriptor.id)) {
errorReporter.reportDuplicatingId(descriptor.id)
if (!moduleIDs.add(descriptor.moduleId)) {
errorReporter.reportDuplicatingId(descriptor.moduleId)
}
}
}
@@ -6,6 +6,7 @@ import com.intellij.devkit.runtimeModuleRepository.generator.RuntimeModuleReposi
import com.intellij.devkit.runtimeModuleRepository.generator.RuntimeModuleRepositoryValidator
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
@@ -53,8 +54,8 @@ internal class RuntimeModuleRepositoryBuilder
LOG.info("${descriptors.size} descriptors are created in ${timeToCreateDescriptors}ms")
val errorReporter = object : RuntimeModuleRepositoryValidator.ErrorReporter {
override fun reportDuplicatingId(moduleId: String) {
context.reportError(DevkitRuntimeModuleRepositoryJpsBundle.message("error.message.duplicating.id.0.is.found", moduleId))
override fun reportDuplicatingId(moduleId: RuntimeModuleId) {
context.reportError(DevkitRuntimeModuleRepositoryJpsBundle.message("error.message.duplicating.id.0.is.found", moduleId.presentableName))
}
}
RuntimeModuleRepositoryValidator.validate(descriptors, errorReporter)
@@ -21,12 +21,12 @@ private fun checkRuntimeModuleRepository(
buildRepositoryData: RawRuntimeModuleRepositoryData,
expected: RawDescriptorListBuilder.() -> Unit,
) {
val actualIds = buildRepositoryData.allIds.filter { it != RUNTIME_REPOSITORY_MARKER_MODULE && it != "${RUNTIME_REPOSITORY_MARKER_MODULE}${RuntimeModuleId.TESTS_NAME_SUFFIX}" }
val actualIds = buildRepositoryData.allModuleIds.filter { it != RUNTIME_REPOSITORY_MARKER_MODULE && it != RUNTIME_REPOSITORY_TESTS_MARKER_MODULE }
val builder = RawDescriptorListBuilder()
builder.expected()
JpsBuildTestCase.assertSameElements(actualIds, builder.descriptors.map { it.id })
JpsBuildTestCase.assertSameElements(actualIds, builder.descriptors.map { it.moduleId })
for (expectedDescriptor in builder.descriptors) {
JpsBuildTestCase.assertEquals("Different data for '${expectedDescriptor.id}'.", expectedDescriptor, buildRepositoryData.findDescriptor(expectedDescriptor.id)!!)
JpsBuildTestCase.assertEquals("Different data for '${expectedDescriptor.moduleId.presentableName}'.", expectedDescriptor, buildRepositoryData.findDescriptor(expectedDescriptor.moduleId)!!)
}
}
@@ -45,8 +45,9 @@ class RawDescriptorListBuilder {
}
fun descriptor(id: String, resources: List<String>, dependencies: List<String>) {
descriptors.add(RawRuntimeModuleDescriptor.create(id, resources, dependencies))
descriptors.add(RawRuntimeModuleDescriptor.create(RuntimeModuleId.raw(id), resources, dependencies.map { RuntimeModuleId.raw(it) }))
}
}
const val RUNTIME_REPOSITORY_MARKER_MODULE: String = "intellij.idea.community.main"
internal val RUNTIME_REPOSITORY_MARKER_MODULE: RuntimeModuleId = RuntimeModuleId.module("intellij.idea.community.main")
internal val RUNTIME_REPOSITORY_TESTS_MARKER_MODULE: RuntimeModuleId = RuntimeModuleId.moduleTests("intellij.idea.community.main")
@@ -14,7 +14,7 @@ import kotlin.io.path.writeText
abstract class RuntimeModuleRepositoryTestCase : JpsBuildTestCase() {
override fun setUp() {
super.setUp()
addModule(RUNTIME_REPOSITORY_MARKER_MODULE)
addModule(RUNTIME_REPOSITORY_MARKER_MODULE.stringId)
JpsJavaExtensionService.getInstance().getOrCreateProjectExtension(myProject).outputUrl = getUrl("out")
val projectDir = Path(getAbsolutePath("project"))
val modulesXml = projectDir.resolve(".idea/modules.xml")