IJPL-217839 simplify createWindowsCustomizer (part 2 - image path as NIO Path)

GitOrigin-RevId: 9aca119c33d39b11878f0887993d8b386a71853f
This commit is contained in:
Vladimir Krivosheev
2025-11-13 12:12:34 +00:00
committed by intellij-monorepo-bot
parent e4364da218
commit 4c04714771
10 changed files with 279 additions and 260 deletions
@@ -142,9 +142,9 @@ open class IdeaCommunityProperties(private val communityHomeDir: Path) : JetBrai
protected open inner class CommunityWindowsDistributionCustomizer : WindowsDistributionCustomizer() {
init {
icoPath = "${communityHomeDir}/build/conf/ideaCE/win/images/idea_CE.ico"
icoPathForEAP = "${communityHomeDir}/build/conf/ideaCE/win/images/idea_CE_EAP.ico"
installerImagesPath = "${communityHomeDir}/build/conf/ideaCE/win/images"
icoPath = communityHomeDir.resolve("build/conf/ideaCE/win/images/idea_CE.ico")
icoPathForEAP = communityHomeDir.resolve("build/conf/ideaCE/win/images/idea_CE_EAP.ico")
installerImagesPath = communityHomeDir.resolve("build/conf/ideaCE/win/images")
}
override val fileAssociations: List<String>
@@ -8,12 +8,12 @@ abstract class WindowsDistributionCustomizer {
/**
* Path to 256x256 *.ico file for Windows distribution.
*/
var icoPath: String? = null
var icoPath: Path? = null
/**
* Path to an ico file for EAP builds (if `null` [icoPath] will be used).
*/
var icoPathForEAP: String? = null
var icoPathForEAP: Path? = null
/**
* If `true`, *.bat files (productName.bat and inspect.bat) will be included in the distribution.
@@ -42,7 +42,7 @@ abstract class WindowsDistributionCustomizer {
/**
* Path to a directory containing images for installer: `logo.bmp`, `headerlogo.bmp`, `install.ico`, `uninstall.ico`.
*/
var installerImagesPath: String? = null
var installerImagesPath: Path? = null
/**
* Set to `false` for products that are not updated with patches.
@@ -611,22 +611,22 @@ private suspend fun checkProductProperties(context: BuildContext) {
}
context.linuxDistributionCustomizer?.let { linuxDistributionCustomizer ->
checkPaths(listOfNotNull(linuxDistributionCustomizer.iconPngPath), "productProperties.linuxCustomizer.iconPngPath")
checkPaths(listOfNotNull(linuxDistributionCustomizer.iconPngPathForEAP), "productProperties.linuxCustomizer.iconPngPathForEAP")
checkStringPaths(listOfNotNull(linuxDistributionCustomizer.iconPngPath), "productProperties.linuxCustomizer.iconPngPath")
checkStringPaths(listOfNotNull(linuxDistributionCustomizer.iconPngPathForEAP), "productProperties.linuxCustomizer.iconPngPathForEAP")
}
context.macDistributionCustomizer?.let { macCustomizer ->
checkMandatoryField(macCustomizer.bundleIdentifier, "productProperties.macCustomizer.bundleIdentifier")
checkMandatoryPath(macCustomizer.icnsPath, "productProperties.macCustomizer.icnsPath")
checkPaths(listOfNotNull(macCustomizer.icnsPathForEAP), "productProperties.macCustomizer.icnsPathForEAP")
checkPaths(listOfNotNull(macCustomizer.icnsPathForAlternativeIcon), "productProperties.macCustomizer.icnsPathForAlternativeIcon")
checkPaths(
checkStringPaths(listOfNotNull(macCustomizer.icnsPathForEAP), "productProperties.macCustomizer.icnsPathForEAP")
checkStringPaths(listOfNotNull(macCustomizer.icnsPathForAlternativeIcon), "productProperties.macCustomizer.icnsPathForAlternativeIcon")
checkStringPaths(
listOfNotNull(macCustomizer.icnsPathForAlternativeIconForEAP),
"productProperties.macCustomizer.icnsPathForAlternativeIconForEAP"
)
context.executeStep(spanBuilder("check .dmg images"), BuildOptions.MAC_DMG_STEP) {
checkMandatoryPath(macCustomizer.dmgImagePath, "productProperties.macCustomizer.dmgImagePath")
checkPaths(listOfNotNull(macCustomizer.dmgImagePathForEAP), "productProperties.macCustomizer.dmgImagePathForEAP")
checkStringPaths(listOfNotNull(macCustomizer.dmgImagePathForEAP), "productProperties.macCustomizer.dmgImagePathForEAP")
}
}
@@ -767,7 +767,14 @@ private fun checkPluginModules(pluginModules: Collection<String>?, fieldName: St
}
}
private fun checkPaths(paths: Collection<String>, propertyName: String) {
private fun checkPaths(paths: Collection<Path>, propertyName: String) {
val nonExistingFiles = paths.filter { Files.notExists(it) }
check(nonExistingFiles.isEmpty()) {
"$propertyName contains non-existing files: ${nonExistingFiles.joinToString()}"
}
}
private fun checkStringPaths(paths: Collection<String>, propertyName: String) {
val nonExistingFiles = paths.filter { Files.notExists(Path.of(it)) }
check(nonExistingFiles.isEmpty()) {
"$propertyName contains non-existing files: ${nonExistingFiles.joinToString()}"
@@ -789,7 +796,7 @@ private fun checkMandatoryField(value: String?, fieldName: String) {
private fun checkMandatoryPath(path: String, fieldName: String) {
checkMandatoryField(path, fieldName)
checkPaths(listOf(path), fieldName)
checkPaths(listOf(Path.of(path)), fieldName)
}
private fun logFreeDiskSpace(phase: String, context: CompilationContext) {
@@ -122,7 +122,7 @@ class LinuxDistributionBuilder(
span.addEvent("skip")
}
else {
buildTarGz(arch, runtimeDir = null, osAndArchSpecificDistPath, NO_RUNTIME_SUFFIX + suffix(arch, targetLibcImpl))
buildTarGz(arch = arch, runtimeDir = null, unixDistPath = osAndArchSpecificDistPath, suffix = NO_RUNTIME_SUFFIX + suffix(arch, targetLibcImpl))
}
}
}
@@ -138,12 +138,12 @@ class LinuxDistributionBuilder(
"linux_tar_gz_${arch.name}"
) { _ ->
val suffix = suffix(arch, targetLibcImpl)
buildTarGz(arch, runtimeDir, osAndArchSpecificDistPath, suffix)
buildTarGz(arch = arch, runtimeDir = runtimeDir, unixDistPath = osAndArchSpecificDistPath, suffix = suffix)
}
if (targetLibcImpl != LinuxLibcImpl.MUSL) {
launch(Dispatchers.IO + CoroutineName("build Snap package")) {
buildSnapPackage(runtimeDir, osAndArchSpecificDistPath, arch, targetLibcImpl)
buildSnapPackage(runtimeDir = runtimeDir, unixDistPath = osAndArchSpecificDistPath, arch = arch, targetLibcImpl = targetLibcImpl)
}
}
@@ -180,8 +180,9 @@ class LinuxDistributionBuilder(
)
}
override fun generateExecutableFilesPatterns(includeRuntime: Boolean, arch: JvmArchitecture, libc: LibcImpl): Sequence<String> =
customizer.generateExecutableFilesPatterns(includeRuntime, arch, libc, context)
override fun generateExecutableFilesPatterns(includeRuntime: Boolean, arch: JvmArchitecture, libc: LibcImpl): Sequence<String> {
return customizer.generateExecutableFilesPatterns(includeRuntime = includeRuntime, arch = arch, targetLibcImpl = libc, context = context)
}
private val rootDirectoryName: String
get() = customizer.getRootDirectoryName(context.applicationInfo, context.buildNumber)
@@ -203,20 +204,27 @@ class LinuxDistributionBuilder(
}
val productJsonDir = context.paths.tempDir.resolve("linux.dist.product-info.json${suffix}")
val productJsonFile = writeProductJsonFile(productJsonDir, arch, withRuntime = runtimeDir != null)
val productJsonFile = writeProductJsonFile(targetDir = productJsonDir, arch = arch, withRuntime = runtimeDir != null)
dirs.add(productJsonDir)
spanBuilder("build Linux tar.gz")
.setAttribute("runtimeDir", runtimeDir?.toString() ?: "")
.setAttribute("targetLibcImpl", targetLibcImpl.name)
.use(Dispatchers.IO) {
val executableFileMatchers = generateExecutableFilesMatchers(includeRuntime = runtimeDir != null, arch, targetLibcImpl).keys
val executableFileMatchers = generateExecutableFilesMatchers(includeRuntime = runtimeDir != null, arch, this@LinuxDistributionBuilder.targetLibcImpl).keys
tar(tarPath, tarRoot, dirs, executableFileMatchers, context.options.buildDateInSeconds)
validateProductJson(tarPath, tarRoot, context)
copyFile(productJsonFile, tarProductInfoJsonPath)
context.notifyArtifactBuilt(tarProductInfoJsonPath)
context.notifyArtifactBuilt(tarPath)
checkExecutablePermissions(tarPath, rootDirectoryName, includeRuntime = runtimeDir != null, arch, targetLibcImpl)
checkExecutablePermissions(
distribution = tarPath,
root = rootDirectoryName,
includeRuntime = runtimeDir != null,
arch = arch,
libc = this@LinuxDistributionBuilder.targetLibcImpl,
)
}
tarPath
}
@@ -239,7 +247,7 @@ class LinuxDistributionBuilder(
}
buildSnapPackage(snapName, runtimeDir, unixDistPath, arch, targetLibcImpl)
customizer.snapLegacyAliases.forEach {
buildSnapPackage(snapName = it, runtimeDir, unixDistPath, arch, targetLibcImpl)
buildSnapPackage(snapName = it, runtimeDir = runtimeDir, unixDistPath = unixDistPath, arch = arch, targetLibcImpl = targetLibcImpl)
}
}
@@ -299,7 +307,7 @@ class LinuxDistributionBuilder(
val productJsonDir = context.paths.tempDir.resolve("linux.dist.snap.$snapName.product-info.json.$architecture")
val productJsonFile = writeProductJsonFile(productJsonDir, arch)
val installationDirectories = listOf(context.paths.distAllDir, unixDistPath, runtimeDir)
validateProductJson(jsonText = productJsonFile.readText(), installationDirectories, installationArchives = emptyList(), context)
validateProductJson(jsonText = productJsonFile.readText(), installationDirectories = installationDirectories, installationArchives = emptyList(), context = context)
val resultDir = snapDir.resolve("result")
Files.createDirectories(resultDir)
@@ -328,7 +336,7 @@ class LinuxDistributionBuilder(
val snapArtifactPath = moveFileToDir(resultDir.resolve(snapArtifactName), context.paths.artifactDir)
context.notifyArtifactBuilt(snapArtifactPath)
checkExecutablePermissions(snapArtifactPath, root = "", includeRuntime = true, arch, targetLibcImpl)
checkExecutablePermissions(distribution = snapArtifactPath, root = "", includeRuntime = true, arch = arch, libc = targetLibcImpl)
val snapProductInfoJsonPath = snapArtifactPath.resolveProductInfoJsonSibling()
copyFile(productJsonFile, snapProductInfoJsonPath)
@@ -379,107 +387,112 @@ 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(sourceFile = file, targetFile = distBinDir.resolve(fileName), additionalTemplateValues = emptyList(), context = context)
}
}
copyInspectScript(context, distBinDir)
generateLauncherScript(distBinDir, arch, nonCustomizableJvmArgs = emptyList(), targetLibcImpl, context)
}
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"))
}
copyInspectScript(context, distBinDir)
private fun generateLauncherScript(distBinDir: Path, arch: JvmArchitecture, nonCustomizableJvmArgs: List<String>, targetLibcImpl: LinuxLibcImpl, context: BuildContext) {
val vmOptionsPath = distBinDir.resolve("${context.productProperties.baseFileName}64.vmoptions")
generateLauncherScript(distBinDir = distBinDir, arch = arch, nonCustomizableJvmArgs = emptyList(), targetLibcImpl = targetLibcImpl, context = context)
}
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>, targetLibcImpl: LinuxLibcImpl, context: BuildContext) {
val vmOptionsPath = distBinDir.resolve("${context.productProperties.baseFileName}64.vmoptions")
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 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 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 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 template = context.paths.communityHomeDir.resolve("platform/build-scripts/resources/linux/scripts/${EXECUTABLE_TEMPLATE_NAME}")
val targetFile = distBinDir.resolve("${context.productProperties.baseFileName}.sh")
copyScript(template, targetFile, 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")
}
additionalJvmArguments.addAll(context.getAdditionalJvmArguments(os = OsFamily.LINUX, arch = 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 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,
)
}
val template = context.paths.communityHomeDir.resolve("platform/build-scripts/resources/linux/scripts/${EXECUTABLE_TEMPLATE_NAME}")
copyScript(
sourceFile = template,
targetFile = distBinDir.resolve("${context.productProperties.baseFileName}.sh"),
additionalTemplateValues = additionalTemplateValues,
context = 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")
VmOptionsGenerator.writeVmOptions(vmOptionsPath, vmOptions, separator = "\n")
return vmOptionsPath
}
private fun writeLinuxVmOptions(distBinDir: Path, context: BuildContext): Path {
val vmOptionsPath = distBinDir.resolve("${context.productProperties.baseFileName}64.vmoptions")
val vmOptions = generateVmOptions(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 =
suffix(arch) + if (targetLibcImpl == LinuxLibcImpl.MUSL) "-musl" else ""
private fun suffix(arch: JvmArchitecture, targetLibcImpl: LinuxLibcImpl): String {
return suffix(arch) + if (targetLibcImpl == LinuxLibcImpl.MUSL) "-musl" else ""
}
private fun getSnapArchName(arch: JvmArchitecture) = when (arch) {
JvmArchitecture.x64 -> "amd64"
JvmArchitecture.aarch64 -> "arm64"
}
private fun getSnapArchName(arch: JvmArchitecture) = when (arch) {
JvmArchitecture.x64 -> "amd64"
JvmArchitecture.aarch64 -> "arm64"
}
@@ -119,7 +119,7 @@ class MacDistributionBuilder(
override suspend fun copyFilesForOsDistribution(targetPath: Path, arch: JvmArchitecture) {
withContext(Dispatchers.IO) {
doCopyExtraFiles(targetPath, arch, copyDistFiles = true)
doCopyExtraFiles(macDistDir = targetPath, arch = arch, copyDistFiles = true)
}
}
@@ -231,7 +231,7 @@ class MacDistributionBuilder(
signMacBinaries(binariesToSign, context)
for (dir in listOf(osAndArchSpecificDistPath, runtimeDist)) {
launch(CoroutineName("recursively signing macOS binaries in $dir")) {
recursivelySignMacBinaries(coroutineScope = this, dir, context, matchers)
recursivelySignMacBinaries(coroutineScope = this, root = dir, context = context, executableFileMatchers = matchers)
}
}
}
@@ -492,15 +492,15 @@ class MacDistributionBuilder(
}
}
validateProductJson(targetFile, pathInArchive = "${zipRoot}/Resources", macDistributionBuilder.context)
validateProductJson(archiveFile = targetFile, pathInArchive = "${zipRoot}/Resources", context = macDistributionBuilder.context)
}
}
private fun writeMacOsVmOptions(distBinDir: Path, context: BuildContext): Path {
val executable = context.productProperties.baseFileName
val vmOptions = VmOptionsGenerator.generate(context).asSequence() + sequenceOf("-Dapple.awt.application.appearance=system")
val vmOptions = generateVmOptions(context).asSequence() + sequenceOf("-Dapple.awt.application.appearance=system")
val vmOptionsPath = distBinDir.resolve("${executable}.vmoptions")
VmOptionsGenerator.writeVmOptions(vmOptionsPath, vmOptions, separator = "\n")
writeVmOptions(vmOptionsPath, vmOptions, separator = "\n")
return vmOptionsPath
}
@@ -569,8 +569,9 @@ class MacDistributionBuilder(
}
}
private fun getMacZipRoot(customizer: MacDistributionCustomizer, context: BuildContext): String =
"${customizer.getRootDirectoryName(context.applicationInfo, context.buildNumber)}/Contents"
private fun getMacZipRoot(customizer: MacDistributionCustomizer, context: BuildContext): String {
return "${customizer.getRootDirectoryName(context.applicationInfo, context.buildNumber)}/Contents"
}
private val publishSitArchive: Boolean
get() = !context.isStepSkipped(BuildOptions.MAC_SIT_PUBLICATION_STEP)
@@ -638,75 +639,75 @@ 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)
}
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
}
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)
}
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()
}
RepairUtilityBuilder.generateManifest(context, tempSit.resolve(sitRoot), OsFamily.MACOS, arch)
}
finally {
withContext(Dispatchers.IO + NonCancellable) {
@OptIn(ExperimentalPathApi::class)
tempSit.deleteRecursively()
}
}
}
@@ -633,7 +633,7 @@ internal class TestingTasksImpl(context: CompilationContext, private val options
val customMemoryOptions = options.jvmMemoryOptions?.trim()?.split(Regex("\\s+"))?.takeIf { it.isNotEmpty() }
jvmArgs.addAll(
index = 0,
elements = VmOptionsGenerator.generate(
elements = generateVmOptions(
isEAP = true,
customVmMemoryOptions = if (customMemoryOptions == null) mapOf("-Xms" to "750m", "-Xmx" to "1024m") else emptyMap(),
additionalVmOptions = customMemoryOptions ?: emptyList(),
@@ -9,92 +9,90 @@ import java.nio.file.Files
import java.nio.file.Path
import kotlin.io.path.name
object VmOptionsGenerator {
private const val DEFAULT_MIN_HEAP = "128m"
private const val DEFAULT_MAX_HEAP = "2048m"
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",
)
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"
/** 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.productProperties.customJvmMemoryOptions,
context.productProperties.additionalVmOptions.let {
val url = computeCustomPluginRepositoryUrl(context)
if (url == null) it else it + "-D${CUSTOM_BUILT_IN_PLUGIN_REPOSITORY_PROPERTY}=${url}"
},
context.productProperties.platformPrefix,
)
fun generateVmOptions(context: BuildContext): List<String> = generateVmOptions(
context.applicationInfo.isEAP,
context.productProperties.customJvmMemoryOptions,
context.productProperties.additionalVmOptions.let {
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,
customVmMemoryOptions: Map<String, String>,
additionalVmOptions: List<String>,
platformPrefix: String?,
): List<String> {
val result = ArrayList<String>()
internal fun generateVmOptions(
isEAP: Boolean,
customVmMemoryOptions: Map<String, String>,
additionalVmOptions: List<String>,
platformPrefix: String?,
): List<String> {
val result = ArrayList<String>()
val memory = LinkedHashMap<String, String>(customVmMemoryOptions)
memory.putIfAbsent("-Xms", DEFAULT_MIN_HEAP)
memory.putIfAbsent("-Xmx", DEFAULT_MAX_HEAP)
for ((k, v) in memory) {
result += k + v
}
result += COMMON_VM_OPTIONS
if (isMultiRoutingFileSystemEnabledForProduct(platformPrefix)) {
result.addAll(MULTI_ROUTING_FILE_SYSTEM_VMOPTIONS)
}
result += additionalVmOptions
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
val memory = LinkedHashMap<String, String>(customVmMemoryOptions)
memory.putIfAbsent("-Xms", DEFAULT_MIN_HEAP)
memory.putIfAbsent("-Xmx", DEFAULT_MAX_HEAP)
for ((k, v) in memory) {
result += k + v
}
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 null
result += COMMON_VM_OPTIONS
if (isMultiRoutingFileSystemEnabledForProduct(platformPrefix)) {
result.addAll(MULTI_ROUTING_FILE_SYSTEM_VMOPTIONS)
}
internal fun writeVmOptions(file: Path, vmOptions: Sequence<String>, separator: String) {
Files.writeString(file, vmOptions.joinToString(separator, postfix = separator), StandardCharsets.US_ASCII)
result += additionalVmOptions
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}")
}
return builtinPluginsRepoUrl
}
}
return null
}
internal fun writeVmOptions(file: Path, vmOptions: Sequence<String>, separator: String) {
Files.writeString(file, vmOptions.joinToString(separator, postfix = separator), StandardCharsets.US_ASCII)
}
@@ -196,7 +196,7 @@ private suspend fun prepareConfigurationFiles(nsiConfDir: Path, uninstallerFileN
Files.writeString(nsiConfDir.resolve("config.nsi"), $$"""
!define INSTALLER_ARCH $${expectedArch}
!define IMAGES_LOCATION "$${Path.of(customizer.installerImagesPath!!)}"
!define IMAGES_LOCATION "$${customizer.installerImagesPath!!}"
!define MANUFACTURER "$${appInfo.shortCompanyName}"
!define MUI_PRODUCT "$${customizer.getFullNameIncludingEdition(appInfo)}"
@@ -468,13 +468,13 @@ internal class WindowsDistributionBuilder(
val customizer = context.windowsDistributionCustomizer!!
val icoPath = (if (context.applicationInfo.isEAP) customizer.icoPathForEAP else null) ?: customizer.icoPath
requireNotNull(icoPath) { "`WindowsDistributionCustomizer#icoPath` must be set" }
return Path.of(icoPath)
return icoPath
}
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")
val vmOptions = generateVmOptions(context).asSequence()
writeVmOptions(vmOptionsFile, vmOptions, separator = "\r\n")
return vmOptionsFile
}
@@ -90,9 +90,9 @@ open class PyCharmCommunityProperties(protected val communityHome: Path) : PyCha
override fun createWindowsCustomizer(projectHome: Path): WindowsDistributionCustomizer = object : WindowsDistributionCustomizer() {
init {
icoPath = "${communityHome}/python/build/resources/PyCharmCore.ico"
icoPathForEAP = "${communityHome}/python/build/resources/PyCharmCore_EAP.ico"
installerImagesPath = "${communityHome}/python/build/resources"
icoPath = communityHome.resolve("python/build/resources/PyCharmCore.ico")
icoPathForEAP = communityHome.resolve("python/build/resources/PyCharmCore_EAP.ico")
installerImagesPath = communityHome.resolve("python/build/resources")
}
override val fileAssociations: List<String>