IJPL-217839 simplify UltimateMacDistributionCustomizer

GitOrigin-RevId: 0a8a660eec3505668d1f814230b4c1e1644dc42d
This commit is contained in:
Vladimir Krivosheev
2025-11-18 08:02:19 +00:00
committed by intellij-monorepo-bot
parent e835485f62
commit e586dbfa8d
13 changed files with 90 additions and 57 deletions
@@ -138,7 +138,7 @@ open class IdeaCommunityProperties(private val communityHomeDir: Path) : JetBrai
override fun createLinuxCustomizer(projectHome: String): LinuxDistributionCustomizer = CommunityLinuxDistributionCustomizer()
override fun createMacCustomizer(projectHome: String): MacDistributionCustomizer = CommunityMacDistributionCustomizer()
override fun createMacCustomizer(projectHome: Path): MacDistributionCustomizer = CommunityMacDistributionCustomizer()
protected open inner class CommunityWindowsDistributionCustomizer : WindowsDistributionCustomizer() {
init {
@@ -185,13 +185,13 @@ open class IdeaCommunityProperties(private val communityHomeDir: Path) : JetBrai
protected open inner class CommunityMacDistributionCustomizer : MacDistributionCustomizer() {
init {
icnsPath = "${communityHomeDir}/build/conf/ideaCE/mac/images/idea.icns"
icnsPathForEAP = "${communityHomeDir}/build/conf/ideaCE/mac/images/communityEAP.icns"
icnsPath = communityHomeDir.resolve("build/conf/ideaCE/mac/images/idea.icns")
icnsPathForEAP = communityHomeDir.resolve("build/conf/ideaCE/mac/images/communityEAP.icns")
urlSchemes = listOf("idea")
associateIpr = true
fileAssociations = FileAssociation.from("java", "groovy", "kt", "kts")
bundleIdentifier = "com.jetbrains.intellij.ce"
dmgImagePath = "${communityHomeDir}/build/conf/ideaCE/mac/images/dmg_background.tiff"
dmgImagePath = communityHomeDir.resolve("build/conf/ideaCE/mac/images/dmg_background.tiff")
}
override fun getRootDirectoryName(appInfo: ApplicationInfoProperties, buildNumber: String): String {
@@ -85,6 +85,6 @@ open class LinuxDistributionCustomizer {
* Override this method to copy additional files to the Linux distribution of the product.
*/
open suspend fun copyAdditionalFiles(targetDir: Path, arch: JvmArchitecture, context: BuildContext) {
RepairUtilityBuilder.bundle(context, OsFamily.LINUX, arch, targetDir)
RepairUtilityBuilder.bundle(OsFamily.LINUX, arch, targetDir, context)
}
}
@@ -22,22 +22,22 @@ open class MacDistributionCustomizer {
*
* Reference: [Apple Icon Image Format](https://en.wikipedia.org/wiki/Apple_Icon_Image_format).
*/
lateinit var icnsPath: String
lateinit var icnsPath: Path
/**
* Path to an .icns file for EAP builds (if `null`, [icnsPath] will be used).
*/
var icnsPathForEAP: String? = null
var icnsPathForEAP: Path? = null
/**
* Path to an alternative .icns file in macOS Big Sur style
*/
var icnsPathForAlternativeIcon: String? = null
var icnsPathForAlternativeIcon: Path? = null
/**
* Path to an alternative .icns file in macOS Big Sur style for EAP
*/
var icnsPathForAlternativeIconForEAP: String? = null
var icnsPathForAlternativeIconForEAP: Path? = null
/**
* Relative paths to files in macOS distribution which should take 'executable' permissions.
@@ -56,7 +56,7 @@ open class MacDistributionCustomizer {
/**
* Path to an image which will be injected into the .dmg file.
*/
lateinit var dmgImagePath: String
lateinit var dmgImagePath: Path
/**
* The minimum version of macOS where the product is allowed to be installed.
@@ -114,7 +114,7 @@ open class MacDistributionCustomizer {
/**
* Path to an image which will be injected into .dmg file for EAP builds (if `null` dmgImagePath will be used).
*/
var dmgImagePathForEAP: String? = null
var dmgImagePathForEAP: Path? = null
/**
* If `true`, a separate *-[org.jetbrains.intellij.build.impl.NO_RUNTIME_SUFFIX].dmg artifact without a runtime will be produced.
@@ -139,7 +139,7 @@ open class MacDistributionCustomizer {
* Override this method to copy additional files to the macOS distribution of the product.
*/
open suspend fun copyAdditionalFiles(context: BuildContext, targetDir: Path, arch: JvmArchitecture) {
RepairUtilityBuilder.bundle(context, OsFamily.MACOS, arch, targetDir)
RepairUtilityBuilder.bundle(os = OsFamily.MACOS, arch = arch, distributionDir = targetDir, context = context)
}
open fun generateExecutableFilesPatterns(includeRuntime: Boolean, arch: JvmArchitecture, context: BuildContext): Sequence<String> {
@@ -294,7 +294,7 @@ abstract class ProductProperties {
* @return an instance of the class containing properties specific for macOS distribution,
* or `null` if the product doesn't have macOS distribution.
*/
abstract fun createMacCustomizer(projectHome: String): MacDistributionCustomizer?
abstract fun createMacCustomizer(projectHome: Path): MacDistributionCustomizer?
/**
* If `true`, a .zip archive containing sources of modules included in the product will be produced.
@@ -78,7 +78,7 @@ abstract class WindowsDistributionCustomizer {
* Override this method to copy additional files to the Windows distribution of the product.
*/
open suspend fun copyAdditionalFiles(targetDir: Path, arch: JvmArchitecture, context: BuildContext) {
RepairUtilityBuilder.bundle(context, OsFamily.WINDOWS, arch, targetDir)
RepairUtilityBuilder.bundle(OsFamily.WINDOWS, arch, targetDir, context)
}
/**
@@ -212,7 +212,7 @@ class BuildContextImpl internal constructor(
productProperties = productProperties,
windowsDistributionCustomizer = productProperties.createWindowsCustomizer(projectHome),
linuxDistributionCustomizer = productProperties.createLinuxCustomizer(projectHomeAsString),
macDistributionCustomizer = productProperties.createMacCustomizer(projectHomeAsString),
macDistributionCustomizer = productProperties.createMacCustomizer(projectHome),
proprietaryBuildTools = proprietaryBuildTools,
applicationInfo = ApplicationInfoPropertiesImpl(project = compilationContext.project, productProperties = productProperties, buildOptions = compilationContext.options),
jarCacheManager = jarCacheManager,
@@ -346,7 +346,7 @@ class BuildContextImpl internal constructor(
productProperties = productProperties,
windowsDistributionCustomizer = productProperties.createWindowsCustomizer(projectHomeForCustomizers),
linuxDistributionCustomizer = productProperties.createLinuxCustomizer(projectHomeForCustomizersAsString),
macDistributionCustomizer = productProperties.createMacCustomizer(projectHomeForCustomizersAsString),
macDistributionCustomizer = productProperties.createMacCustomizer(projectHomeForCustomizers),
proprietaryBuildTools = proprietaryBuildTools,
applicationInfo = newAppInfo,
jarCacheManager = jarCacheManager,
@@ -617,16 +617,16 @@ private suspend fun checkProductProperties(context: BuildContext) {
context.macDistributionCustomizer?.let { macCustomizer ->
checkMandatoryField(macCustomizer.bundleIdentifier, "productProperties.macCustomizer.bundleIdentifier")
checkMandatoryPath(macCustomizer.icnsPath, "productProperties.macCustomizer.icnsPath")
checkStringPaths(listOfNotNull(macCustomizer.icnsPathForEAP), "productProperties.macCustomizer.icnsPathForEAP")
checkStringPaths(listOfNotNull(macCustomizer.icnsPathForAlternativeIcon), "productProperties.macCustomizer.icnsPathForAlternativeIcon")
checkStringPaths(
checkPaths(listOf(macCustomizer.icnsPath), "productProperties.macCustomizer.icnsPath")
checkPaths(listOfNotNull(macCustomizer.icnsPathForEAP), "productProperties.macCustomizer.icnsPathForEAP")
checkPaths(listOfNotNull(macCustomizer.icnsPathForAlternativeIcon), "productProperties.macCustomizer.icnsPathForAlternativeIcon")
checkPaths(
listOfNotNull(macCustomizer.icnsPathForAlternativeIconForEAP),
"productProperties.macCustomizer.icnsPathForAlternativeIconForEAP"
)
context.executeStep(spanBuilder("check .dmg images"), BuildOptions.MAC_DMG_STEP) {
checkMandatoryPath(macCustomizer.dmgImagePath, "productProperties.macCustomizer.dmgImagePath")
checkStringPaths(listOfNotNull(macCustomizer.dmgImagePathForEAP), "productProperties.macCustomizer.dmgImagePathForEAP")
checkPaths(listOf(macCustomizer.dmgImagePath), "productProperties.macCustomizer.dmgImagePath")
checkPaths(listOfNotNull(macCustomizer.dmgImagePathForEAP), "productProperties.macCustomizer.dmgImagePathForEAP")
}
}
@@ -152,7 +152,7 @@ class LinuxDistributionBuilder(
val tempTar = Files.createTempDirectory(context.paths.tempDir, "tar-")
try {
unTar(tarGzPath, tempTar)
RepairUtilityBuilder.generateManifest(context, unpackedDistribution = tempTar.resolve(rootDirectoryName), OsFamily.LINUX, arch)
RepairUtilityBuilder.generateManifest(unpackedDistribution = tempTar.resolve(rootDirectoryName), OsFamily.LINUX, arch, context)
}
finally {
NioFiles.deleteRecursively(tempTar)
@@ -137,7 +137,7 @@ class MacDistributionBuilder(
platformProperties.add("$k=$v")
}
layoutMacApp(ideaProperties!!, platformProperties, getDocTypes(), macDistDir, arch)
layoutMacApp(ideaPropertyContent = ideaProperties!!, platformProperties = platformProperties, docTypes = getDocTypes(), macDistDir = macDistDir, arch = arch)
generateBuildTxt(context, macDistDir.resolve("Resources"))
@@ -192,13 +192,29 @@ class MacDistributionBuilder(
}
buildMacZip(
builder, macZip, zipRoot, arch, productJson, directories, extraFiles, includeRuntime = true, compressionLevel
macDistributionBuilder = builder,
targetFile = macZip,
zipRoot = zipRoot,
arch = arch,
productJson = productJson,
directories = directories,
extraFiles = extraFiles,
includeRuntime = true,
compressionLevel = compressionLevel,
)
if (customizer.buildArtifactWithoutRuntime) {
val directoriesSansRuntime = directories.filterNot { it == runtimeDir }
buildMacZip(
builder, macZipWithoutRuntime, zipRoot, arch, productJsonWithoutRuntime, directoriesSansRuntime, extraFiles, includeRuntime = false, compressionLevel
macDistributionBuilder = builder,
targetFile = macZipWithoutRuntime,
zipRoot = zipRoot,
arch = arch,
productJson = productJsonWithoutRuntime,
directories = directoriesSansRuntime,
extraFiles = extraFiles,
includeRuntime = false,
compressionLevel = compressionLevel,
)
}
@@ -212,7 +228,13 @@ class MacDistributionBuilder(
}
}
else {
buildForArch(arch, macZip, macZipProductInfoJson, macZipWithoutRuntime, macZipWithoutRuntimeProductInfoJson)
buildForArch(
arch = arch,
macZip = macZip,
macZipProductInfoJson = macZipProductInfoJson,
macZipWithoutRuntime = macZipWithoutRuntime,
macZipWithoutRuntimeProductInfoJson = macZipWithoutRuntimeProductInfoJson,
)
}
}
}
@@ -258,13 +280,13 @@ class MacDistributionBuilder(
MachOUuid(copy, customizer, context).patch()
copyFile(licensePath, macDistDir.resolve("license/launcher-third-party-libraries.html"))
val icnsPath = Path.of(customizer.icnsPathForEAP?.takeIf { context.applicationInfo.isEAP } ?: customizer.icnsPath)
val icnsPath = customizer.icnsPathForEAP?.takeIf { context.applicationInfo.isEAP } ?: customizer.icnsPath
val resourcesDistDir = macDistDir.resolve("Resources")
copyFile(icnsPath, resourcesDistDir.resolve(targetIcnsFileName))
val alternativeIcon = customizer.icnsPathForAlternativeIconForEAP?.takeIf { context.applicationInfo.isEAP } ?: customizer.icnsPathForAlternativeIcon
if (alternativeIcon != null) {
copyFile(Path.of(alternativeIcon), resourcesDistDir.resolve("custom.icns"))
copyFile(alternativeIcon, resourcesDistDir.resolve("custom.icns"))
}
for (fileAssociation in customizer.fileAssociations) {
@@ -327,8 +349,9 @@ class MacDistributionBuilder(
}
}
override fun generateExecutableFilesPatterns(includeRuntime: Boolean, arch: JvmArchitecture, libc: LibcImpl): Sequence<String> =
customizer.generateExecutableFilesPatterns(includeRuntime, arch, context)
override fun generateExecutableFilesPatterns(includeRuntime: Boolean, arch: JvmArchitecture, libc: LibcImpl): Sequence<String> {
return customizer.generateExecutableFilesPatterns(includeRuntime, arch, context)
}
private suspend fun buildForArch(
arch: JvmArchitecture,
@@ -500,7 +523,7 @@ class MacDistributionBuilder(
val executable = context.productProperties.baseFileName
val vmOptions = generateVmOptions(context).asSequence() + sequenceOf("-Dapple.awt.application.appearance=system")
val vmOptionsPath = distBinDir.resolve("${executable}.vmoptions")
writeVmOptions(vmOptionsPath, vmOptions, separator = "\n")
writeVmOptions(file = vmOptionsPath, vmOptions = vmOptions, separator = "\n")
return vmOptionsPath
}
@@ -569,10 +592,6 @@ class MacDistributionBuilder(
}
}
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)
@@ -593,7 +612,7 @@ class MacDistributionBuilder(
notarize(sitFile, context)
}
buildDmg(sitFile, productInfoJson, "${baseName}.dmg", notarize)
buildDmg(sitFile = sitFile, productInfoJson = productInfoJson, dmgName = "${baseName}.dmg", staple = notarize)
if (publishSitArchive) {
context.notifyArtifactBuilt(sitFile)
@@ -601,10 +620,10 @@ class MacDistributionBuilder(
}
val zipRoot = getMacZipRoot(customizer, context)
checkExecutablePermissions(sitFile, zipRoot, isRuntimeBundled, arch, targetLibcImpl)
checkExecutablePermissions(distribution = sitFile, root = zipRoot, includeRuntime = isRuntimeBundled, arch = arch, libc = targetLibcImpl)
if (isRuntimeBundled) {
generateIntegrityManifest(sitFile, zipRoot, arch, context)
generateIntegrityManifest(sitFile = sitFile, sitRoot = zipRoot, arch = arch, context = context)
}
}
@@ -641,11 +660,15 @@ class MacDistributionBuilder(
}
}
private fun getMacZipRoot(customizer: MacDistributionCustomizer, context: BuildContext): String {
return "${customizer.getRootDirectoryName(context.applicationInfo, context.buildNumber)}/Contents"
}
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)
Files.copy((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"))
@@ -702,7 +725,7 @@ private suspend fun generateIntegrityManifest(sitFile: Path, sitRoot: String, ar
.withZipExtensions()
.extract(tempSit)
}
RepairUtilityBuilder.generateManifest(context, tempSit.resolve(sitRoot), OsFamily.MACOS, arch)
RepairUtilityBuilder.generateManifest(tempSit.resolve(sitRoot), OsFamily.MACOS, arch, context)
}
finally {
withContext(Dispatchers.IO + NonCancellable) {
@@ -455,7 +455,7 @@ private suspend fun checkThatExeInstallerAndZipWithJbrAreTheSame(
}
}
if (!context.options.buildStepsToSkip.contains(BuildOptions.REPAIR_UTILITY_BUNDLE_STEP)) {
RepairUtilityBuilder.generateManifest(context, tempExe, OsFamily.WINDOWS, arch)
RepairUtilityBuilder.generateManifest(tempExe, OsFamily.WINDOWS, arch, context)
}
}
finally {
@@ -5,25 +5,32 @@ package org.jetbrains.intellij.build.impl.support
import com.intellij.openapi.util.SystemInfoRt
import io.opentelemetry.api.trace.Span
import kotlinx.coroutines.*
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import org.jetbrains.intellij.build.*
import kotlinx.coroutines.withContext
import org.jetbrains.intellij.build.BuildContext
import org.jetbrains.intellij.build.BuildOptions.Companion.REPAIR_UTILITY_BUNDLE_STEP
import org.jetbrains.intellij.build.JvmArchitecture
import org.jetbrains.intellij.build.JvmArchitecture.Companion.currentJvmArch
import org.jetbrains.intellij.build.OsFamily
import org.jetbrains.intellij.build.OsFamily.Companion.currentOs
import org.jetbrains.intellij.build.dependencies.TeamCityHelper
import org.jetbrains.intellij.build.executeStep
import org.jetbrains.intellij.build.impl.Docker
import org.jetbrains.intellij.build.impl.OsSpecificDistributionBuilder
import org.jetbrains.intellij.build.impl.asyncLazy
import org.jetbrains.intellij.build.io.runProcess
import org.jetbrains.intellij.build.retryWithExponentialBackOff
import org.jetbrains.intellij.build.telemetry.TraceManager.spanBuilder
import org.jetbrains.intellij.build.telemetry.use
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardCopyOption
import java.nio.file.attribute.PosixFilePermission.*
import java.util.*
import java.util.UUID
import java.util.WeakHashMap
import kotlin.time.Duration.Companion.minutes
/**
@@ -44,7 +51,7 @@ class RepairUtilityBuilder {
companion object {
private val buildLock = Mutex()
suspend fun bundle(context: BuildContext, os: OsFamily, arch: JvmArchitecture, distributionDir: Path) {
suspend fun bundle(os: OsFamily, arch: JvmArchitecture, distributionDir: Path, context: BuildContext) {
context.executeStep(spanBuilder("bundle repair-utility").setAttribute("os", os.osName), REPAIR_UTILITY_BUNDLE_STEP) {
if (!canBinariesBeBuilt(context)) {
return@executeStep
@@ -65,7 +72,7 @@ class RepairUtilityBuilder {
}
}
suspend fun generateManifest(context: BuildContext, unpackedDistribution: Path, os: OsFamily, arch: JvmArchitecture) {
suspend fun generateManifest(unpackedDistribution: Path, os: OsFamily, arch: JvmArchitecture, context: BuildContext) {
context.executeStep(spanBuilder("generate installation integrity manifest")
.setAttribute("dir", unpackedDistribution.toString()), REPAIR_UTILITY_BUNDLE_STEP) {
check(Files.exists(unpackedDistribution)) {
@@ -163,10 +170,12 @@ class RepairUtilityBuilder {
buildLock.withLock {
withContext(Dispatchers.IO) {
retryWithExponentialBackOff {
runProcess(args = listOf("bash", "build.sh"), workingDir = projectHome,
additionalEnvVariables = distributionUrls,
timeout = 5.minutes,
inheritOut = true)
runProcess(
args = listOf("bash", "build.sh"), workingDir = projectHome,
additionalEnvVariables = distributionUrls,
timeout = 5.minutes,
inheritOut = true,
)
}
}
}
@@ -109,7 +109,7 @@ open class PyCharmCommunityProperties(protected val communityHome: Path) : PyCha
}
}
override fun createMacCustomizer(projectHome: String): MacDistributionCustomizer = PyCharmMacDistributionCustomizer(communityHome)
override fun createMacCustomizer(projectHome: Path): MacDistributionCustomizer = PyCharmMacDistributionCustomizer(communityHome)
override fun createLinuxCustomizer(projectHome: String): LinuxDistributionCustomizer {
return object : LinuxDistributionCustomizer() {
@@ -9,10 +9,10 @@ import java.nio.file.Path
open class PyCharmMacDistributionCustomizer(projectHome: Path) : MacDistributionCustomizer() {
init {
icnsPath = "$projectHome/python/build/resources/PyCharmCore.icns"
icnsPathForEAP = "$projectHome/python/build/resources/PyCharmCore_EAP.icns"
icnsPath = projectHome.resolve("python/build/resources/PyCharmCore.icns")
icnsPathForEAP = projectHome.resolve("python/build/resources/PyCharmCore_EAP.icns")
bundleIdentifier = "com.jetbrains.pycharm.ce"
dmgImagePath = "$projectHome/python/build/resources/dmg_background.tiff"
dmgImagePath = projectHome.resolve("python/build/resources/dmg_background.tiff")
}
override fun getRootDirectoryName(appInfo: ApplicationInfoProperties, buildNumber: String): String {
@@ -25,6 +25,7 @@ open class PyCharmMacDistributionCustomizer(projectHome: Path) : MacDistribution
PyCharmBuildUtils.copySkeletons(context, targetDir, "skeletons-mac*.zip")
}
override fun getCustomIdeaProperties(appInfo: ApplicationInfoProperties): Map<String, String> =
mapOf("ide.mac.useNativeClipboard" to "false")
override fun getCustomIdeaProperties(appInfo: ApplicationInfoProperties): Map<String, String> {
return mapOf("ide.mac.useNativeClipboard" to "false")
}
}