IJPL-242344 ij-light: Add a way to start IJ Light from installers

GitOrigin-RevId: d2dba6305bafefaaed23cc22d6ba4d66fa23a032
This commit is contained in:
Vyacheslav Karpukhin
2026-06-05 20:56:03 +00:00
committed by intellij-monorepo-bot
parent 1a3fe81a06
commit bd6aedce33
5 changed files with 71 additions and 10 deletions
@@ -24,6 +24,7 @@ import org.jetbrains.intellij.build.impl.OsSpecificDistributionBuilder.Companion
import org.jetbrains.intellij.build.impl.client.getAdditionalEmbeddedClientVmOptions
import org.jetbrains.intellij.build.impl.productInfo.PRODUCT_INFO_FILE_NAME
import org.jetbrains.intellij.build.impl.productInfo.generateEmbeddedFrontendLaunchData
import org.jetbrains.intellij.build.impl.productInfo.generateIjLightLaunchData
import org.jetbrains.intellij.build.impl.productInfo.generateProductInfoJson
import org.jetbrains.intellij.build.impl.productInfo.resolveProductInfoJsonSibling
import org.jetbrains.intellij.build.impl.productInfo.validateProductJson
@@ -402,10 +403,12 @@ class LinuxDistributionBuilder(
stdioRedirectArg = context.productProperties.stdioRedirectArg,
startupWmClass = getLinuxFrameClass(context),
customCommands = run {
val vmOptionsFilePath: (BuildContext) -> String = {
"bin/${it.add64IfNeeded(it.productProperties.baseFileName)}.vmoptions"
}
val base = listOfNotNull(
generateEmbeddedFrontendLaunchData(arch, OsFamily.LINUX, context) {
"bin/${it.add64IfNeeded(it.productProperties.baseFileName)}.vmoptions"
},
generateEmbeddedFrontendLaunchData(arch, OsFamily.LINUX, context, vmOptionsFilePath),
generateIjLightLaunchData(arch, OsFamily.LINUX, context, vmOptionsFilePath),
generateQodanaLaunchData(context, arch, OsFamily.LINUX),
generateStdioMcpRunnerLaunchData(context, OsFamily.LINUX)
)
@@ -32,6 +32,7 @@ import org.jetbrains.intellij.build.impl.OsSpecificDistributionBuilder.Companion
import org.jetbrains.intellij.build.impl.macOS.MachOUuid
import org.jetbrains.intellij.build.impl.productInfo.PRODUCT_INFO_FILE_NAME
import org.jetbrains.intellij.build.impl.productInfo.generateEmbeddedFrontendLaunchData
import org.jetbrains.intellij.build.impl.productInfo.generateIjLightLaunchData
import org.jetbrains.intellij.build.impl.productInfo.generateProductInfoJson
import org.jetbrains.intellij.build.impl.productInfo.resolveProductInfoJsonSibling
import org.jetbrains.intellij.build.impl.productInfo.validateProductJson
@@ -421,10 +422,12 @@ class MacDistributionBuilder(
mainClass = context.ideMainClassName,
stdioRedirectArg = context.productProperties.stdioRedirectArg,
customCommands = run {
val vmOptionsFilePath: (BuildContext) -> String = {
"${toRoot}bin/${it.productProperties.baseFileName}.vmoptions"
}
val base = listOfNotNull(
generateEmbeddedFrontendLaunchData(arch, OsFamily.MACOS, context) {
"${toRoot}bin/${it.productProperties.baseFileName}.vmoptions"
},
generateEmbeddedFrontendLaunchData(arch, OsFamily.MACOS, context, vmOptionsFilePath),
generateIjLightLaunchData(arch, OsFamily.MACOS, context, vmOptionsFilePath),
generateQodanaLaunchData(context, arch, OsFamily.MACOS),
generateStdioMcpRunnerLaunchData(context, OsFamily.MACOS)
)
@@ -30,6 +30,7 @@ import org.jetbrains.intellij.build.executeStep
import org.jetbrains.intellij.build.impl.OsSpecificDistributionBuilder.Companion.suffix
import org.jetbrains.intellij.build.impl.productInfo.PRODUCT_INFO_FILE_NAME
import org.jetbrains.intellij.build.impl.productInfo.generateEmbeddedFrontendLaunchData
import org.jetbrains.intellij.build.impl.productInfo.generateIjLightLaunchData
import org.jetbrains.intellij.build.impl.productInfo.generateProductInfoJson
import org.jetbrains.intellij.build.impl.productInfo.resolveProductInfoJsonSibling
import org.jetbrains.intellij.build.impl.productInfo.validateProductJson
@@ -547,10 +548,12 @@ internal class WindowsDistributionBuilder(
mainClass = context.ideMainClassName,
stdioRedirectArg = context.productProperties.stdioRedirectArg,
customCommands = run {
val vmOptionsFilePath: (BuildContext) -> String = { clientCtx ->
"bin/${clientCtx.add64IfNeeded(clientCtx.productProperties.baseFileName)}.exe.vmoptions"
}
val base = listOfNotNull(
generateEmbeddedFrontendLaunchData(arch, OsFamily.WINDOWS, context) { clientCtx ->
"bin/${clientCtx.add64IfNeeded(clientCtx.productProperties.baseFileName)}.exe.vmoptions"
},
generateEmbeddedFrontendLaunchData(arch, OsFamily.WINDOWS, context, vmOptionsFilePath),
generateIjLightLaunchData(arch, OsFamily.WINDOWS, context, vmOptionsFilePath),
generateQodanaLaunchData(context, arch, OsFamily.WINDOWS),
generateStdioMcpRunnerLaunchData(context, OsFamily.WINDOWS)
)
@@ -13,6 +13,7 @@ import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import org.jetbrains.intellij.build.BuildContext
import org.jetbrains.intellij.build.BuiltinModulesFileData
import org.jetbrains.intellij.build.JarPackagerDependencyHelper
import org.jetbrains.intellij.build.JvmArchitecture
import org.jetbrains.intellij.build.OsFamily
import org.jetbrains.intellij.build.impl.Git
@@ -141,6 +142,56 @@ internal suspend fun generateEmbeddedFrontendLaunchData(
)
}
private suspend fun BuildContext.ijLightInitialPluginIds(): List<String> = listOf(
"com.intellij",
findFrontendCustomizationPluginId(this),
"com.jetbrains.remoteDevelopment",
"intellij.platform.ijent.impl",
"org.jetbrains.plugins.textmate",
"org.jetbrains.plugins.terminal",
"com.intellij.modules.jcef",
)
internal suspend fun generateIjLightLaunchData(
arch: JvmArchitecture,
os: OsFamily,
ideContext: BuildContext,
vmOptionsFilePath: (BuildContext) -> String,
): CustomCommandLaunchData? {
val clientContext = ideContext.getEmbeddedFrontendProductContext()
?: ideContext.takeIf { it.productProperties.platformPrefix == "JetBrainsClient" }
?: return null
val explicitPluginIds = clientContext.ijLightInitialPluginIds().joinToString(",")
return CustomCommandLaunchData(
commands = listOf("ijLight"),
vmOptionsFilePath = vmOptionsFilePath(clientContext),
bootClassPathJarNames = clientContext.bootClassPathJarNames,
additionalJvmArguments = clientContext.getAdditionalJvmArguments(os, arch) +
getAdditionalEmbeddedClientVmOptions(os, ideContext) +
"-Didea.load.plugins.id=$explicitPluginIds" +
"-Dintellij.platform.use.proxies.for.open.services=true" +
"-Didea.vfs.max-file-length-to-cache=0",
mainClass = clientContext.ideMainClassName,
envVarBaseName = "JETBRAINS_CLIENT",
dataDirectoryName = clientContext.systemSelector,
)
}
private suspend fun findFrontendCustomizationPluginId(clientContext: BuildContext): String {
val rootModule = clientContext.productProperties.rootModuleForModularLoader
val candidates = clientContext.getBundledPluginModules().filter {
it != rootModule && (it.endsWith(".frontend.split.customization") || it.endsWith(".frontend.customization"))
}
if (candidates.size != 1) {
clientContext.messages.logErrorAndThrow("Expected exactly one frontend customization plugin module for ${clientContext.productProperties.rootModuleForModularLoader}, got $candidates")
}
val pluginModuleName = candidates.single()
val helper = JarPackagerDependencyHelper(clientContext.outputProvider)
return helper.getPluginIdByModule(clientContext.outputProvider.findRequiredModule(pluginModuleName))
}
/**
* See 'IJI-2228 Publish product-info.json next to installers'.
*
@@ -135,7 +135,8 @@ private fun PluginInitializationContext.selectFromExplicitSubset(
onPluginExcluded: (PluginMainDescriptor, PluginNonLoadReason) -> Unit,
): List<PluginMainDescriptor> {
val compatiblePlugins = selectMostRecentCompatible(discoveredPlugins, onPluginExcluded)
val pluginIdsSubset = essentialPlugins + explicitPluginSubsetToLoad!!
val explicitSubset = explicitPluginSubsetToLoad ?: emptySet()
val pluginIdsSubset = essentialPlugins + explicitSubset
val pluginSubset = compatiblePlugins.filter { it.pluginId in pluginIdsSubset }
val ambiguousPluginSet = AmbiguousPluginSet.build(compatiblePlugins)
val requiredModules = PluginDependencyAnalysis.getRequiredTransitiveModules(