mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-16 14:23:28 +07:00
[runtime module repository] implement a more efficient format for the repository (IJPL-189949)
A new implementation which generates and loads the runtime module repository from a module-descriptors.dat file in binary format is implemented. module-descriptors.jar in the old format is still generated for compatibility with other tools (e.g., IntelliJ Platform Gradle Plugin) and to provide a human-readable view. It's also used as a fallback variant if module-descriptors.dat is absent. The new format speeds up loading by around 10 times. GitOrigin-RevId: b17ba7b53f825e6dcf243ff0aa5b7aedaf7ab9e2
This commit is contained in:
committed by
intellij-monorepo-bot
parent
1ad00d2a66
commit
791282fbe7
@@ -37,7 +37,11 @@
|
||||
- getBasePath():java.nio.file.Path
|
||||
- getMainPluginModuleId():java.lang.String
|
||||
*f:com.intellij.platform.runtime.repository.serialization.RuntimeModuleRepositorySerialization
|
||||
- s:loadBootstrapClasspath(java.nio.file.Path,java.lang.String):java.lang.String[]
|
||||
- s:loadFromCompactFile(java.nio.file.Path):com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleRepositoryData
|
||||
- s:loadFromJar(java.nio.file.Path):com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleRepositoryData
|
||||
- s:loadFromRawData(java.nio.file.Path,com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleRepositoryData):com.intellij.platform.runtime.repository.RuntimeModuleRepository
|
||||
- s:saveToCompactFile(java.util.Collection,java.lang.String,java.nio.file.Path,I):V
|
||||
- s:saveToCompactFile(java.util.Collection,java.lang.String,java.nio.file.Path,java.lang.String,I):V
|
||||
- s:saveToJar(java.util.Collection,java.lang.String,java.nio.file.Path,I):V
|
||||
- s:saveToJar(java.util.Collection,java.lang.String,java.nio.file.Path,java.lang.String,I):V
|
||||
|
||||
@@ -17,10 +17,10 @@ import java.util.List;
|
||||
@ApiStatus.NonExtendable
|
||||
public interface RuntimeModuleRepository {
|
||||
/**
|
||||
* Creates a repository from a JAR file containing module descriptors.
|
||||
* Creates a repository from a file containing module descriptors.
|
||||
*/
|
||||
static @NotNull RuntimeModuleRepository create(@NotNull Path moduleDescriptorsJarPath) throws MalformedRepositoryException {
|
||||
return new RuntimeModuleRepositoryImpl(moduleDescriptorsJarPath);
|
||||
static @NotNull RuntimeModuleRepository create(@NotNull Path moduleDescriptorsFilePath) throws MalformedRepositoryException {
|
||||
return new RuntimeModuleRepositoryImpl(moduleDescriptorsFilePath);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,7 +8,6 @@ import com.intellij.platform.runtime.repository.RuntimeModuleRepository;
|
||||
import com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleDescriptor;
|
||||
import com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleRepositoryData;
|
||||
import com.intellij.platform.runtime.repository.serialization.RuntimeModuleRepositorySerialization;
|
||||
import com.intellij.platform.runtime.repository.serialization.impl.JarFileSerializer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -22,15 +21,15 @@ public class RuntimeModuleRepositoryImpl implements RuntimeModuleRepository {
|
||||
private final Map<RuntimeModuleId, ResolveResult> myResolveResults;
|
||||
private volatile RawRuntimeModuleRepositoryData myMainData;
|
||||
private volatile List<RawRuntimeModuleRepositoryData> myAdditionalData;
|
||||
private final Path myDescriptorsJarPath;
|
||||
private final Path myDescriptorsFilePath;
|
||||
private final Map<String, RuntimeModuleId> myInternedModuleIds;
|
||||
|
||||
public RuntimeModuleRepositoryImpl(@NotNull Path descriptorsJarPath) {
|
||||
this(descriptorsJarPath, null);
|
||||
public RuntimeModuleRepositoryImpl(@NotNull Path descriptorsFilePath) {
|
||||
this(descriptorsFilePath, null);
|
||||
}
|
||||
|
||||
public RuntimeModuleRepositoryImpl(@NotNull Path descriptorsJarPath, @Nullable RawRuntimeModuleRepositoryData preloadedMainData) {
|
||||
myDescriptorsJarPath = descriptorsJarPath;
|
||||
public RuntimeModuleRepositoryImpl(@NotNull Path descriptorsFilePath, @Nullable RawRuntimeModuleRepositoryData preloadedMainData) {
|
||||
myDescriptorsFilePath = descriptorsFilePath;
|
||||
myResolveResults = new ConcurrentHashMap<>();
|
||||
myInternedModuleIds = new ConcurrentHashMap<>();
|
||||
myMainData = preloadedMainData;
|
||||
@@ -144,11 +143,11 @@ public class RuntimeModuleRepositoryImpl implements RuntimeModuleRepository {
|
||||
public @NotNull List<@NotNull Path> getBootstrapClasspath(@NotNull String bootstrapModuleName) {
|
||||
if (myMainData == null) {
|
||||
try {
|
||||
String[] bootstrapClasspath = JarFileSerializer.loadBootstrapClasspath(myDescriptorsJarPath, bootstrapModuleName);
|
||||
String[] bootstrapClasspath = RuntimeModuleRepositorySerialization.loadBootstrapClasspath(myDescriptorsFilePath, bootstrapModuleName);
|
||||
if (bootstrapClasspath != null) {
|
||||
List<Path> result = new ArrayList<>(bootstrapClasspath.length);
|
||||
for (String relativePath : bootstrapClasspath) {
|
||||
result.add(myDescriptorsJarPath.getParent().resolve(relativePath));
|
||||
result.add(myDescriptorsFilePath.getParent().resolve(relativePath));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -174,12 +173,18 @@ public class RuntimeModuleRepositoryImpl implements RuntimeModuleRepository {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RuntimeModuleRepository{descriptorsJarPath=" + myDescriptorsJarPath + '}';
|
||||
return "RuntimeModuleRepository{descriptorsFilePath=" + myDescriptorsFilePath + '}';
|
||||
}
|
||||
|
||||
private RawRuntimeModuleRepositoryData getMainData() {
|
||||
if (myMainData == null) {
|
||||
myMainData = RuntimeModuleRepositorySerialization.loadFromJar(myDescriptorsJarPath);
|
||||
Path fallbackJarPath = RuntimeModuleRepositorySerialization.getFallbackJarPath(myDescriptorsFilePath);
|
||||
if (fallbackJarPath != null) {
|
||||
myMainData = RuntimeModuleRepositorySerialization.loadFromJar(fallbackJarPath);
|
||||
}
|
||||
else {
|
||||
myMainData = RuntimeModuleRepositorySerialization.loadFromCompactFile(myDescriptorsFilePath);
|
||||
}
|
||||
}
|
||||
return myMainData;
|
||||
}
|
||||
|
||||
@@ -4,18 +4,32 @@ package com.intellij.platform.runtime.repository.serialization;
|
||||
import com.intellij.platform.runtime.repository.MalformedRepositoryException;
|
||||
import com.intellij.platform.runtime.repository.RuntimeModuleRepository;
|
||||
import com.intellij.platform.runtime.repository.impl.RuntimeModuleRepositoryImpl;
|
||||
import com.intellij.platform.runtime.repository.serialization.impl.CompactFileReader;
|
||||
import com.intellij.platform.runtime.repository.serialization.impl.CompactFileWriter;
|
||||
import com.intellij.platform.runtime.repository.serialization.impl.JarFileSerializer;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.xml.stream.XMLStreamException;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collection;
|
||||
|
||||
public final class RuntimeModuleRepositorySerialization {
|
||||
private RuntimeModuleRepositorySerialization() {}
|
||||
|
||||
public static void saveToCompactFile(@NotNull Collection<RawRuntimeModuleDescriptor> descriptors, @Nullable String bootstrapModuleName,
|
||||
@NotNull Path filePath, int generatorVersion) throws IOException {
|
||||
saveToCompactFile(descriptors, bootstrapModuleName, filePath, null, generatorVersion);
|
||||
}
|
||||
|
||||
public static void saveToCompactFile(@NotNull Collection<RawRuntimeModuleDescriptor> descriptors, @Nullable String bootstrapModuleName,
|
||||
@NotNull Path filePath, @Nullable String mainPluginModuleId, int generatorVersion) throws IOException {
|
||||
CompactFileWriter.saveToFile(descriptors, bootstrapModuleName, mainPluginModuleId, generatorVersion, filePath);
|
||||
}
|
||||
|
||||
public static void saveToJar(@NotNull Collection<RawRuntimeModuleDescriptor> descriptors, @Nullable String bootstrapModuleName,
|
||||
@NotNull Path jarPath, int generatorVersion) throws IOException {
|
||||
saveToJar(descriptors, bootstrapModuleName, jarPath, null, generatorVersion);
|
||||
@@ -31,6 +45,15 @@ public final class RuntimeModuleRepositorySerialization {
|
||||
throw new IOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static @NotNull RawRuntimeModuleRepositoryData loadFromCompactFile(@NotNull Path filePath) throws MalformedRepositoryException {
|
||||
try {
|
||||
return CompactFileReader.loadFromFile(filePath);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new MalformedRepositoryException("Failed to load repository from " + filePath, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static @NotNull RawRuntimeModuleRepositoryData loadFromJar(@NotNull Path jarPath) throws MalformedRepositoryException {
|
||||
try {
|
||||
@@ -45,4 +68,25 @@ public final class RuntimeModuleRepositorySerialization {
|
||||
@NotNull RawRuntimeModuleRepositoryData rawRuntimeModuleRepositoryData) {
|
||||
return new RuntimeModuleRepositoryImpl(descriptorsJarPath, rawRuntimeModuleRepositoryData);
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static @Nullable Path getFallbackJarPath(@NotNull Path descriptorsFilePath) {
|
||||
if (descriptorsFilePath.getFileName().toString().endsWith(".jar")) {
|
||||
return descriptorsFilePath;
|
||||
}
|
||||
Path jarPath = descriptorsFilePath.getParent().resolve("module-descriptors.jar");
|
||||
if (!Files.exists(descriptorsFilePath) && Files.exists(jarPath)) {
|
||||
return jarPath;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static @NotNull String @Nullable [] loadBootstrapClasspath(@NotNull Path descriptorsFilePath, @NotNull String bootstrapModuleName)
|
||||
throws IOException {
|
||||
Path fallbackJarPath = getFallbackJarPath(descriptorsFilePath);
|
||||
if (fallbackJarPath != null) {
|
||||
return JarFileSerializer.loadBootstrapClasspath(fallbackJarPath, bootstrapModuleName);
|
||||
}
|
||||
return CompactFileReader.loadBootstrapClasspath(descriptorsFilePath, bootstrapModuleName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
// 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.MalformedRepositoryException;
|
||||
import com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleDescriptor;
|
||||
import com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleRepositoryData;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
public final class CompactFileReader {
|
||||
public static final int FORMAT_VERSION = 1;
|
||||
|
||||
public static RawRuntimeModuleRepositoryData loadFromFile(@NotNull Path filePath) throws IOException {
|
||||
try (DataInputStream in = new DataInputStream(new BufferedInputStream(Files.newInputStream(filePath)))) {
|
||||
int formatVersion = in.readInt();
|
||||
if (formatVersion != FORMAT_VERSION) {
|
||||
throw new MalformedRepositoryException("'" + filePath + "' has unsupported format '" + formatVersion + "'");
|
||||
}
|
||||
in.readInt();//generator version
|
||||
|
||||
boolean hasBootstrapClasspath = in.readBoolean();
|
||||
if (hasBootstrapClasspath) {
|
||||
in.readUTF();
|
||||
int size = in.readInt();
|
||||
for (int i = 0; i < size; i++) {
|
||||
in.readUTF();
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasMainPluginModule = in.readBoolean();
|
||||
String mainPluginModuleName = hasMainPluginModule? in.readUTF() : null;
|
||||
|
||||
Map<String, RawRuntimeModuleDescriptor> descriptors = new HashMap<>();
|
||||
|
||||
int descriptorsCount = in.readInt();
|
||||
String[] descriptorIds = new String[descriptorsCount];
|
||||
for (int i = 0; i < descriptorsCount; i++) {
|
||||
descriptorIds[i] = in.readUTF();
|
||||
}
|
||||
for (int i = 0; i < descriptorsCount; i++) {
|
||||
String descriptorId = descriptorIds[i];
|
||||
int dependenciesCount = in.readInt();
|
||||
List<String> dependencies = new ArrayList<>(dependenciesCount);
|
||||
for (int j = 0; j < dependenciesCount; j++) {
|
||||
int dependencyIndex = in.readInt();
|
||||
if (dependencyIndex < 0 || dependencyIndex >= descriptorsCount) {
|
||||
throw new MalformedRepositoryException("Invalid dependency index '" + dependencyIndex + "' in '" + descriptorId + "'");
|
||||
}
|
||||
dependencies.add(descriptorIds[dependencyIndex]);
|
||||
}
|
||||
int resourcePathsCount = in.readInt();
|
||||
List<String> resourcePaths = new ArrayList<>(resourcePathsCount);
|
||||
for (int j = 0; j < resourcePathsCount; j++) {
|
||||
resourcePaths.add(in.readUTF());
|
||||
}
|
||||
|
||||
descriptors.put(descriptorId, RawRuntimeModuleDescriptor.create(descriptorId, resourcePaths, dependencies));
|
||||
}
|
||||
return new RawRuntimeModuleRepositoryData(descriptors, filePath.getParent(), mainPluginModuleName);
|
||||
}
|
||||
}
|
||||
|
||||
public static @NotNull String @Nullable [] loadBootstrapClasspath(@NotNull Path binaryFile, @NotNull String bootstrapModuleName) throws IOException {
|
||||
try (DataInputStream in = new DataInputStream(new BufferedInputStream(Files.newInputStream(binaryFile)))) {
|
||||
int formatVersion = in.readInt();
|
||||
if (formatVersion != FORMAT_VERSION) return null;
|
||||
|
||||
in.readInt();
|
||||
|
||||
boolean hasBootstrap = in.readBoolean();
|
||||
if (!hasBootstrap) return null;
|
||||
|
||||
String actualBootstrapModuleName = in.readUTF();
|
||||
if (!actualBootstrapModuleName.equals(bootstrapModuleName)) return null;
|
||||
|
||||
int size = in.readInt();
|
||||
String[] classpath = new String[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
classpath[i] = in.readUTF();
|
||||
}
|
||||
return classpath;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// 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.MalformedRepositoryException;
|
||||
import com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleDescriptor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
public final class CompactFileWriter {
|
||||
public static void saveToFile(@NotNull Collection<RawRuntimeModuleDescriptor> originalDescriptors,
|
||||
@Nullable String bootstrapModuleName, @Nullable String mainPluginModuleId,
|
||||
int generatorVersion,
|
||||
@NotNull Path outputFile) throws IOException {
|
||||
try (DataOutputStream out = new DataOutputStream(new BufferedOutputStream(Files.newOutputStream(outputFile)))) {
|
||||
out.writeInt(CompactFileReader.FORMAT_VERSION);
|
||||
out.writeInt(generatorVersion);
|
||||
|
||||
boolean hasBootstrap = bootstrapModuleName != null;
|
||||
out.writeBoolean(hasBootstrap);
|
||||
if (hasBootstrap) {
|
||||
out.writeUTF(bootstrapModuleName);
|
||||
Collection<String> bootstrapClasspath = CachedClasspathComputation.computeClasspath(originalDescriptors, bootstrapModuleName);
|
||||
out.writeInt(bootstrapClasspath.size());
|
||||
for (String path : bootstrapClasspath) {
|
||||
out.writeUTF(path);
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasMainPluginModule = mainPluginModuleId != null;
|
||||
out.writeBoolean(hasMainPluginModule);
|
||||
if (hasMainPluginModule) {
|
||||
out.writeUTF(mainPluginModuleId);
|
||||
}
|
||||
|
||||
List<RawRuntimeModuleDescriptor> descriptors = new ArrayList<>(originalDescriptors);
|
||||
Collections.sort(descriptors, Comparator.comparing(RawRuntimeModuleDescriptor::getId));
|
||||
Map<String, Integer> indexes = new HashMap<>(descriptors.size());
|
||||
for (int i = 0; i < descriptors.size(); i++) {
|
||||
indexes.put(descriptors.get(i).getId(), i);
|
||||
}
|
||||
|
||||
out.writeInt(descriptors.size());
|
||||
for (RawRuntimeModuleDescriptor descriptor : descriptors) {
|
||||
out.writeUTF(descriptor.getId());
|
||||
}
|
||||
for (RawRuntimeModuleDescriptor descriptor : descriptors) {
|
||||
out.writeInt(descriptor.getDependencies().size());
|
||||
for (String dependency : descriptor.getDependencies()) {
|
||||
Integer index = indexes.get(dependency);
|
||||
if (index == null) {
|
||||
throw new MalformedRepositoryException("Unknown dependency '" + dependency + "' in '" + descriptor.getId() + "'");
|
||||
}
|
||||
out.writeInt(index);
|
||||
}
|
||||
out.writeInt(descriptor.getResourcePaths().size());
|
||||
for (String path : descriptor.getResourcePaths()) {
|
||||
out.writeUTF(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ jvm_library(
|
||||
"//platform/util-ex",
|
||||
"//platform/testFramework",
|
||||
"//platform/testFramework:testFramework_test_lib",
|
||||
"@lib//:junit5Pioneer",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
@@ -10,5 +10,6 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.runtime.repository" />
|
||||
<orderEntry type="module" module-name="intellij.platform.util.ex" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.testFramework" scope="TEST" />
|
||||
<orderEntry type="library" scope="TEST" name="JUnit5Pioneer" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -11,8 +11,7 @@ import com.intellij.testFramework.rules.TempDirectoryExtension
|
||||
import org.junit.jupiter.api.Assertions.*
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.RegisterExtension
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.ValueSource
|
||||
import org.junitpioneer.jupiter.cartesian.CartesianTest
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.Path
|
||||
|
||||
@@ -153,18 +152,27 @@ class RepositoryTest {
|
||||
assertEquals(listOf("bar.jar", "foo.jar", "baz.jar").map { tempDirectory.rootPath.resolve(it) }, classpath)
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "stored bootstrap module = {0}")
|
||||
@ValueSource(strings = ["", "ij.foo", "ij.bar"])
|
||||
fun `bootstrap classpath`(storedBootstrapModule: String) {
|
||||
@CartesianTest(name = "stored bootstrap module = {0}, loadFromCompact = {1}")
|
||||
fun `bootstrap classpath`(
|
||||
@CartesianTest.Values(strings = ["", "ij.foo", "ij.bar"]) storedBootstrapModule: String,
|
||||
@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")),
|
||||
)
|
||||
val basePath = tempDirectory.rootPath
|
||||
val moduleDescriptorsJarPath = basePath.resolve("module-descriptors.jar")
|
||||
val bootstrapModuleName = storedBootstrapModule.takeIf { it.isNotEmpty() }
|
||||
RuntimeModuleRepositorySerialization.saveToJar(descriptors.asList(), bootstrapModuleName, moduleDescriptorsJarPath, 0)
|
||||
val repository = RuntimeModuleRepository.create(moduleDescriptorsJarPath)
|
||||
val filePath: Path
|
||||
if (loadFromCompact) {
|
||||
filePath = basePath.resolve("module-descriptors.dat")
|
||||
RuntimeModuleRepositorySerialization.saveToCompactFile(descriptors.asList(), bootstrapModuleName, filePath, 0)
|
||||
}
|
||||
else {
|
||||
filePath = basePath.resolve("module-descriptors.jar")
|
||||
RuntimeModuleRepositorySerialization.saveToJar(descriptors.asList(), bootstrapModuleName, filePath, 0)
|
||||
}
|
||||
val repository = RuntimeModuleRepository.create(filePath)
|
||||
assertEquals(listOf(basePath.resolve("bar.jar"), basePath.resolve("foo.jar")), repository.getBootstrapClasspath("ij.bar"))
|
||||
}
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ fun DirectoryContentBuilder.xml(name: String, @Language("XML") content: String)
|
||||
}
|
||||
|
||||
fun createRepository(basePath: Path, vararg descriptors: RawRuntimeModuleDescriptor): RuntimeModuleRepository {
|
||||
val moduleDescriptorsJarPath = basePath.resolve("module-descriptors.jar")
|
||||
return RuntimeModuleRepositoryImpl(moduleDescriptorsJarPath,
|
||||
val moduleDescriptorsPath = basePath.resolve("module-descriptors.dat")
|
||||
return RuntimeModuleRepositoryImpl(moduleDescriptorsPath,
|
||||
RawRuntimeModuleRepositoryData(descriptors.associateBy { it.id }, basePath, null))
|
||||
}
|
||||
|
||||
|
||||
@@ -5,12 +5,10 @@ import com.intellij.platform.runtime.repository.serialization.impl.JarFileSerial
|
||||
import com.intellij.platform.runtime.repository.xml
|
||||
import com.intellij.testFramework.UsefulTestCase
|
||||
import com.intellij.testFramework.rules.TempDirectoryExtension
|
||||
import com.intellij.util.io.DirectoryContentBuilder
|
||||
import com.intellij.util.io.DirectoryContentSpec
|
||||
import com.intellij.util.io.assertMatches
|
||||
import com.intellij.util.io.jarFile
|
||||
import com.intellij.util.io.*
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.extension.RegisterExtension
|
||||
import java.nio.file.Path
|
||||
|
||||
class JarRepositorySerializationTest {
|
||||
@JvmField
|
||||
@@ -111,19 +109,26 @@ class JarRepositorySerializationTest {
|
||||
}
|
||||
content()
|
||||
}
|
||||
checkSaving(descriptors, bootstrapModuleName, jarFile)
|
||||
checkLoading(jarFile, descriptors)
|
||||
val out = tempDirectory.rootPath
|
||||
val jarFilePath = out.resolve("module-descriptors.jar")
|
||||
RuntimeModuleRepositorySerialization.saveToJar(descriptors, bootstrapModuleName, jarFilePath, 0)
|
||||
jarFilePath.assertMatches(jarFile)
|
||||
|
||||
val compactFilePath = out.resolve("module-descriptors.dat")
|
||||
RuntimeModuleRepositorySerialization.saveToCompactFile(descriptors, bootstrapModuleName, compactFilePath, 0)
|
||||
checkLoadingFromCompactFile(compactFilePath, descriptors)
|
||||
checkLoadingFromJar(jarFile, descriptors)
|
||||
}
|
||||
|
||||
private fun checkLoading(zipFileSpec: DirectoryContentSpec, expectedDescriptors: List<RawRuntimeModuleDescriptor>) {
|
||||
val repositoryData = RuntimeModuleRepositorySerialization.loadFromJar(zipFileSpec.generateInTempDir())
|
||||
private fun checkLoadingFromCompactFile(filePath: Path, expectedDescriptors: List<RawRuntimeModuleDescriptor>) {
|
||||
val repositoryData = RuntimeModuleRepositorySerialization.loadFromCompactFile(filePath)
|
||||
val actualDescriptors = repositoryData.allIds.map { repositoryData.findDescriptor(it)!! }
|
||||
UsefulTestCase.assertSameElements(actualDescriptors, expectedDescriptors)
|
||||
}
|
||||
|
||||
private fun checkSaving(descriptors: List<RawRuntimeModuleDescriptor>, bootstrapModuleName: String?, zipFileSpec: DirectoryContentSpec) {
|
||||
val jarFile = tempDirectory.rootPath.resolve("descriptors.jar")
|
||||
RuntimeModuleRepositorySerialization.saveToJar(descriptors, bootstrapModuleName, jarFile, 0)
|
||||
jarFile.assertMatches(zipFileSpec)
|
||||
private fun checkLoadingFromJar(zipFileSpec: DirectoryContentSpec, expectedDescriptors: List<RawRuntimeModuleDescriptor>) {
|
||||
val repositoryData = RuntimeModuleRepositorySerialization.loadFromJar(zipFileSpec.generateInTempDir())
|
||||
val actualDescriptors = repositoryData.allIds.map { repositoryData.findDescriptor(it)!! }
|
||||
UsefulTestCase.assertSameElements(actualDescriptors, expectedDescriptors)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
build.target.intellij.runtime.module.descriptors=IntelliJ Runtime Module Descriptors
|
||||
builder.name.intellij.runtime.module.descriptors=IntelliJ runtime module descriptors builder
|
||||
error.message.duplicating.id.0.is.found=Duplicating ID ''{0}'' is found
|
||||
error.message.failed.to.save.jar.file.0=Failed to save JAR file: {0}
|
||||
error.message.failed.to.save.repository.0=Failed to save the repository: {0}
|
||||
error.message.project.compiler.output.directory.is.not.specified=Project compiler output directory is not specified.
|
||||
progress.message.generating.intellij.modules.repository=Generating IntelliJ Modules Repository\u2026
|
||||
@@ -3,6 +3,7 @@ package com.intellij.devkit.runtimeModuleRepository.jps.build
|
||||
|
||||
object RuntimeModuleRepositoryBuildConstants {
|
||||
const val JAR_REPOSITORY_FILE_NAME: String = "module-descriptors.jar"
|
||||
const val COMPACT_REPOSITORY_FILE_NAME: String = "module-descriptors.dat"
|
||||
const val GENERATOR_VERSION: Int = 2
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.devkit.runtimeModuleRepository.jps.build
|
||||
|
||||
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
|
||||
@@ -8,6 +9,7 @@ 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
|
||||
import org.jetbrains.annotations.Nls
|
||||
import org.jetbrains.jps.builders.BuildOutputConsumer
|
||||
import org.jetbrains.jps.builders.BuildRootDescriptor
|
||||
@@ -74,19 +76,27 @@ internal class RuntimeModuleRepositoryBuilder
|
||||
context.reportError(DevkitRuntimeModuleRepositoryJpsBundle.message("error.message.project.compiler.output.directory.is.not.specified"))
|
||||
return
|
||||
}
|
||||
val outputPath = Path.of(JpsPathUtil.urlToOsPath (outputUrl), JAR_REPOSITORY_FILE_NAME)
|
||||
val timeToSaveDescriptors = measureTimeMillis {
|
||||
try {
|
||||
RuntimeModuleRepositorySerialization.saveToJar(descriptors, null, outputPath, GENERATOR_VERSION)
|
||||
}
|
||||
catch (e: IOException) {
|
||||
LOG.info(e)
|
||||
context.reportError(DevkitRuntimeModuleRepositoryJpsBundle.message("error.message.failed.to.save.jar.file.0", e.message ?: ""))
|
||||
}
|
||||
}
|
||||
val outputDir = Path.of(JpsPathUtil.urlToOsPath(outputUrl))
|
||||
val modulesXml = RuntimeModuleRepositoryTarget.getModulesXmlFile(project) ?: error("Project was not loaded from .idea")
|
||||
outputConsumer.registerOutputFile(outputPath.toFile(), listOf(modulesXml.absolutePath))
|
||||
LOG.info("${descriptors.size} descriptors are saved in ${timeToSaveDescriptors}ms")
|
||||
try {
|
||||
val jarRepositoryPath = outputDir.resolve(JAR_REPOSITORY_FILE_NAME)
|
||||
val timeToSaveDescriptorsToJar = measureTimeMillis {
|
||||
RuntimeModuleRepositorySerialization.saveToJar(descriptors, null, jarRepositoryPath, null, GENERATOR_VERSION)
|
||||
}
|
||||
outputConsumer.registerOutputFile(jarRepositoryPath.toFile(), listOf(modulesXml.absolutePath))
|
||||
LOG.info("${descriptors.size} descriptors are saved to JAR in ${timeToSaveDescriptorsToJar}ms")
|
||||
|
||||
val compactRepositoryPath = outputDir.resolve(COMPACT_REPOSITORY_FILE_NAME)
|
||||
val timeToSaveDescriptorsToCompactFile = measureTimeMillis {
|
||||
CompactFileWriter.saveToFile(descriptors, null, null, GENERATOR_VERSION, compactRepositoryPath)
|
||||
}
|
||||
LOG.info("${descriptors.size} descriptors are saved in compact format in ${timeToSaveDescriptorsToCompactFile}ms")
|
||||
outputConsumer.registerOutputFile(compactRepositoryPath.toFile(), listOf(modulesXml.absolutePath))
|
||||
}
|
||||
catch (e: IOException) {
|
||||
LOG.info(e)
|
||||
context.reportError(DevkitRuntimeModuleRepositoryJpsBundle.message("error.message.failed.to.save.repository.0", e.message ?: ""))
|
||||
}
|
||||
}
|
||||
|
||||
private fun CompileContext.reportError(message: @Nls String) {
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
package com.intellij.devkit.runtimeModuleRepository.jps.build
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashSink
|
||||
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
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.platform.runtime.repository.serialization.impl.CompactFileReader
|
||||
import com.intellij.platform.runtime.repository.serialization.impl.JarFileSerializer
|
||||
import org.jetbrains.jps.builders.*
|
||||
import org.jetbrains.jps.builders.impl.BuildRootDescriptorImpl
|
||||
@@ -69,11 +71,14 @@ internal class RuntimeModuleRepositoryTarget(
|
||||
override fun getOutputRoots(context: CompileContext): Collection<File> {
|
||||
val project = context.projectDescriptor.project
|
||||
val outputUrl = JpsJavaExtensionService.getInstance().getProjectExtension(project)?.outputUrl ?: return emptyList()
|
||||
return java.util.List.of(File(JpsPathUtil.urlToFile(outputUrl), JAR_REPOSITORY_FILE_NAME))
|
||||
val outputDir = JpsPathUtil.urlToFile(outputUrl)
|
||||
return java.util.List.of(File(outputDir, JAR_REPOSITORY_FILE_NAME),
|
||||
File(outputDir, COMPACT_REPOSITORY_FILE_NAME))
|
||||
}
|
||||
|
||||
override fun computeConfigurationDigest(projectDescriptor: ProjectDescriptor, hash: HashSink) {
|
||||
hash.putString(JarFileSerializer.SPECIFICATION_VERSION)
|
||||
hash.putInt(CompactFileReader.FORMAT_VERSION)
|
||||
hash.putInt(RuntimeModuleRepositoryBuildConstants.GENERATOR_VERSION)
|
||||
|
||||
val time = measureTimeMillis {
|
||||
|
||||
@@ -3,14 +3,23 @@ package com.intellij.devkit.runtimeModuleRepository.jps.build
|
||||
|
||||
import com.intellij.platform.runtime.repository.RuntimeModuleId
|
||||
import com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleDescriptor
|
||||
import com.intellij.platform.runtime.repository.serialization.RawRuntimeModuleRepositoryData
|
||||
import com.intellij.platform.runtime.repository.serialization.RuntimeModuleRepositorySerialization
|
||||
import org.jetbrains.jps.builders.JpsBuildTestCase
|
||||
import java.nio.file.Path
|
||||
|
||||
fun checkRuntimeModuleRepository(outputDir: Path,
|
||||
expected: RawDescriptorListBuilder.() -> Unit) {
|
||||
val zipPath = outputDir.resolve(RuntimeModuleRepositoryBuildConstants.JAR_REPOSITORY_FILE_NAME)
|
||||
val buildRepositoryData = RuntimeModuleRepositorySerialization.loadFromJar(zipPath)
|
||||
val jarPath = outputDir.resolve(RuntimeModuleRepositoryBuildConstants.JAR_REPOSITORY_FILE_NAME)
|
||||
checkRuntimeModuleRepository(RuntimeModuleRepositorySerialization.loadFromJar(jarPath), expected)
|
||||
val compactPath = outputDir.resolve(RuntimeModuleRepositoryBuildConstants.COMPACT_REPOSITORY_FILE_NAME)
|
||||
checkRuntimeModuleRepository(RuntimeModuleRepositorySerialization.loadFromCompactFile(compactPath), expected)
|
||||
}
|
||||
|
||||
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 builder = RawDescriptorListBuilder()
|
||||
builder.expected()
|
||||
|
||||
@@ -83,7 +83,7 @@ class RuntimeModuleRepositoryIncrementalBuildTest : RuntimeModuleRepositoryTestC
|
||||
descriptor("a")
|
||||
}
|
||||
|
||||
deleteFile("out/${RuntimeModuleRepositoryBuildConstants.JAR_REPOSITORY_FILE_NAME}")
|
||||
deleteFile("out/${RuntimeModuleRepositoryBuildConstants.COMPACT_REPOSITORY_FILE_NAME}")
|
||||
buildAndCheck {
|
||||
descriptor("a")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user