cleanup [build scripts]: obsolete code; minor optimization; formatting

GitOrigin-RevId: 428337908e5ba55ff0c11341af21820b6c3f353d
This commit is contained in:
Roman Shevchenko
2025-11-09 11:47:53 +00:00
committed by intellij-monorepo-bot
parent c43ff906a2
commit 1a3d0197dd
7 changed files with 287 additions and 393 deletions
@@ -73,11 +73,11 @@ class LinuxDistributionBuilder(
withContext(Dispatchers.IO) {
val distBinDir = targetPath.resolve("bin")
val sourceBinDir = context.paths.communityHomeDir.resolve("bin/linux")
addNativeLauncher(distBinDir = distBinDir, targetPath = targetPath, arch = arch, context = context)
addNativeLauncher(distBinDir, targetPath, arch, context)
copyFileToDir(NativeBinaryDownloader.getRestarter(context, OsFamily.LINUX, arch), distBinDir)
copyFileToDir(sourceBinDir.resolve("${arch.dirName}/fsnotifier"), distBinDir)
generateBuildTxt(context = context, targetDirectory = targetPath)
copyDistFiles(context = context, newDir = targetPath, os = OsFamily.LINUX, arch = arch, libcImpl = targetLibcImpl)
generateBuildTxt(context, targetPath)
copyDistFiles(context, targetPath, OsFamily.LINUX, arch, targetLibcImpl)
//todo converting line separators to unix-style make sense only when building Linux distributions under Windows on a local machine;
// for real installers we need to checkout all text files with 'lf' separators anyway
@@ -87,15 +87,11 @@ class LinuxDistributionBuilder(
Files.copy(iconPngPath, distBinDir.resolve("${context.productProperties.baseFileName}.png"), StandardCopyOption.REPLACE_EXISTING)
}
writeVmOptions(distBinDir)
generateScripts(distBinDir = distBinDir, arch = arch, targetLibcImpl = targetLibcImpl, context = context)
generateScripts(distBinDir, arch, targetLibcImpl, context)
createFrontendContextForLaunchers(context)?.let { clientContext ->
writeLinuxVmOptions(distBinDir, clientContext)
generateLauncherScript(
distBinDir = distBinDir,
arch = arch,
nonCustomizableJvmArgs = ADDITIONAL_EMBEDDED_CLIENT_VM_OPTIONS,
context = clientContext,
targetLibcImpl = targetLibcImpl
distBinDir, arch, ADDITIONAL_EMBEDDED_CLIENT_VM_OPTIONS, clientContext, targetLibcImpl
)
}
generateReadme(targetPath)
@@ -183,9 +179,8 @@ class LinuxDistributionBuilder(
)
}
override fun generateExecutableFilesPatterns(includeRuntime: Boolean, arch: JvmArchitecture, libc: LibcImpl): Sequence<String> {
return customizer.generateExecutableFilesPatterns(context, includeRuntime, arch, libc)
}
override fun generateExecutableFilesPatterns(includeRuntime: Boolean, arch: JvmArchitecture, libc: LibcImpl): Sequence<String> =
customizer.generateExecutableFilesPatterns(context, includeRuntime, arch, libc)
private val rootDirectoryName: String
get() = customizer.getRootDirectoryName(context.applicationInfo, context.buildNumber)
@@ -237,9 +232,7 @@ class LinuxDistributionBuilder(
JvmArchitecture.aarch64 -> "arm64"
}
private fun getSnapArtifactName(snapName: String, arch: JvmArchitecture): String {
return "${snapName}_${snapVersion}_${getSnapArchName(arch)}.snap"
}
private fun getSnapArtifactName(snapName: String, arch: JvmArchitecture): String = "${snapName}_${snapVersion}_${getSnapArchName(arch)}.snap"
private suspend fun buildSnapPackage(runtimeDir: Path, unixDistPath: Path, arch: JvmArchitecture, targetLibcImpl: LinuxLibcImpl) {
if (!context.options.buildUnixSnaps) {
@@ -331,7 +324,7 @@ class LinuxDistributionBuilder(
"--volume=$runtimeDir:/build/jre:ro",
"--workdir=/build",
context.options.snapDockerImage,
"snapcraft",
@Suppress("SpellCheckingInspection") "snapcraft",
"snap",
"--build-for=$architecture",
"-o", "result/$snapArtifactName"
@@ -392,104 +385,101 @@ class LinuxDistributionBuilder(
writeProductInfoJson(file, json, context)
return file
}
}
private fun generateVersionMarker(unixDistPath: Path, context: BuildContext) {
val targetDir = unixDistPath.resolve("lib")
Files.createDirectories(targetDir)
Files.writeString(targetDir.resolve("build-marker-" + context.fullBuildNumber), context.fullBuildNumber)
}
private fun generateVersionMarker(unixDistPath: Path, context: BuildContext) {
val targetDir = unixDistPath.resolve("lib")
Files.createDirectories(targetDir)
Files.writeString(targetDir.resolve("build-marker-" + context.fullBuildNumber), context.fullBuildNumber)
}
private fun generateScripts(distBinDir: Path, arch: JvmArchitecture, targetLibcImpl: LinuxLibcImpl, context: BuildContext) {
Files.createDirectories(distBinDir)
private fun generateScripts(distBinDir: Path, arch: JvmArchitecture, targetLibcImpl: LinuxLibcImpl, context: BuildContext) {
Files.createDirectories(distBinDir)
val sourceScriptDir = context.paths.communityHomeDir.resolve("platform/build-scripts/resources/linux/scripts")
Files.newDirectoryStream(sourceScriptDir).use {
for (file in it) {
val fileName = file.fileName.toString()
if (fileName != EXECUTABLE_TEMPLATE_NAME) {
copyScript(file, distBinDir.resolve(fileName), additionalTemplateValues = emptyList(), context)
val sourceScriptDir = context.paths.communityHomeDir.resolve("platform/build-scripts/resources/linux/scripts")
Files.newDirectoryStream(sourceScriptDir).use {
for (file in it) {
val fileName = file.fileName.toString()
if (fileName != EXECUTABLE_TEMPLATE_NAME) {
copyScript(file, distBinDir.resolve(fileName), additionalTemplateValues = emptyList(), context)
}
}
}
copyInspectScript(context, distBinDir)
generateLauncherScript(distBinDir, arch, nonCustomizableJvmArgs = emptyList(), context, targetLibcImpl)
}
copyInspectScript(context, distBinDir)
generateLauncherScript(distBinDir, arch, nonCustomizableJvmArgs = emptyList(), context, targetLibcImpl)
}
private suspend fun addNativeLauncher(distBinDir: Path, targetPath: Path, arch: JvmArchitecture, context: BuildContext) {
val (execPath, licensePath) = NativeBinaryDownloader.getLauncher(context, OsFamily.LINUX, arch)
copyFile(execPath, distBinDir.resolve(context.productProperties.baseFileName))
copyFile(licensePath, targetPath.resolve("license/launcher-third-party-libraries.html"))
}
private fun generateLauncherScript(distBinDir: Path, arch: JvmArchitecture, nonCustomizableJvmArgs: List<String>, context: BuildContext, targetLibcImpl: LinuxLibcImpl) {
val vmOptionsPath = distBinDir.resolve("${context.productProperties.baseFileName}64.vmoptions")
val defaultXmxParameter = try {
Files.readAllLines(vmOptionsPath).firstOrNull { it.startsWith("-Xmx") }
?: throw IllegalStateException("-Xmx was not found in '$vmOptionsPath'")
}
catch (e: NoSuchFileException) {
throw IllegalStateException("File '$vmOptionsPath' should be already generated at this point", e)
private suspend fun addNativeLauncher(distBinDir: Path, targetPath: Path, arch: JvmArchitecture, context: BuildContext) {
val (execPath, licensePath) = NativeBinaryDownloader.getLauncher(context, OsFamily.LINUX, arch)
copyFile(execPath, distBinDir.resolve(context.productProperties.baseFileName))
copyFile(licensePath, targetPath.resolve("license/launcher-third-party-libraries.html"))
}
val classPathJars = context.bootClassPathJarNames
var classPath = $$"CLASS_PATH=\"$IDE_HOME/lib/$${classPathJars[0]}\""
for (i in 1 until classPathJars.size) {
classPath += $$"\nCLASS_PATH=\"$CLASS_PATH:$IDE_HOME/lib/$${classPathJars[i]}\""
private fun generateLauncherScript(distBinDir: Path, arch: JvmArchitecture, nonCustomizableJvmArgs: List<String>, context: BuildContext, targetLibcImpl: LinuxLibcImpl) {
val vmOptionsPath = distBinDir.resolve("${context.productProperties.baseFileName}64.vmoptions")
val defaultXmxParameter = try {
Files.readAllLines(vmOptionsPath).firstOrNull { it.startsWith("-Xmx") }
?: throw IllegalStateException("-Xmx was not found in '$vmOptionsPath'")
}
catch (e: NoSuchFileException) {
throw IllegalStateException("File '$vmOptionsPath' should be already generated at this point", e)
}
val classPathJars = context.bootClassPathJarNames
var classPath = $$"CLASS_PATH=\"$IDE_HOME/lib/$${classPathJars[0]}\""
for (i in 1 until classPathJars.size) {
classPath += $$"\nCLASS_PATH=\"$CLASS_PATH:$IDE_HOME/lib/$${classPathJars[i]}\""
}
val additionalJvmArguments = mutableListOf<String>()
// https://youtrack.jetbrains.com/issue/IDEA-304440
// "-Djdk.lang.Process.launchMechanism=vfork"
if (targetLibcImpl == LinuxLibcImpl.MUSL) {
additionalJvmArguments.add("-Djdk.lang.Process.launchMechanism=vfork")
}
additionalJvmArguments.addAll(context.getAdditionalJvmArguments(OsFamily.LINUX, arch, isScript = true) + nonCustomizableJvmArgs)
val additionalTemplateValues = listOf(
Pair("vm_options", context.productProperties.baseFileName),
Pair("system_selector", context.systemSelector),
Pair("ide_jvm_args", additionalJvmArguments.joinToString(separator = " ")),
Pair("ide_default_xmx", defaultXmxParameter.trim()),
Pair("class_path", classPath),
Pair("main_class_name", context.ideMainClassName),
)
val template = context.paths.communityHomeDir.resolve("platform/build-scripts/resources/linux/scripts/${EXECUTABLE_TEMPLATE_NAME}")
copyScript(template, distBinDir.resolve("${context.productProperties.baseFileName}.sh"), additionalTemplateValues, context)
}
val additionalJvmArguments = mutableListOf<String>()
// https://youtrack.jetbrains.com/issue/IDEA-304440
// "-Djdk.lang.Process.launchMechanism=vfork"
if (targetLibcImpl == LinuxLibcImpl.MUSL) {
additionalJvmArguments.add("-Djdk.lang.Process.launchMechanism=vfork")
private fun copyScript(sourceFile: Path, targetFile: Path, additionalTemplateValues: List<Pair<String, String>>, context: BuildContext) {
// Until CR (\r) will be removed from the repository checkout, we need to filter it out from Unix-style scripts
// https://youtrack.jetbrains.com/issue/IJI-526/Force-git-to-use-LF-line-endings-in-working-copy-of-via-gitattri
substituteTemplatePlaceholders(
inputFile = sourceFile,
outputFile = targetFile,
placeholder = "__",
values = listOf(
Pair("product_full", context.applicationInfo.fullProductName),
Pair("product_uc", context.productProperties.getEnvironmentVariableBaseName(context.applicationInfo)),
Pair("product_vendor", context.applicationInfo.shortCompanyName),
Pair("product_code", context.applicationInfo.productCode),
Pair("script_name", "${context.productProperties.baseFileName}.sh"),
) + additionalTemplateValues,
mustUseAllPlaceholders = false,
convertToUnixLineEndings = true,
)
}
additionalJvmArguments.addAll(context.getAdditionalJvmArguments(OsFamily.LINUX, arch, isScript = true) + nonCustomizableJvmArgs)
val additionalTemplateValues = listOf(
Pair("vm_options", context.productProperties.baseFileName),
Pair("system_selector", context.systemSelector),
Pair("ide_jvm_args", additionalJvmArguments.joinToString(separator = " ")),
Pair("ide_default_xmx", defaultXmxParameter.trim()),
Pair("class_path", classPath),
Pair("main_class_name", context.ideMainClassName),
)
private fun writeLinuxVmOptions(distBinDir: Path, context: BuildContext): Path {
val vmOptionsPath = distBinDir.resolve("${context.productProperties.baseFileName}64.vmoptions")
val vmOptions = VmOptionsGenerator.generate(context).asSequence() + sequenceOf("-Dsun.tools.attach.tmp.only=true", "-Dawt.lock.fair=true")
VmOptionsGenerator.writeVmOptions(vmOptionsPath, vmOptions, separator = "\n")
return vmOptionsPath
}
val template = context.paths.communityHomeDir.resolve("platform/build-scripts/resources/linux/scripts/${EXECUTABLE_TEMPLATE_NAME}")
copyScript(template, distBinDir.resolve("${context.productProperties.baseFileName}.sh"), additionalTemplateValues, context)
}
private fun copyScript(sourceFile: Path, targetFile: Path, additionalTemplateValues: List<Pair<String, String>>, context: BuildContext) {
// Until CR (\r) will be removed from the repository checkout, we need to filter it out from Unix-style scripts
// https://youtrack.jetbrains.com/issue/IJI-526/Force-git-to-use-LF-line-endings-in-working-copy-of-via-gitattri
substituteTemplatePlaceholders(
inputFile = sourceFile,
outputFile = targetFile,
placeholder = "__",
values = listOf(
Pair("product_full", context.applicationInfo.fullProductName),
Pair("product_uc", context.productProperties.getEnvironmentVariableBaseName(context.applicationInfo)),
Pair("product_vendor", context.applicationInfo.shortCompanyName),
Pair("product_code", context.applicationInfo.productCode),
Pair("script_name", "${context.productProperties.baseFileName}.sh"),
) + additionalTemplateValues,
mustUseAllPlaceholders = false,
convertToUnixLineEndings = true,
)
}
private fun writeLinuxVmOptions(distBinDir: Path, context: BuildContext): Path {
val vmOptionsPath = distBinDir.resolve("${context.productProperties.baseFileName}64.vmoptions")
val vmOptions = VmOptionsGenerator.generate(context).asSequence() + sequenceOf("-Dsun.tools.attach.tmp.only=true", "-Dawt.lock.fair=true")
writeVmOptions(file = vmOptionsPath, vmOptions = vmOptions, separator = "\n")
return vmOptionsPath
}
private fun suffix(arch: JvmArchitecture, targetLibcImpl: LinuxLibcImpl): String {
return suffix(arch) + if (targetLibcImpl == LinuxLibcImpl.MUSL) "-musl" else ""
private fun suffix(arch: JvmArchitecture, targetLibcImpl: LinuxLibcImpl): String =
suffix(arch) + if (targetLibcImpl == LinuxLibcImpl.MUSL) "-musl" else ""
}
@@ -123,7 +123,6 @@ class MacDistributionBuilder(
}
private suspend fun doCopyExtraFiles(macDistDir: Path, arch: JvmArchitecture, copyDistFiles: Boolean) {
@Suppress("SpellCheckingInspection")
val platformProperties = mutableListOf(
"\n#---------------------------------------------------------------------",
"# macOS-specific system properties",
@@ -185,36 +184,20 @@ class MacDistributionBuilder(
val builder = this@MacDistributionBuilder
val productJson = generateProductJson(context, arch, withRuntime = true)
val productJsonWithoutRuntime = generateProductJson(context = context, arch = arch, withRuntime = false)
val productJsonWithoutRuntime = generateProductJson(context, arch, withRuntime = false)
withContext(Dispatchers.IO) {
macZipProductInfoJson.writeText(productJson)
macZipWithoutRuntimeProductInfoJson.writeText(productJsonWithoutRuntime)
}
buildMacZip(
macDistributionBuilder = builder,
targetFile = macZip,
zipRoot = zipRoot,
arch = arch,
productJson = productJson,
directories = directories,
extraFiles = extraFiles,
includeRuntime = true,
compressionLevel = compressionLevel,
builder, macZip, zipRoot, arch, productJson, directories, extraFiles, includeRuntime = true, compressionLevel
)
if (customizer.buildArtifactWithoutRuntime) {
val directoriesSansRuntime = directories.filterNot { it == runtimeDir }
buildMacZip(
macDistributionBuilder = builder,
targetFile = macZipWithoutRuntime,
zipRoot = zipRoot,
arch = arch,
productJson = productJsonWithoutRuntime,
directories = directoriesSansRuntime,
extraFiles = extraFiles,
includeRuntime = false,
compressionLevel = compressionLevel,
builder, macZipWithoutRuntime, zipRoot, arch, productJsonWithoutRuntime, directoriesSansRuntime, extraFiles, includeRuntime = false, compressionLevel
)
}
@@ -228,13 +211,7 @@ class MacDistributionBuilder(
}
}
else {
buildForArch(
arch = arch,
macZip = macZip,
macZipProductInfoJson = macZipProductInfoJson,
macZipWithoutRuntime = macZipWithoutRuntime,
macZipWithoutRuntimeProductInfoJson = macZipWithoutRuntimeProductInfoJson,
)
buildForArch(arch, macZip, macZipProductInfoJson, macZipWithoutRuntime, macZipWithoutRuntimeProductInfoJson)
}
}
}
@@ -259,8 +236,7 @@ class MacDistributionBuilder(
}
}
override fun writeVmOptions(distBinDir: Path): Path =
writeMacOsVmOptions(distBinDir, context)
override fun writeVmOptions(distBinDir: Path): Path = writeMacOsVmOptions(distBinDir, context)
private suspend fun layoutMacApp(
ideaPropertyContent: CharSequence,
@@ -359,9 +335,9 @@ class MacDistributionBuilder(
macZipWithoutRuntime: Path, macZipWithoutRuntimeProductInfoJson: Path,
) {
spanBuilder("build macOS artifacts for specific arch").setAttribute("arch", arch.name).use(Dispatchers.IO) {
val notarize = System.getProperty("intellij.build.mac.notarize")?.toBoolean()
?: !context.isStepSkipped(BuildOptions.MAC_NOTARIZE_STEP)
&& !context.isStepSkipped(BuildOptions.MAC_SIGN_STEP)
val notarize =
(System.getProperty("intellij.build.mac.notarize")?.toBoolean() ?: !context.isStepSkipped(BuildOptions.MAC_NOTARIZE_STEP)) &&
!context.isStepSkipped(BuildOptions.MAC_SIGN_STEP)
buildForArch(arch, macZip, macZipProductInfoJson, macZipWithoutRuntime, macZipWithoutRuntimeProductInfoJson, notarize)
Files.deleteIfExists(macZip)
}
@@ -372,7 +348,7 @@ class MacDistributionBuilder(
macZip: Path, macZipProductInfoJson: Path,
macZipWithoutRuntime: Path, macZipWithoutRuntimeProductInfoJson: Path,
notarize: Boolean,
) {
) {
val archStr = arch.name
coroutineScope {
val taskId = "${BuildOptions.MAC_ARTIFACTS_STEP}_jre_${archStr}"
@@ -412,10 +388,10 @@ class MacDistributionBuilder(
override fun isRuntimeBundled(file: Path): Boolean = !file.name.contains(NO_RUNTIME_SUFFIX)
private suspend fun generateProductJson(context: BuildContext, arch: JvmArchitecture, withRuntime: Boolean): String {
val embeddedFrontendLaunchData = generateEmbeddedFrontendLaunchData(arch = arch, os = OsFamily.MACOS, ideContext = context) {
val embeddedFrontendLaunchData = generateEmbeddedFrontendLaunchData(arch, OsFamily.MACOS, context) {
"../bin/${it.productProperties.baseFileName}.vmoptions"
}
val qodanaCustomLaunchData = generateQodanaLaunchData(ideContext = context, arch = arch, os = OsFamily.MACOS)
val qodanaCustomLaunchData = generateQodanaLaunchData(context, arch, OsFamily.MACOS)
return generateProductInfoJson(
relativePathToBin = "../bin",
builtinModules = context.builtinModule,
@@ -432,7 +408,7 @@ class MacDistributionBuilder(
customCommands = listOfNotNull(embeddedFrontendLaunchData, qodanaCustomLaunchData)
)
),
context = context
context
)
}
@@ -520,9 +496,9 @@ class MacDistributionBuilder(
private fun writeMacOsVmOptions(distBinDir: Path, context: BuildContext): Path {
val executable = context.productProperties.baseFileName
val fileVmOptions = VmOptionsGenerator.generate(context).asSequence() + sequenceOf("-Dapple.awt.application.appearance=system")
val vmOptions = VmOptionsGenerator.generate(context).asSequence() + sequenceOf("-Dapple.awt.application.appearance=system")
val vmOptionsPath = distBinDir.resolve("${executable}.vmoptions")
writeVmOptions(file = vmOptionsPath, vmOptions = fileVmOptions, separator = "\n")
VmOptionsGenerator.writeVmOptions(vmOptionsPath, vmOptions, separator = "\n")
return vmOptionsPath
}
@@ -591,9 +567,8 @@ class MacDistributionBuilder(
}
}
private fun getMacZipRoot(customizer: MacDistributionCustomizer, context: BuildContext): String {
return "${customizer.getRootDirectoryName(context.applicationInfo, context.buildNumber)}/Contents"
}
private fun getMacZipRoot(customizer: MacDistributionCustomizer, context: BuildContext): String =
"${customizer.getRootDirectoryName(context.applicationInfo, context.buildNumber)}/Contents"
private val publishSitArchive: Boolean
get() = !context.isStepSkipped(BuildOptions.MAC_SIT_PUBLICATION_STEP)
@@ -615,7 +590,7 @@ class MacDistributionBuilder(
notarize(sitFile, context)
}
buildDmg(sitFile = sitFile, productInfoJson = productInfoJson, dmgName = "${baseName}.dmg", staple = notarize)
buildDmg(sitFile, productInfoJson, "${baseName}.dmg", notarize)
if (publishSitArchive) {
context.notifyArtifactBuilt(sitFile)
@@ -623,7 +598,7 @@ class MacDistributionBuilder(
}
val zipRoot = getMacZipRoot(customizer, context)
checkExecutablePermissions(distribution = sitFile, root = zipRoot, includeRuntime = isRuntimeBundled, arch = arch, libc = targetLibcImpl)
checkExecutablePermissions(sitFile, zipRoot, isRuntimeBundled, arch, targetLibcImpl)
if (isRuntimeBundled) {
generateIntegrityManifest(sitFile, zipRoot, arch, context)
@@ -637,7 +612,7 @@ class MacDistributionBuilder(
NioFiles.deleteRecursively(tempDir)
NioFiles.createDirectories(tempDir)
NioFiles.createDirectories(context.paths.artifactDir)
val entrypoint = prepareDmgBuildScripts(tempDir = tempDir, staple = staple, customizer = customizer, context = context)
val entrypoint = prepareDmgBuildScripts(tempDir, staple, customizer, context)
if (!SystemInfoRt.isMac) {
it.addEvent(".dmg can be built only on macOS")
if (publishSitArchive) {
@@ -661,76 +636,76 @@ class MacDistributionBuilder(
NioFiles.deleteRecursively(tempDir)
}
}
}
private fun prepareDmgBuildScripts(tempDir: Path, staple: Boolean, customizer: MacDistributionCustomizer, context: BuildContext): Path {
NioFiles.deleteRecursively(tempDir)
Files.createDirectories(tempDir)
val dmgImageCopy = tempDir.resolve("${context.fullBuildNumber}.png")
Files.copy(Path.of((if (context.applicationInfo.isEAP) customizer.dmgImagePathForEAP else null) ?: customizer.dmgImagePath), dmgImageCopy)
val scriptsDir = context.paths.communityHomeDir.resolve("platform/build-scripts/tools/mac/scripts")
Files.copy(scriptsDir.resolve("makedmg.sh"), tempDir.resolve("makedmg.sh"), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES)
NioFiles.setExecutable(tempDir.resolve("makedmg.sh"))
Files.copy(scriptsDir.resolve("makedmg.py"), tempDir.resolve("makedmg.py"), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES)
Files.copy(scriptsDir.resolve("staple.sh"), tempDir.resolve("staple.sh"), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES)
val entrypoint = tempDir.resolve("build.sh")
Files.writeString(
entrypoint,
Files.readString(scriptsDir.resolve("build-template.sh"))
.resolveTemplateVar("staple", "$staple")
.resolveTemplateVar("appName", context.fullBuildNumber)
.resolveTemplateVar("contentSigned", "${context.isMacCodeSignEnabled}")
.resolveTemplateVar("buildDateInSeconds", "${context.options.buildDateInSeconds}")
)
NioFiles.setExecutable(entrypoint)
return entrypoint
}
private fun prepareDmgBuildScripts(tempDir: Path, staple: Boolean, customizer: MacDistributionCustomizer, context: BuildContext): Path {
NioFiles.deleteRecursively(tempDir)
Files.createDirectories(tempDir)
val dmgImageCopy = tempDir.resolve("${context.fullBuildNumber}.png")
Files.copy(Path.of((if (context.applicationInfo.isEAP) customizer.dmgImagePathForEAP else null) ?: customizer.dmgImagePath), dmgImageCopy)
val scriptsDir = context.paths.communityHomeDir.resolve("platform/build-scripts/tools/mac/scripts")
Files.copy(scriptsDir.resolve("makedmg.sh"), tempDir.resolve("makedmg.sh"), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES)
NioFiles.setExecutable(tempDir.resolve("makedmg.sh"))
Files.copy(scriptsDir.resolve("makedmg.py"), tempDir.resolve("makedmg.py"), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES)
Files.copy(scriptsDir.resolve("staple.sh"), tempDir.resolve("staple.sh"), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES)
val entrypoint = tempDir.resolve("build.sh")
Files.writeString(
entrypoint,
Files.readString(scriptsDir.resolve("build-template.sh"))
.resolveTemplateVar("staple", "$staple")
.resolveTemplateVar("appName", context.fullBuildNumber)
.resolveTemplateVar("contentSigned", "${context.isMacCodeSignEnabled}")
.resolveTemplateVar("buildDateInSeconds", "${context.options.buildDateInSeconds}")
)
NioFiles.setExecutable(entrypoint)
return entrypoint
}
private fun String.resolveTemplateVar(variable: String, value: String): String {
val reference = "%$variable%"
check(contains(reference)) { "No $reference is found in:\n'$this'" }
return replace(reference, value)
}
private fun String.resolveTemplateVar(variable: String, value: String): String {
val reference = "%$variable%"
check(contains(reference)) { "No $reference is found in:\n'$this'" }
return replace(reference, value)
}
private fun publishDmgBuildScripts(entrypoint: Path, tempDir: Path, context: BuildContext) {
val artifactDir = context.paths.artifactDir.resolve("macos-dmg-build")
artifactDir.createDirectories()
synchronized("$artifactDir".intern()) {
tempDir.listDirectoryEntries().forEach {
Files.copy(it, artifactDir.resolve(it.name), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES)
}
val message = """
private fun publishDmgBuildScripts(entrypoint: Path, tempDir: Path, context: BuildContext) {
val artifactDir = context.paths.artifactDir.resolve("macos-dmg-build")
artifactDir.createDirectories()
synchronized("$artifactDir".intern()) {
tempDir.listDirectoryEntries().forEach {
Files.copy(it, artifactDir.resolve(it.name), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES)
}
val message = """
To build .dmg(s):
1. transfer .sit(s) to macOS host;
2. transfer ${artifactDir.name}/ content to the same folder;
3. execute ${entrypoint.name} from Terminal.
.dmg(s) will be built in the same folder.
""".trimIndent()
artifactDir.resolve("README.txt").writeText(message)
context.messages.info(message)
context.notifyArtifactBuilt(artifactDir)
}
}
private suspend fun generateIntegrityManifest(sitFile: Path, sitRoot: String, arch: JvmArchitecture, context: BuildContext) {
if (context.options.buildStepsToSkip.contains(BuildOptions.REPAIR_UTILITY_BUNDLE_STEP)) {
return
}
val tempSit = Files.createTempDirectory(context.paths.tempDir, "sit-")
try {
spanBuilder("extracting ${sitFile.name}").use(Dispatchers.IO) {
Decompressor.Zip(sitFile)
.withZipExtensions()
.extract(tempSit)
artifactDir.resolve("README.txt").writeText(message)
context.messages.info(message)
context.notifyArtifactBuilt(artifactDir)
}
RepairUtilityBuilder.generateManifest(context, tempSit.resolve(sitRoot), OsFamily.MACOS, arch)
}
finally {
withContext(Dispatchers.IO + NonCancellable) {
@OptIn(ExperimentalPathApi::class)
tempSit.deleteRecursively()
private suspend fun generateIntegrityManifest(sitFile: Path, sitRoot: String, arch: JvmArchitecture, context: BuildContext) {
if (context.options.buildStepsToSkip.contains(BuildOptions.REPAIR_UTILITY_BUNDLE_STEP)) {
return
}
val tempSit = Files.createTempDirectory(context.paths.tempDir, "sit-")
try {
spanBuilder("extracting ${sitFile.name}").use(Dispatchers.IO) {
Decompressor.Zip(sitFile)
.withZipExtensions()
.extract(tempSit)
}
RepairUtilityBuilder.generateManifest(context, tempSit.resolve(sitRoot), OsFamily.MACOS, arch)
}
finally {
withContext(Dispatchers.IO + NonCancellable) {
@OptIn(ExperimentalPathApi::class)
tempSit.deleteRecursively()
}
}
}
}
@@ -635,7 +635,6 @@ internal class TestingTasksImpl(context: CompilationContext, private val options
index = 0,
elements = VmOptionsGenerator.generate(
isEAP = true,
bundledRuntime = context.bundledRuntime,
customVmMemoryOptions = if (customMemoryOptions == null) mapOf("-Xms" to "750m", "-Xmx" to "1024m") else emptyMap(),
additionalVmOptions = customMemoryOptions ?: emptyList(),
platformPrefix = options.platformPrefix,
@@ -1,7 +1,6 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.intellij.build.impl
import com.intellij.ReviseWhenPortedToJDK
import com.intellij.platform.ijent.community.buildConstants.MULTI_ROUTING_FILE_SYSTEM_VMOPTIONS
import com.intellij.platform.ijent.community.buildConstants.isMultiRoutingFileSystemEnabledForProduct
import org.jetbrains.intellij.build.BuildContext
@@ -10,51 +9,46 @@ import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.name
private const val DEFAULT_MIN_HEAP = "128m"
private const val DEFAULT_MAX_HEAP = "2048m"
private val COMMON_VM_OPTIONS: List<String> = listOf(
"-XX:JbrShrinkingGcMaxHeapFreeRatio=40", // IJPL-181469. Used in a couple with AppIdleMemoryCleaner.runGc()
"-XX:ReservedCodeCacheSize=512m",
"-XX:+HeapDumpOnOutOfMemoryError",
"-XX:-OmitStackTraceInFastThrow",
"-XX:CICompilerCount=2",
"-XX:+IgnoreUnrecognizedVMOptions", // allowing the JVM to start even with outdated options stuck in user configs
"-ea",
"-Dsun.io.useCanonCaches=false",
"-Dsun.java2d.metal=true",
"-Djbr.catch.SIGABRT=true",
"-Djdk.http.auth.tunneling.disabledSchemes=\"\"",
"-Djdk.attach.allowAttachSelf=true",
"-Djdk.module.illegalAccess.silent=true",
"-Djdk.nio.maxCachedBufferSize=2097152",
"-Djava.util.zip.use.nio.for.zip.file.access=true", // IJPL-149160
"-Dkotlinx.coroutines.debug=off",
)
/** duplicates RepositoryHelper.CUSTOM_BUILT_IN_PLUGIN_REPOSITORY_PROPERTY */
private const val CUSTOM_BUILT_IN_PLUGIN_REPOSITORY_PROPERTY = "intellij.plugins.custom.built.in.repository.url"
object VmOptionsGenerator {
private const val DEFAULT_MIN_HEAP = "128m"
private const val DEFAULT_MAX_HEAP = "2048m"
private val COMMON_VM_OPTIONS: List<String> = listOf(
"-XX:JbrShrinkingGcMaxHeapFreeRatio=40", // IJPL-181469. Used in a couple with AppIdleMemoryCleaner.runGc()
"-XX:ReservedCodeCacheSize=512m",
"-XX:+HeapDumpOnOutOfMemoryError",
"-XX:-OmitStackTraceInFastThrow",
"-XX:CICompilerCount=2",
"-XX:+IgnoreUnrecognizedVMOptions", // allowing the JVM to start even with outdated options stuck in user configs
"-XX:+UnlockDiagnosticVMOptions",
"-XX:TieredOldPercentage=100000",
"-ea",
"-Dsun.io.useCanonCaches=false",
"-Dsun.java2d.metal=true",
"-Djbr.catch.SIGABRT=true",
"-Djdk.http.auth.tunneling.disabledSchemes=\"\"",
"-Djdk.attach.allowAttachSelf=true",
"-Djdk.module.illegalAccess.silent=true",
"-Djdk.nio.maxCachedBufferSize=2097152",
"-Djava.util.zip.use.nio.for.zip.file.access=true", // IJPL-149160
"-Dkotlinx.coroutines.debug=off",
)
/** duplicates RepositoryHelper.CUSTOM_BUILT_IN_PLUGIN_REPOSITORY_PROPERTY */
private const val CUSTOM_BUILT_IN_PLUGIN_REPOSITORY_PROPERTY = "intellij.plugins.custom.built.in.repository.url"
fun generate(context: BuildContext): List<String> = generate(
context.applicationInfo.isEAP,
context.bundledRuntime,
context.productProperties.customJvmMemoryOptions,
context.productProperties.additionalVmOptions.let {
val customPluginRepositoryUrl = computeCustomPluginRepositoryUrl(context)
if (customPluginRepositoryUrl == null) {
it
}
else {
it + "-D${CUSTOM_BUILT_IN_PLUGIN_REPOSITORY_PROPERTY}=${customPluginRepositoryUrl}"
}
val url = computeCustomPluginRepositoryUrl(context)
if (url == null) it else it + "-D${CUSTOM_BUILT_IN_PLUGIN_REPOSITORY_PROPERTY}=${url}"
},
context.productProperties.platformPrefix,
)
internal fun generate(
isEAP: Boolean,
bundledRuntime: BundledRuntime,
customVmMemoryOptions: Map<String, String>,
additionalVmOptions: List<String>,
platformPrefix: String?,
@@ -63,12 +57,12 @@ object VmOptionsGenerator {
val memory = LinkedHashMap<String, String>(customVmMemoryOptions)
memory.putIfAbsent("-Xms", DEFAULT_MIN_HEAP)
memory.putIfAbsent("-Xmx", DEFAULT_MAX_HEAP) // must be the same as [com.intellij.diagnostic.MemorySizeConfigurator.DEFAULT_XMX]
memory.putIfAbsent("-Xmx", DEFAULT_MAX_HEAP)
for ((k, v) in memory) {
result.add(k + v)
result += k + v
}
result.addAll(COMMON_VM_OPTIONS)
result += COMMON_VM_OPTIONS
if (isMultiRoutingFileSystemEnabledForProduct(platformPrefix)) {
result.addAll(MULTI_ROUTING_FILE_SYSTEM_VMOPTIONS)
@@ -76,48 +70,31 @@ object VmOptionsGenerator {
result += additionalVmOptions
var index = result.indexOf("-ea")
if (index < 0) {
index = result.indexOfFirst { it.startsWith("-D") }
}
if (index < 0) {
index = result.size
}
result.addAll(
index,
@ReviseWhenPortedToJDK("21", description = "Merge into `COMMON_VM_OPTIONS`")
if (bundledRuntime.build.startsWith("17.")) {
listOf(
"-XX:CompileCommand=exclude,com/intellij/openapi/vfs/impl/FilePartNodeRoot,trieDescend", // temporary workaround for crashes in С2 (JBR-4509)
"-XX:SoftRefLRUPolicyMSPerMB=50",
)
}
else listOf("-XX:+UnlockDiagnosticVMOptions", "-XX:TieredOldPercentage=100000")
)
if (isEAP) {
var index = result.indexOf("-ea")
if (index < 0) index = result.indexOfFirst { it.startsWith("-D") }
if (index < 0) index = result.size
result.add(index, "-XX:MaxJavaStackTraceDepth=10000") // must be consistent with `ConfigImportHelper#updateVMOptions`
}
return result
}
}
private fun computeCustomPluginRepositoryUrl(context: BuildContext): String? {
val artifactsServer = context.proprietaryBuildTools.artifactsServer
if (artifactsServer != null && context.productProperties.productLayout.prepareCustomPluginRepositoryForPublishedPlugins) {
val builtinPluginsRepoUrl = artifactsServer.urlToArtifact(context, "${context.nonBundledPlugins.name}/plugins.xml")
if (builtinPluginsRepoUrl != null) {
if (builtinPluginsRepoUrl.startsWith("http:")) {
context.messages.logErrorAndThrow("Insecure artifact server: ${builtinPluginsRepoUrl}")
private fun computeCustomPluginRepositoryUrl(context: BuildContext): String? {
val artifactsServer = context.proprietaryBuildTools.artifactsServer
if (artifactsServer != null && context.productProperties.productLayout.prepareCustomPluginRepositoryForPublishedPlugins) {
val builtinPluginsRepoUrl = artifactsServer.urlToArtifact(context, "${context.nonBundledPlugins.name}/plugins.xml")
if (builtinPluginsRepoUrl != null) {
if (builtinPluginsRepoUrl.startsWith("http:")) {
context.messages.logErrorAndThrow("Insecure artifact server: ${builtinPluginsRepoUrl}")
}
return builtinPluginsRepoUrl
}
return builtinPluginsRepoUrl
}
return null
}
return null
}
internal fun writeVmOptions(file: Path, vmOptions: Sequence<String>, separator: String) {
Files.writeString(file, vmOptions.joinToString(separator, postfix = separator), StandardCharsets.US_ASCII)
internal fun writeVmOptions(file: Path, vmOptions: Sequence<String>, separator: String) {
Files.writeString(file, vmOptions.joinToString(separator, postfix = separator), StandardCharsets.US_ASCII)
}
}
@@ -89,7 +89,7 @@ internal class WindowsDistributionBuilder(
copyFileToDir(NativeBinaryDownloader.getRestarter(context, OsFamily.WINDOWS, arch), distBinDir)
generateBuildTxt(context, targetPath)
copyDistFiles(context = context, newDir = targetPath, os = OsFamily.WINDOWS, arch = arch, libcImpl = WindowsLibcImpl.DEFAULT)
copyDistFiles(context, targetPath, OsFamily.WINDOWS, arch, WindowsLibcImpl.DEFAULT)
Files.writeString(distBinDir.resolve(PROPERTIES_FILE_NAME), StringUtilRt.convertLineSeparators(ideaProperties!!, "\r\n"))
@@ -101,11 +101,11 @@ internal class WindowsDistributionBuilder(
writeVmOptions(distBinDir)
buildWinLauncher(winDistPath = targetPath, arch = arch, context = context, copyLicense = true)
buildWinLauncher(targetPath, arch, context, copyLicense = true)
createFrontendContextForLaunchers(context)?.let { clientContext ->
writeWindowsVmOptions(distBinDir, clientContext)
buildWinLauncher(winDistPath = targetPath, arch = arch, context = clientContext, copyLicense = false)
buildWinLauncher(targetPath, arch, clientContext, copyLicense = false)
}
customizer.copyAdditionalFiles(context, targetPath, arch)
@@ -133,7 +133,6 @@ internal class WindowsDistributionBuilder(
copyFilesForOsDistribution(osAndArchSpecificDistPath, arch)
val runtimeDir = context.bundledRuntime.extract(OsFamily.WINDOWS, arch, WindowsLibcImpl.DEFAULT)
@Suppress("SpellCheckingInspection")
val vcRtDll = runtimeDir.resolve("jbr/bin/msvcp140.dll")
check(Files.exists(vcRtDll)) {
"VS C++ Runtime DLL (${vcRtDll.fileName}) not found in ${vcRtDll.parent}.\n" +
@@ -151,14 +150,7 @@ internal class WindowsDistributionBuilder(
if (customizer.buildZipArchiveWithBundledJre && !context.isStepSkipped(BuildOptions.WINDOWS_ZIP_STEP)) {
val zipNameSuffix = suffix(arch) + customizer.zipArchiveWithBundledJreSuffix
launch(Dispatchers.IO + CoroutineName("build Windows ${zipNameSuffix}.zip distribution")) {
zipWithJbrPath = createBuildWinZipTask(
runtimeDir = runtimeDir,
zipNameSuffix = zipNameSuffix,
winDistPath = osAndArchSpecificDistPath,
arch = arch,
customizer = customizer,
context = context,
)
zipWithJbrPath = createBuildWinZipTask(runtimeDir, zipNameSuffix, osAndArchSpecificDistPath, arch, customizer, context)
}
}
@@ -176,14 +168,7 @@ internal class WindowsDistributionBuilder(
validateProductJson(jsonText = productJsonFile.readText(), installationDirectories, installationArchives = emptyList(), context)
launch(Dispatchers.IO + CoroutineName("build Windows ${arch.dirName} installer")) {
exePath = buildNsisInstaller(
winDistPath = osAndArchSpecificDistPath,
productInfoJsonFile = productJsonFile,
additionalDirectoryToInclude = productJsonDir,
suffix = suffix(arch),
customizer = customizer,
runtimeDir = runtimeDir,
context = context,
arch = arch,
osAndArchSpecificDistPath, productJsonFile, productJsonDir, suffix(arch), customizer, runtimeDir, context, arch
)
}
}
@@ -222,7 +207,7 @@ internal class WindowsDistributionBuilder(
val winScripts = context.paths.communityHomeDir.resolve("platform/build-scripts/resources/win/scripts")
val actualScriptNames = Files.newDirectoryStream(winScripts).use { dirStream -> dirStream.map { it.fileName.toString() }.sorted() }
val expectedScriptNames = listOf("executable-template.bat", "format.bat", "inspect.bat", @Suppress("SpellCheckingInspection") "ltedit.bat")
val expectedScriptNames = listOf("executable-template.bat", "format.bat", "inspect.bat", "ltedit.bat")
check(actualScriptNames == expectedScriptNames) {
"Expected script names '${expectedScriptNames.joinToString(separator = " ")}', " +
"but got '${actualScriptNames.joinToString(separator = " ")}' " +
@@ -247,7 +232,7 @@ internal class WindowsDistributionBuilder(
)
val inspectScript = context.productProperties.inspectCommandName
for (fileName in listOf("format.bat", "inspect.bat", @Suppress("SpellCheckingInspection") "ltedit.bat")) {
for (fileName in listOf("format.bat", "inspect.bat", "ltedit.bat")) {
substituteTemplatePlaceholders(
inputFile = winScripts.resolve(fileName),
outputFile = distBinDir.resolve(fileName),
@@ -479,40 +464,40 @@ internal class WindowsDistributionBuilder(
}
}
}
}
private fun writeWindowsVmOptions(distBinDir: Path, context: BuildContext): Path {
val vmOptionsFile = distBinDir.resolve("${context.productProperties.baseFileName}64.exe.vmoptions")
val vmOptions = VmOptionsGenerator.generate(context).asSequence()
writeVmOptions(file = vmOptionsFile, vmOptions = vmOptions, separator = "\r\n")
return vmOptionsFile
}
private suspend fun writeProductJsonFile(targetDir: Path, arch: JvmArchitecture, context: BuildContext, withRuntime: Boolean = true): Path {
val embeddedFrontendLaunchData = generateEmbeddedFrontendLaunchData(arch, OsFamily.WINDOWS, context) {
"bin/${it.productProperties.baseFileName}64.exe.vmoptions"
private fun writeWindowsVmOptions(distBinDir: Path, context: BuildContext): Path {
val vmOptionsFile = distBinDir.resolve("${context.productProperties.baseFileName}64.exe.vmoptions")
val vmOptions = VmOptionsGenerator.generate(context).asSequence()
VmOptionsGenerator.writeVmOptions(vmOptionsFile, vmOptions, separator = "\r\n")
return vmOptionsFile
}
val qodanaCustomLaunchData = generateQodanaLaunchData(context, arch, OsFamily.WINDOWS)
val json = generateProductInfoJson(
relativePathToBin = "bin",
builtinModules = context.builtinModule,
launch = listOf(
ProductInfoLaunchData.create(
os = OsFamily.WINDOWS.osName,
arch = arch.dirName,
launcherPath = "bin/${context.productProperties.baseFileName}64.exe",
javaExecutablePath = if (withRuntime) "jbr/bin/java.exe" else null,
vmOptionsFilePath = "bin/${context.productProperties.baseFileName}64.exe.vmoptions",
bootClassPathJarNames = context.bootClassPathJarNames,
additionalJvmArguments = context.getAdditionalJvmArguments(OsFamily.WINDOWS, arch),
mainClass = context.ideMainClassName,
customCommands = listOfNotNull(embeddedFrontendLaunchData, qodanaCustomLaunchData),
)
),
context)
val file = targetDir.resolve(PRODUCT_INFO_FILE_NAME)
writeProductInfoJson(file, json, context)
return file
}
private fun toDosLineEndings(x: String): String = x.replace("\r", "").replace("\n", "\r\n")
private suspend fun writeProductJsonFile(targetDir: Path, arch: JvmArchitecture, context: BuildContext, withRuntime: Boolean = true): Path {
val embeddedFrontendLaunchData = generateEmbeddedFrontendLaunchData(arch, OsFamily.WINDOWS, context) {
"bin/${it.productProperties.baseFileName}64.exe.vmoptions"
}
val qodanaCustomLaunchData = generateQodanaLaunchData(context, arch, OsFamily.WINDOWS)
val json = generateProductInfoJson(
relativePathToBin = "bin",
builtinModules = context.builtinModule,
launch = listOf(
ProductInfoLaunchData.create(
os = OsFamily.WINDOWS.osName,
arch = arch.dirName,
launcherPath = "bin/${context.productProperties.baseFileName}64.exe",
javaExecutablePath = if (withRuntime) "jbr/bin/java.exe" else null,
vmOptionsFilePath = "bin/${context.productProperties.baseFileName}64.exe.vmoptions",
bootClassPathJarNames = context.bootClassPathJarNames,
additionalJvmArguments = context.getAdditionalJvmArguments(OsFamily.WINDOWS, arch),
mainClass = context.ideMainClassName,
customCommands = listOfNotNull(embeddedFrontendLaunchData, qodanaCustomLaunchData),
)
),
context)
val file = targetDir.resolve(PRODUCT_INFO_FILE_NAME)
writeProductInfoJson(file, json, context)
return file
}
private fun toDosLineEndings(x: String): String = x.replace("\r", "").replace("\n", "\r\n")
}
@@ -120,18 +120,16 @@ internal suspend fun generateEmbeddedFrontendLaunchData(
os: OsFamily,
ideContext: BuildContext,
vmOptionsFilePath: (BuildContext) -> String
): CustomCommandLaunchData? {
return createFrontendContextForLaunchers(ideContext)?.let { clientContext ->
CustomCommandLaunchData(
commands = listOf("thinClient", "thinClient-headless", "installFrontendPlugins"),
vmOptionsFilePath = vmOptionsFilePath(clientContext),
bootClassPathJarNames = clientContext.bootClassPathJarNames,
additionalJvmArguments = clientContext.getAdditionalJvmArguments(os, arch) + ADDITIONAL_EMBEDDED_CLIENT_VM_OPTIONS,
mainClass = clientContext.ideMainClassName,
envVarBaseName = "JETBRAINS_CLIENT",
dataDirectoryName = clientContext.systemSelector,
)
}
): CustomCommandLaunchData? = createFrontendContextForLaunchers(ideContext)?.let { clientContext ->
CustomCommandLaunchData(
commands = listOf("thinClient", "thinClient-headless", "installFrontendPlugins"),
vmOptionsFilePath = vmOptionsFilePath(clientContext),
bootClassPathJarNames = clientContext.bootClassPathJarNames,
additionalJvmArguments = clientContext.getAdditionalJvmArguments(os, arch) + ADDITIONAL_EMBEDDED_CLIENT_VM_OPTIONS,
mainClass = clientContext.ideMainClassName,
envVarBaseName = "JETBRAINS_CLIENT",
dataDirectoryName = clientContext.systemSelector,
)
}
/**
@@ -139,6 +137,4 @@ internal suspend fun generateEmbeddedFrontendLaunchData(
*
* E.g., if [this] is `installer.tag.gz`, returned Path will be `installer.tag.gz.product-info.json`.
*/
internal fun Path.resolveProductInfoJsonSibling(): Path {
return resolveSibling("${this.fileName}.$PRODUCT_INFO_FILE_NAME")
}
internal fun Path.resolveProductInfoJsonSibling(): Path = resolveSibling("${this.fileName}.$PRODUCT_INFO_FILE_NAME")
@@ -6,7 +6,7 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.Serializer
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import org.jetbrains.annotations.ApiStatus.Internal
import org.jetbrains.annotations.ApiStatus
import java.time.LocalDate
import java.time.format.DateTimeFormatter
@@ -43,7 +43,7 @@ class ProductInfoData private constructor(
val flavors: List<ProductFlavorData> = emptyList(),
// not used by the launcher; must be at the end
@Internal
@ApiStatus.Internal
val layout: List<ProductInfoLayoutItem> = emptyList(),
) {
companion object {
@@ -52,7 +52,7 @@ class ProductInfoData private constructor(
* Some properties that are nullable in the primary constructor are deliberately marked as not-null in this function to state that they
* are required in the current version, and internal clients may rely on their presence.
*/
@Internal
@ApiStatus.Internal
@JvmStatic
fun create(
name: String,
@@ -72,32 +72,15 @@ class ProductInfoData private constructor(
fileExtensions: List<String>,
flavors: List<ProductFlavorData>,
layout: List<ProductInfoLayoutItem>,
): ProductInfoData {
return ProductInfoData(
name = name,
version = version,
versionSuffix = versionSuffix,
buildNumber = buildNumber,
productCode = productCode,
envVarBaseName = envVarBaseName,
dataDirectoryName = dataDirectoryName,
svgIconPath = svgIconPath,
productVendor = productVendor,
majorVersionReleaseDate = majorVersionReleaseDate,
launch = launch,
customProperties = customProperties,
bundledPlugins = bundledPlugins,
modules = modules,
fileExtensions = fileExtensions,
flavors = flavors,
layout = layout
)
}
): ProductInfoData = ProductInfoData(
name, version, versionSuffix, buildNumber, productCode, envVarBaseName, dataDirectoryName, svgIconPath, productVendor,
majorVersionReleaseDate, launch, customProperties, bundledPlugins, modules, fileExtensions, flavors, layout
)
}
}
@Serializable
class ProductFlavorData @Internal constructor(@JvmField val id: String)
class ProductFlavorData @ApiStatus.Internal constructor(@JvmField val id: String)
/**
* Describes 'launch' section in [product-info.json][ProductInfoData] file.
@@ -121,7 +104,7 @@ class ProductInfoLaunchData private constructor(
* Some properties that are nullable in the primary constructor are deliberately marked as not-null in this function to state that they
* are required in the current version, and internal clients may rely on their presence.
*/
@Internal
@ApiStatus.Internal
@JvmStatic
fun create(
os: String,
@@ -134,25 +117,16 @@ class ProductInfoLaunchData private constructor(
mainClass: String,
startupWmClass: String? = null,
customCommands: List<CustomCommandLaunchData> = emptyList(),
): ProductInfoLaunchData {
return ProductInfoLaunchData(
os = os,
arch = arch,
launcherPath = launcherPath,
javaExecutablePath = javaExecutablePath,
vmOptionsFilePath = vmOptionsFilePath,
startupWmClass = startupWmClass,
bootClassPathJarNames = bootClassPathJarNames,
additionalJvmArguments = additionalJvmArguments,
mainClass = mainClass,
customCommands = customCommands
)
}
): ProductInfoLaunchData = ProductInfoLaunchData(
os, arch, launcherPath, javaExecutablePath, vmOptionsFilePath, startupWmClass, bootClassPathJarNames, additionalJvmArguments,
mainClass, customCommands
)
}
}
@Serializable
class CustomCommandLaunchData @Internal constructor(
@Suppress("unused")
class CustomCommandLaunchData @ApiStatus.Internal constructor(
val commands: List<String>,
val vmOptionsFilePath: String? = null,
val bootClassPathJarNames: List<String> = emptyList(),
@@ -163,20 +137,18 @@ class CustomCommandLaunchData @Internal constructor(
)
@Serializable
class CustomProperty @Internal constructor(
class CustomProperty @ApiStatus.Internal constructor(
val key: String,
val value: String,
)
@Serializer(forClass = LocalDate::class)
private object LocalDateSerializer : KSerializer<LocalDate> {
private val formatter = DateTimeFormatter.ofPattern("yyyyMMdd")
private val formatter = DateTimeFormatter.ofPattern(@Suppress("SpellCheckingInspection") "yyyyMMdd")
override fun serialize(encoder: Encoder, value: LocalDate) {
encoder.encodeString(value.format(formatter))
}
override fun deserialize(decoder: Decoder): LocalDate {
return LocalDate.parse(decoder.decodeString(), formatter)
}
override fun deserialize(decoder: Decoder): LocalDate = LocalDate.parse(decoder.decodeString(), formatter)
}