IJPL-172978 different UUIDs for IDE binaries on macOS

(cherry picked from commit e56374d6355c41d66e41e2de4c2ca14431464537)

IJ-CR-151551

GitOrigin-RevId: a18ab4cd13c6476dfff57f6cb62722f72c5dcb68
This commit is contained in:
Dmitriy.Panov
2024-12-11 20:45:15 +01:00
committed by intellij-monorepo-bot
parent 5b5d8415c7
commit 82fa4ae1e2
5 changed files with 95 additions and 18 deletions

View File

@@ -3,8 +3,10 @@ package org.jetbrains.intellij.build
import kotlinx.collections.immutable.PersistentList import kotlinx.collections.immutable.PersistentList
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import org.jetbrains.annotations.ApiStatus
import org.jetbrains.intellij.build.impl.support.RepairUtilityBuilder import org.jetbrains.intellij.build.impl.support.RepairUtilityBuilder
import java.nio.file.Path import java.nio.file.Path
import java.util.UUID
import java.util.function.Predicate import java.util.function.Predicate
open class MacDistributionCustomizer { open class MacDistributionCustomizer {
@@ -164,4 +166,12 @@ open class MacDistributionCustomizer {
extraExecutables + extraExecutables +
context.getExtraExecutablePattern(OsFamily.MACOS) context.getExtraExecutablePattern(OsFamily.MACOS)
} }
/**
* @see org.jetbrains.intellij.build.NativeBinaryDownloader.getLauncher
*/
@ApiStatus.Internal
open fun getDistributionUUID(context: BuildContext): UUID {
return UUID.nameUUIDFromBytes("${context.fullBuildNumber}-${context.options.buildDateInSeconds}".toByteArray())
}
} }

View File

@@ -14,6 +14,7 @@ import org.apache.commons.compress.archivers.zip.ZipArchiveEntry
import org.jetbrains.intellij.build.* import org.jetbrains.intellij.build.*
import org.jetbrains.intellij.build.impl.OsSpecificDistributionBuilder.Companion.suffix import org.jetbrains.intellij.build.impl.OsSpecificDistributionBuilder.Companion.suffix
import org.jetbrains.intellij.build.impl.client.createJetBrainsClientContextForLaunchers import org.jetbrains.intellij.build.impl.client.createJetBrainsClientContextForLaunchers
import org.jetbrains.intellij.build.impl.macOS.MachOUuid
import org.jetbrains.intellij.build.impl.productInfo.* import org.jetbrains.intellij.build.impl.productInfo.*
import org.jetbrains.intellij.build.impl.qodana.generateQodanaLaunchData import org.jetbrains.intellij.build.impl.qodana.generateQodanaLaunchData
import org.jetbrains.intellij.build.impl.support.RepairUtilityBuilder import org.jetbrains.intellij.build.impl.support.RepairUtilityBuilder
@@ -24,6 +25,7 @@ import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path
import java.nio.file.StandardCopyOption import java.nio.file.StandardCopyOption
import java.time.LocalDate import java.time.LocalDate
import java.util.UUID
import java.util.zip.Deflater import java.util.zip.Deflater
import kotlin.io.path.* import kotlin.io.path.*
@@ -212,7 +214,9 @@ class MacDistributionBuilder(
val executable = context.productProperties.baseFileName val executable = context.productProperties.baseFileName
val (execPath, licensePath) = NativeBinaryDownloader.getLauncher(context, OsFamily.MACOS, arch) val (execPath, licensePath) = NativeBinaryDownloader.getLauncher(context, OsFamily.MACOS, arch)
copyFile(execPath, macDistDir.resolve("MacOS/${executable}")) val copy = macDistDir.resolve("MacOS/$executable")
copyFile(execPath, copy)
MachOUuid(copy, customizer.getDistributionUUID(context), context).patch()
copyFile(licensePath, macDistDir.resolve("license/launcher-third-party-libraries.html")) copyFile(licensePath, macDistDir.resolve("license/launcher-third-party-libraries.html"))
val icnsPath = Path.of((if (context.applicationInfo.isEAP) customizer.icnsPathForEAP else null) ?: customizer.icnsPath) val icnsPath = Path.of((if (context.applicationInfo.isEAP) customizer.icnsPathForEAP else null) ?: customizer.icnsPath)

View File

@@ -0,0 +1,64 @@
// Copyright 2000-2024 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.macOS
import org.jetbrains.intellij.build.BuildContext
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.StandardOpenOption
import java.util.*
/**
* Patches UUID value in the Mach-O [executable] with the [newUuid].
* Only single-arch 64-bit files are supported.
*/
internal class MachOUuid(private val executable: Path, private val newUuid: UUID, private val context: BuildContext) {
private companion object {
const val LC_UUID = 0x1b
}
fun patch() {
Files.newByteChannel(executable, StandardOpenOption.READ, StandardOpenOption.WRITE).use { channel ->
var buffer = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN)
channel.read(buffer)
buffer.flip()
val magic = buffer.getInt()
check(magic == -0x1120531) { "Not a valid 64-bit Mach-O file: 0x" + Integer.toHexString(magic) }
buffer.clear()
channel.position(16)
channel.read(buffer)
buffer.flip()
val nCmds = buffer.getInt()
buffer = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN)
channel.position(32)
(0..<nCmds).forEach {
buffer.clear()
channel.read(buffer)
buffer.flip()
val cmd = buffer.getInt()
val cmdSize = buffer.getInt()
if (cmd == LC_UUID) {
buffer = ByteBuffer.allocate(16).order(ByteOrder.BIG_ENDIAN)
channel.read(buffer)
buffer.flip()
val msb = buffer.getLong()
val lsb = buffer.getLong()
context.messages.info("current UUID of $executable: ${UUID(msb, lsb)}")
buffer.clear()
buffer.putLong(newUuid.mostSignificantBits)
buffer.putLong(newUuid.leastSignificantBits)
buffer.flip()
channel.position(channel.position() - 16)
channel.write(buffer)
context.messages.info("new UUID of $executable: $newUuid")
return
}
else {
channel.position(channel.position() + cmdSize - 8)
}
}
context.messages.error("LC_UUID not found in $executable")
}
}
}

