IJPL-866 separate product modules on a class loader level (part 2)

GitOrigin-RevId: 0d10fdd0619f39e5d70db94106833928e0e57e93
This commit is contained in:
Vladimir Krivosheev
2024-03-31 21:08:05 +03:00
committed by intellij-monorepo-bot
parent 6fb57f5b2d
commit a6711620be
6 changed files with 83 additions and 61 deletions
@@ -56,9 +56,8 @@ fun getIdeSystemProperties(runDir: Path): Map<String, String> {
/** Returns IDE installation directory */
suspend fun buildProductInProcess(request: BuildRequest): Path {
return TraceManager.spanBuilder("build ide").setAttribute("request", request.toString()).useWithScope {
val platformPrefix = request.platformPrefix
val configuration = createConfiguration(homePath = request.homePath, productionClassOutput = request.productionClassOutput)
val productConfiguration = getProductConfiguration(configuration, platformPrefix)
val productConfiguration = getProductConfiguration(configuration, request.platformPrefix)
try {
buildProduct(productConfiguration = productConfiguration, request = request)
}
@@ -186,7 +186,12 @@ internal suspend fun buildProduct(productConfiguration: ProductConfiguration, re
}
launch {
computeIdeFingerprint(platformDistributionEntriesDeferred, pluginDistributionEntriesDeferred, runDir, request.homePath)
computeIdeFingerprint(
platformDistributionEntriesDeferred = platformDistributionEntriesDeferred,
pluginDistributionEntriesDeferred = pluginDistributionEntriesDeferred,
runDir = runDir,
homePath = request.homePath,
)
}
}
.invokeOnCompletion {
@@ -24,8 +24,8 @@ import org.jetbrains.intellij.build.io.runJava
import java.nio.file.Files
import java.nio.file.NoSuchFileException
import java.nio.file.Path
import java.nio.file.StandardCopyOption
import java.util.function.Predicate
import kotlin.io.path.copyTo
import kotlin.time.Duration
internal fun span(spanBuilder: SpanBuilder, task: Runnable) {
@@ -104,7 +104,7 @@ suspend fun runApplicationStarter(
BuildUtils.addVmProperty(jvmArgs, "java.system.class.loader", "com.intellij.util.lang.PathClassLoader")
BuildUtils.addVmProperty(jvmArgs, "idea.platform.prefix", context.productProperties.platformPrefix)
jvmArgs.addAll(BuildUtils.propertiesToJvmArgs(systemProperties.entries.map { it.key to it.value.toString() }))
jvmArgs.addAll(vmOptions.takeIf { it.isNotEmpty() } ?: listOf("-Xmx1536m"))
jvmArgs.addAll(vmOptions.takeIf { it.isNotEmpty() } ?: listOf("-Xmx2g"))
System.getProperty("intellij.build.${arguments.first()}.debug.port")?.let {
jvmArgs.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:$it")
}
@@ -135,7 +135,7 @@ suspend fun runApplicationStarter(
val logFile = systemDir.resolve("log").resolve("idea.log")
if (Files.exists(logFile)) {
val logFileToPublish = Files.createTempFile("idea-", ".log")
logFile.copyTo(target = logFileToPublish, overwrite = true)
Files.copy(logFile, logFileToPublish, StandardCopyOption.REPLACE_EXISTING)
context.notifyArtifactBuilt(logFileToPublish)
Span.current().addEvent("log file $logFileToPublish attached to build artifacts")
}
@@ -29,9 +29,6 @@ import org.jetbrains.idea.maven.aether.ArtifactRepositoryManager
import org.jetbrains.idea.maven.aether.ProgressConsumer
import org.jetbrains.intellij.build.*
import org.jetbrains.intellij.build.TraceManager.spanBuilder
import org.jetbrains.intellij.build.dev.BuildRequest
import org.jetbrains.intellij.build.dev.buildProductInProcess
import org.jetbrains.intellij.build.dev.getIdeSystemProperties
import org.jetbrains.intellij.build.impl.productInfo.PRODUCT_INFO_FILE_NAME
import org.jetbrains.intellij.build.impl.productInfo.ProductInfoLaunchData
import org.jetbrains.intellij.build.impl.productInfo.checkInArchive
@@ -67,7 +64,6 @@ import java.util.concurrent.TimeUnit
import java.util.zip.Deflater
import kotlin.io.NoSuchFileException
import kotlin.io.path.*
import kotlin.time.Duration.Companion.seconds
internal const val PROPERTIES_FILE_NAME: String = "idea.properties"
@@ -106,7 +102,7 @@ class BuildTasksImpl(private val context: BuildContextImpl) : BuildTasks {
compilationTasks = compilationTasks,
context = context,
)
buildSearchableOptions(distState.platform, context)
buildSearchableOptions(context)
buildNonBundledPlugins(
pluginsToPublish = pluginsToPublish,
compressPluginArchive = context.options.compressZipFiles,
@@ -649,7 +645,7 @@ private suspend fun compileModulesForDistribution(context: BuildContext): Distri
hasPlatformCoverage(
productLayout = productLayout,
enabledPluginModules = enabledPluginModules,
context = context
context = context,
)
if (context.shouldBuildDistributions()) {
@@ -665,40 +661,14 @@ private suspend fun compileModulesForDistribution(context: BuildContext): Distri
}
val builtinModuleData = spanBuilder("build provided module list").useWithScope {
//val ideClasspath = createIdeClassPath(platform = platform, context = context)
var homePath: Path? = null
var newClassPath: Collection<Path>? = null
val systemProperties = HashMap<String, Any>()
val tempDir = context.paths.tempDir.resolve("builtinModules")
buildProductInProcess(
BuildRequest(
devRootPath = tempDir,
isUnpackedDist = true,
platformPrefix = context.productProperties.platformPrefix ?: "idea",
additionalModules = emptyList(),
homePath = context.paths.projectHome,
platformClassPathConsumer = { classPath, runDir ->
newClassPath = classPath
homePath = runDir
for ((name, value) in getIdeSystemProperties(runDir)) {
systemProperties.put(name, value)
}
}
)
)
Files.deleteIfExists(providedModuleFile)
val tempDir = context.paths.tempDir.resolve("builtinModules")
// start the product in headless mode using com.intellij.ide.plugins.BundledPluginsLister
runApplicationStarter(
context = context,
createDevIdeBuild(context = context).runProduct(
tempDir = tempDir,
ideClasspath = newClassPath!!.map { it.toString() },
arguments = listOf("listBundledPlugins", providedModuleFile.toString()),
timeout = 30.seconds,
homePath = homePath ?: context.paths.projectHome,
systemProperties = systemProperties,
listOf("listBundledPlugins", providedModuleFile.toString()),
)
context.productProperties.customizeBuiltinModules(context = context, builtinModulesFile = providedModuleFile)
try {
val builtinModuleData = readBuiltinModulesFile(file = providedModuleFile)
@@ -791,7 +761,7 @@ suspend fun buildDistributions(context: BuildContext): Unit = spanBuilder("build
"skip building product distributions because " +
"'intellij.build.target.os' property is set to '${BuildOptions.OS_NONE}'"
)
buildSearchableOptions(distributionState.platform, context)
buildSearchableOptions(context)
buildNonBundledPlugins(
pluginsToPublish = pluginsToPublish,
compressPluginArchive = context.options.compressZipFiles,
@@ -1418,7 +1388,7 @@ fun collectModulesToCompile(context: BuildContext, result: MutableSet<String>) {
// Captures information about all available inspections in a JSON format as part of an Inspectopedia project.
// This is later used by Qodana and other tools.
// Keymaps are extracted as an XML file and also used in authoring help.
internal suspend fun buildAdditionalAuthoringArtifacts(ideClassPath: Set<String>, context: BuildContext) {
internal suspend fun buildAdditionalAuthoringArtifacts(ide: DevIdeBuild, context: BuildContext) {
context.executeStep(spanBuilder("build authoring asserts"), BuildOptions.DOC_AUTHORING_ASSETS_STEP) {
val commands = listOf(
Pair("inspectopedia-generator", "inspections-${context.applicationInfo.productCode.lowercase()}"),
@@ -1429,12 +1399,7 @@ internal suspend fun buildAdditionalAuthoringArtifacts(ideClassPath: Set<String>
launch {
val temporaryStepDirectory = temporaryBuildDirectory.resolve(command.first)
val targetPath = temporaryStepDirectory.resolve(command.second)
runApplicationStarter(
context = context,
tempDir = temporaryStepDirectory,
ideClasspath = ideClassPath,
arguments = listOf(command.first, targetPath.toString())
)
ide.runProduct(tempDir = temporaryStepDirectory, arguments = listOf(command.first, targetPath.toString()))
val targetFile = context.paths.artifactDir.resolve("${command.second}.zip")
zipWithCompression(
@@ -0,0 +1,56 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
@file:Suppress("ReplacePutWithAssignment")
package org.jetbrains.intellij.build.impl
import org.jetbrains.intellij.build.BuildContext
import org.jetbrains.intellij.build.dev.BuildRequest
import org.jetbrains.intellij.build.dev.buildProductInProcess
import org.jetbrains.intellij.build.dev.getIdeSystemProperties
import org.jetbrains.intellij.build.io.DEFAULT_TIMEOUT
import java.nio.file.Path
import kotlin.time.Duration.Companion.seconds
internal suspend fun createDevIdeBuild(context: BuildContext): DevIdeBuild {
var newClassPath: Collection<Path>? = null
val runDir = buildProductInProcess(
BuildRequest(
devRootPath = context.paths.tempDir.resolve("dev-run"),
isUnpackedDist = true,
platformPrefix = context.productProperties.platformPrefix ?: "idea",
additionalModules = emptyList(),
homePath = context.paths.projectHome,
productionClassOutput = context.classesOutputDirectory.resolve("production"),
platformClassPathConsumer = { classPath, _ ->
newClassPath = classPath
}
)
)
return DevIdeBuild(context = context, homePath = runDir, classPath = newClassPath!!)
}
/**
* Only for use in build scripts, not for dev mode / integrations tests.
*/
internal class DevIdeBuild(
private val context: BuildContext,
private val homePath: Path,
private val classPath: Collection<Path>,
) {
suspend fun runProduct(
tempDir: Path,
arguments: List<String>,
systemProperties: Map<String, Any> = emptyMap(),
isLongRunning: Boolean = false,
) {
runApplicationStarter(
context = context,
tempDir = tempDir,
ideClasspath = classPath.map { it.toString() },
arguments = arguments,
timeout = if (isLongRunning) DEFAULT_TIMEOUT else 30.seconds,
homePath = homePath,
systemProperties = systemProperties + getIdeSystemProperties(homePath),
)
}
}
@@ -65,10 +65,10 @@ internal suspend fun buildDistribution(
context.productProperties.validateLayout(state.platform, context)
createBuildBrokenPluginListJob(context)
val flatIdeClassPath = createIdeClassPath(state.platform, context)
val ide = createDevIdeBuild(context)
if (context.productProperties.buildDocAuthoringAssets) {
launch {
buildAdditionalAuthoringArtifacts(ideClassPath = flatIdeClassPath, context = context)
buildAdditionalAuthoringArtifacts(ide = ide, context = context)
}
}
@@ -76,7 +76,7 @@ internal suspend fun buildDistribution(
val entries = coroutineScope {
// must be completed before plugin building
context.executeStep(spanBuilder("build searchable options index"), BuildOptions.SEARCHABLE_OPTIONS_INDEX_STEP) {
buildSearchableOptions(ideClassPath = flatIdeClassPath, context = context)
buildSearchableOptions(ide = ide, context = context)
}
val pluginLayouts = getPluginLayoutsByJpsModuleNames(
@@ -1359,12 +1359,11 @@ suspend fun createIdeClassPath(platform: PlatformLayout, context: BuildContext):
}
suspend fun buildSearchableOptions(
platform: PlatformLayout,
context: BuildContext,
systemProperties: Map<String, Any> = emptyMap(),
): Path? {
return buildSearchableOptions(
ideClassPath = createIdeClassPath(platform, context),
ide = createDevIdeBuild(context),
context = context,
systemProperties = systemProperties,
)
@@ -1373,8 +1372,8 @@ suspend fun buildSearchableOptions(
/**
* Build index which is used to search options in the Settings dialog.
*/
suspend fun buildSearchableOptions(
ideClassPath: Set<String>,
private suspend fun buildSearchableOptions(
ide: DevIdeBuild,
context: BuildContext,
systemProperties: Map<String, Any> = emptyMap(),
): Path? {
@@ -1406,13 +1405,11 @@ suspend fun buildSearchableOptions(
}
// Start the product in headless mode using com.intellij.ide.ui.search.TraverseUIStarter.
// It'll process all UI elements in the `Settings` dialog and build an index for them.
runApplicationStarter(
context = context,
ide.runProduct(
tempDir = context.paths.tempDir.resolve("searchableOptions"),
ideClasspath = ideClassPath,
arguments = listOf("traverseUI", targetDirectory.toString(), "true"),
vmOptions = listOf("-Xmx2g"),
systemProperties = systemProperties,
isLongRunning = true,
)
check(Files.isDirectory(targetDirectory)) {
"Failed to build searchable options index: $targetDirectory does not exist. See log above for error output from traverseUI run."