View File

@@ -11,7 +11,7 @@ import org.jetbrains.intellij.build.io.copyFileToDir
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path
open class PyCharmCommunityProperties(private val communityHome: Path) : PyCharmPropertiesBase(enlargeWelcomeScreen = true) { open class PyCharmCommunityProperties(protected val communityHome: Path) : PyCharmPropertiesBase(enlargeWelcomeScreen = true) {
override val customProductCode: String override val customProductCode: String
get() = "PC" get() = "PC"
@@ -73,10 +73,10 @@ open class PyCharmCommunityProperties(private val communityHome: Path) : PyCharm
} }
override fun createMacCustomizer(projectHome: String): MacDistributionCustomizer { override fun createMacCustomizer(projectHome: String): MacDistributionCustomizer {
return PyCharmCommunityMacDistributionCustomizer(communityHome) return PyCharmMacDistributionCustomizer(communityHome)
} }
override fun getOutputDirectoryName(appInfo: ApplicationInfoProperties) = "pycharm-ce" override fun getOutputDirectoryName(appInfo: ApplicationInfoProperties): String = "pycharm-ce"
} }
private class PyCharmCommunityWindowsDistributionCustomizer(projectHome: Path) : PyCharmWindowsDistributionCustomizer() { private class PyCharmCommunityWindowsDistributionCustomizer(projectHome: Path) : PyCharmWindowsDistributionCustomizer() {
@@ -101,16 +101,3 @@ private open class PyCharmCommunityLinuxDistributionCustomizer(projectHome: Path
} }
} }
private class PyCharmCommunityMacDistributionCustomizer(projectHome: Path) : PyCharmMacDistributionCustomizer() {
init {
icnsPath = "$projectHome/python/build/resources/PyCharmCore.icns"
icnsPathForEAP = "$projectHome/python/build/resources/PyCharmCore_EAP.icns"
bundleIdentifier = "com.jetbrains.pycharm.ce"
dmgImagePath = "$projectHome/python/build/resources/dmg_background.tiff"
}
override fun getRootDirectoryName(appInfo: ApplicationInfoProperties, buildNumber: String): String {
val suffix = if (appInfo.isEAP) " ${appInfo.majorVersion}.${appInfo.minorVersion} EAP" else ""
return "PyCharm CE${suffix}.app"
}
}

View File

@@ -7,7 +7,19 @@ import org.jetbrains.intellij.build.JvmArchitecture
import org.jetbrains.intellij.build.MacDistributionCustomizer import org.jetbrains.intellij.build.MacDistributionCustomizer
import java.nio.file.Path import java.nio.file.Path
open class PyCharmMacDistributionCustomizer : MacDistributionCustomizer() { open class PyCharmMacDistributionCustomizer(projectHome: Path) : MacDistributionCustomizer() {
init {
icnsPath = "$projectHome/python/build/resources/PyCharmCore.icns"
icnsPathForEAP = "$projectHome/python/build/resources/PyCharmCore_EAP.icns"
bundleIdentifier = "com.jetbrains.pycharm.ce"
dmgImagePath = "$projectHome/python/build/resources/dmg_background.tiff"
}
override fun getRootDirectoryName(appInfo: ApplicationInfoProperties, buildNumber: String): String {
val suffix = if (appInfo.isEAP) " ${appInfo.majorVersion}.${appInfo.minorVersion} EAP" else ""
return "PyCharm CE${suffix}.app"
}
override suspend fun copyAdditionalFiles(context: BuildContext, targetDir: Path, arch: JvmArchitecture) { override suspend fun copyAdditionalFiles(context: BuildContext, targetDir: Path, arch: JvmArchitecture) {
super.copyAdditionalFiles(context, targetDir, arch) super.copyAdditionalFiles(context, targetDir, arch)
PyCharmBuildUtils.copySkeletons(context, targetDir, "skeletons-mac*.zip") PyCharmBuildUtils.copySkeletons(context, targetDir, "skeletons-mac*.zip")