IJPL-866 cleanup

GitOrigin-RevId: 3d61931f2964e559c81c5f28347df98446222f3d
This commit is contained in:
Vladimir Krivosheev
2024-03-31 21:08:07 +03:00
committed by intellij-monorepo-bot
parent a6711620be
commit e41540544b
4 changed files with 133 additions and 93 deletions
@@ -16,9 +16,6 @@ import org.jetbrains.intellij.build.closeKtorClient
import java.nio.file.Files
import java.nio.file.Path
import java.util.*
import kotlin.io.path.bufferedReader
import kotlin.io.path.exists
import kotlin.io.path.listDirectoryEntries
@Serializable
internal data class Configuration(@JvmField val products: Map<String, ProductConfiguration>)
@@ -35,22 +32,27 @@ private const val CUSTOM_PRODUCT_PROPERTIES_PATH = "idea.product.properties.path
@Suppress("SpellCheckingInspection")
fun getIdeSystemProperties(runDir: Path): Map<String, String> {
val result = LinkedHashMap<String, String>()
val properties = Properties()
properties.load(Files.newInputStream(runDir.resolve("bin/idea.properties")))
for (property in properties) {
result.put(property.key.toString(), property.value.toString())
}
// see BuildContextImpl.getAdditionalJvmArguments - we should somehow deduplicate code
val libDir = runDir.resolve("lib")
val defaultProperties: Map<String, String> = Properties().apply {
load(runDir.resolve("bin/idea.properties").bufferedReader())
}.map { it.key.toString() to it.value.toString() }.toMap()
return defaultProperties.plus(
mapOf(
result.putAll(
listOf(
"jna.boot.library.path" to "$libDir/jna/${JvmArchitecture.currentJvmArch.dirName}",
"pty4j.preferred.native.folder" to "$libDir/pty4j",
// require bundled JNA dispatcher lib
"jna.nosys" to "true",
"jna.noclasspath" to "true",
"jb.vmOptionsFile" to "${runDir.parent.listDirectoryEntries(glob = "*.vmoptions").singleOrNull()}"
))
"jb.vmOptionsFile" to "${Files.newDirectoryStream(runDir.parent, "*.vmoptions").use { it.singleOrNull() }}"
)
)
return result
}
/** Returns IDE installation directory */
@@ -80,9 +82,9 @@ private fun createConfiguration(productionClassOutput: Path, homePath: Path): Co
}
private fun getProductPropertiesPath(homePath: Path): Path {
// Handle custom product properties path
// handle a custom product properties path
val customPath = System.getProperty(CUSTOM_PRODUCT_PROPERTIES_PATH)?.let { homePath.resolve(it) }
if (customPath != null && customPath.exists()) {
if (customPath != null && Files.exists(customPath)) {
return customPath
}
return homePath.resolve(PRODUCTS_PROPERTIES_PATH)
@@ -26,9 +26,11 @@ import kotlin.io.path.name
import kotlin.io.path.nameWithoutExtension
import kotlin.time.Duration.Companion.minutes
class LinuxDistributionBuilder(override val context: BuildContext,
private val customizer: LinuxDistributionCustomizer,
private val ideaProperties: CharSequence?) : OsSpecificDistributionBuilder {
class LinuxDistributionBuilder(
override val context: BuildContext,
private val customizer: LinuxDistributionCustomizer,
private val ideaProperties: CharSequence?
) : OsSpecificDistributionBuilder {
private companion object {
const val NO_RUNTIME_SUFFIX = "-no-jbr"
}
@@ -84,12 +86,16 @@ class LinuxDistributionBuilder(override val context: BuildContext,
context.executeStep(spanBuilder("build linux .tar.gz").setAttribute("arch", arch.name), BuildOptions.LINUX_ARTIFACTS_STEP) {
if (customizer.buildArtifactWithoutRuntime) {
launch {
context.executeStep(spanBuilder("Build Linux .tar.gz without bundled Runtime").setAttribute("arch", arch.name),
BuildOptions.LINUX_TAR_GZ_WITHOUT_BUNDLED_RUNTIME_STEP) {
buildTarGz(runtimeDir = null,
unixDistPath = osAndArchSpecificDistPath,
suffix = NO_RUNTIME_SUFFIX + suffix(arch),
arch = arch)
context.executeStep(
spanBuilder("Build Linux .tar.gz without bundled Runtime").setAttribute("arch", arch.name),
BuildOptions.LINUX_TAR_GZ_WITHOUT_BUNDLED_RUNTIME_STEP
) {
buildTarGz(
runtimeDir = null,
unixDistPath = osAndArchSpecificDistPath,
suffix = NO_RUNTIME_SUFFIX + suffix(arch),
arch = arch
)
}
}
}
@@ -111,10 +117,12 @@ class LinuxDistributionBuilder(override val context: BuildContext,
val tempTar = Files.createTempDirectory(context.paths.tempDir, "tar-")
try {
unTar(tarGzPath, tempTar)
RepairUtilityBuilder.generateManifest(context = context,
unpackedDistribution = tempTar.resolve(rootDirectoryName),
os = OsFamily.LINUX,
arch = arch)
RepairUtilityBuilder.generateManifest(
context = context,
unpackedDistribution = tempTar.resolve(rootDirectoryName),
os = OsFamily.LINUX,
arch = arch
)
}
finally {
NioFiles.deleteRecursively(tempTar)
@@ -135,16 +143,19 @@ class LinuxDistributionBuilder(override val context: BuildContext,
val fullName = context.applicationInfo.fullProductName
val sourceFile = context.paths.communityHomeDir.resolve("platform/build-scripts/resources/linux/Install-Linux-tar.txt")
val targetFile = unixDistPath.resolve("Install-Linux-tar.txt")
substituteTemplatePlaceholders(sourceFile, targetFile, "@@", listOf(
substituteTemplatePlaceholders(
sourceFile, targetFile, "@@", listOf(
"product_full" to fullName,
"product" to context.productProperties.baseFileName,
"product_vendor" to context.applicationInfo.shortCompanyName,
"system_selector" to context.systemSelector
), convertToUnixLineEndings = true)
), convertToUnixLineEndings = true
)
}
override fun generateExecutableFilesPatterns(includeRuntime: Boolean, arch: JvmArchitecture): List<String> =
customizer.generateExecutableFilesPatterns(context, includeRuntime, arch)
override fun generateExecutableFilesPatterns(includeRuntime: Boolean, arch: JvmArchitecture): List<String> {
return customizer.generateExecutableFilesPatterns(context, includeRuntime, arch)
}
private val rootDirectoryName: String
get() = customizer.getRootDirectoryName(context.applicationInfo, context.buildNumber)
@@ -161,18 +172,24 @@ class LinuxDistributionBuilder(override val context: BuildContext,
check(Files.exists(runtimeDir.resolve(javaExecutablePath))) { "$javaExecutablePath was not found under $runtimeDir" }
}
val productJsonDir = context.paths.tempDir.resolve("linux.dist.product-info.json${suffix}")
generateProductJson(productJsonDir, context, arch, withRuntime = runtimeDir != null)
val productJsonDir = context.paths.tempDir.resolve("linux.dist.product-info.json$suffix")
generateProductJson(targetDir = productJsonDir, context = context, arch = arch, withRuntime = runtimeDir != null)
dirs.add(productJsonDir)
spanBuilder("build Linux tar.gz")
.setAttribute("runtimeDir", runtimeDir?.toString() ?: "")
.useWithScope {
val executableFileMatchers = generateExecutableFilesMatchers(runtimeDir != null, arch).keys
tar(tarPath, tarRoot, dirs, executableFileMatchers, context.options.buildDateInSeconds)
val executableFileMatchers = generateExecutableFilesMatchers(includeRuntime = runtimeDir != null, arch = arch).keys
tar(
archive = tarPath,
rootDir = tarRoot,
directories = dirs,
executableFileMatchers = executableFileMatchers,
buildDateInSeconds = context.options.buildDateInSeconds,
)
checkInArchive(tarPath, tarRoot, context)
context.notifyArtifactBuilt(tarPath)
checkExecutablePermissions(tarPath, rootDirectoryName, includeRuntime = runtimeDir != null, arch = arch)
checkExecutablePermissions(distribution = tarPath, root = rootDirectoryName, includeRuntime = runtimeDir != null, arch = arch)
}
tarPath
}
@@ -228,7 +245,8 @@ class LinuxDistributionBuilder(override val context: BuildContext,
)
copyFile(iconPngPath, snapDir.resolve("$snapName.png"))
val snapcraftTemplate = context.paths.communityHomeDir.resolve(
"platform/build-scripts/resources/linux/snap/snapcraft-template.yaml")
"platform/build-scripts/resources/linux/snap/snapcraft-template.yaml"
)
val snapcraftConfig = snapDir.resolve("snapcraft.yaml")
substituteTemplatePlaceholders(
inputFile = snapcraftTemplate,
@@ -243,19 +261,23 @@ class LinuxDistributionBuilder(override val context: BuildContext,
"SCRIPT" to "bin/${context.productProperties.baseFileName}.sh"
)
)
context.messages.info("""
context.messages.info(
"""
|# <${snapcraftConfig.name}>
|${Files.readString(snapcraftConfig)}
|# </${snapcraftConfig.name}>
""".trimMargin())
""".trimMargin()
)
val productJsonDir = context.paths.tempDir.resolve("linux.dist.snap.product-info.json")
val jsonText = generateProductJson(productJsonDir, context, arch)
validateProductJson(jsonText = jsonText,
relativePathToProductJson = "",
installationDirectories = listOf(context.paths.distAllDir, unixDistPath, runtimeDir),
installationArchives = listOf(),
context = context)
validateProductJson(
jsonText = jsonText,
relativePathToProductJson = "",
installationDirectories = listOf(context.paths.distAllDir, unixDistPath, runtimeDir),
installationArchives = listOf(),
context = context
)
val resultDir = snapDir.resolve("result")
Files.createDirectories(resultDir)
span.addEvent("build package")
@@ -317,17 +339,21 @@ private fun generateProductJson(targetDir: Path, context: BuildContext, arch: Jv
val json = generateProductInfoJson(
relativePathToBin = "bin",
builtinModules = context.builtinModule,
launch = listOf(ProductInfoLaunchData(
os = OsFamily.LINUX.osName,
arch = arch.dirName,
launcherPath = "bin/${context.productProperties.baseFileName}.sh",
javaExecutablePath = if (withRuntime) "jbr/bin/java" else null,
vmOptionsFilePath = "bin/${context.productProperties.baseFileName}64.vmoptions",
startupWmClass = getLinuxFrameClass(context),
bootClassPathJarNames = context.bootClassPathJarNames,
additionalJvmArguments = context.getAdditionalJvmArguments(OsFamily.LINUX, arch),
mainClass = context.ideMainClassName)),
context)
launch = listOf(
ProductInfoLaunchData(
os = OsFamily.LINUX.osName,
arch = arch.dirName,
launcherPath = "bin/${context.productProperties.baseFileName}.sh",
javaExecutablePath = if (withRuntime) "jbr/bin/java" else null,
vmOptionsFilePath = "bin/${context.productProperties.baseFileName}64.vmoptions",
startupWmClass = getLinuxFrameClass(context),
bootClassPathJarNames = context.bootClassPathJarNames,
additionalJvmArguments = context.getAdditionalJvmArguments(OsFamily.LINUX, arch),
mainClass = context.ideMainClassName,
)
),
context
)
writeProductInfoJson(targetDir.resolve(PRODUCT_INFO_FILE_NAME), json, context)
return json
}
@@ -348,10 +374,12 @@ private fun generateScripts(distBinDir: Path, arch: JvmArchitecture, context: Bu
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)
copyScript(
sourceFile = file,
targetFile = distBinDir.resolve(fileName),
additionalTemplateValues = emptyList(),
context = context
)
}
}
}
@@ -398,16 +426,20 @@ private fun generateMainScript(distBinDir: Path, arch: JvmArchitecture, addition
val sourceScriptDir = context.paths.communityHomeDir.resolve("platform/build-scripts/resources/linux/scripts")
copyScript(sourceFile = sourceScriptDir.resolve(EXECUTABLE_TEMPLATE_NAME),
targetFile = distBinDir.resolve(context.productProperties.mainScriptFileName),
additionalTemplateValues = additionalTemplateValues,
context = context)
copyScript(
sourceFile = sourceScriptDir.resolve(EXECUTABLE_TEMPLATE_NAME),
targetFile = distBinDir.resolve(context.productProperties.mainScriptFileName),
additionalTemplateValues = additionalTemplateValues,
context = context
)
}
private fun copyScript(sourceFile: Path,
targetFile: Path,
additionalTemplateValues: List<Pair<String, String>>,
context: BuildContext) {
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(
@@ -431,8 +463,10 @@ private fun writeLinuxVmOptions(distBinDir: Path, context: BuildContext): Path {
@Suppress("SpellCheckingInspection")
val vmOptions = VmOptionsGenerator.computeVmOptions(context) +
listOf("-Dsun.tools.attach.tmp.only=true",
"-Dawt.lock.fair=true")
listOf(
"-Dsun.tools.attach.tmp.only=true",
"-Dawt.lock.fair=true"
)
writeVmOptions(file = vmOptionsPath, vmOptions = vmOptions, separator = "\n")
return vmOptionsPath
@@ -1,10 +1,10 @@
// Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// 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.productInfo
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.serializer
import org.jetbrains.intellij.build.BuildContext
import org.jetbrains.intellij.build.BuiltinModulesFileData
import java.nio.file.Files
@@ -12,10 +12,10 @@ import java.nio.file.Path
import java.nio.file.attribute.FileTime
import java.util.concurrent.TimeUnit
const val PRODUCT_INFO_FILE_NAME = "product-info.json"
const val PRODUCT_INFO_FILE_NAME: String = "product-info.json"
@OptIn(ExperimentalSerializationApi::class)
internal val jsonEncoder by lazy {
internal val jsonEncoder: Json by lazy {
Json {
prettyPrint = true
prettyPrintIndent = " "
@@ -27,10 +27,12 @@ internal val jsonEncoder by lazy {
/**
* Generates product-info.json file containing meta-information about product installation.
*/
internal fun generateProductInfoJson(relativePathToBin: String,
builtinModules: BuiltinModulesFileData?,
launch: List<ProductInfoLaunchData>,
context: BuildContext): String {
internal fun generateProductInfoJson(
relativePathToBin: String,
builtinModules: BuiltinModulesFileData?,
launch: List<ProductInfoLaunchData>,
context: BuildContext,
): String {
val appInfo = context.applicationInfo
val jbrFlavors = if (launch.any { it.javaExecutablePath != null } && context.bundledRuntime.build.startsWith("21.")) {
listOf(ProductFlavorData("jbr21"))
@@ -55,7 +57,7 @@ internal fun generateProductInfoJson(relativePathToBin: String,
modules = builtinModules?.modules ?: emptyList(),
flavors = jbrFlavors + productFlavors
)
return jsonEncoder.encodeToString(serializer(), json)
return jsonEncoder.encodeToString<ProductInfoData>(json)
}
internal fun writeProductInfoJson(targetFile: Path, json: String, context: BuildContext) {
@@ -1,4 +1,4 @@
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
// 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
import com.intellij.openapi.util.SystemInfoRt
@@ -6,17 +6,15 @@ import com.intellij.util.io.Compressor
import com.intellij.util.io.Decompressor
import com.intellij.util.io.PosixFilePermissionsUtil
import java.io.InputStream
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.PathMatcher
import java.nio.file.attribute.PosixFilePermission
import java.util.concurrent.TimeUnit
import kotlin.io.path.isDirectory
fun tar(archive: Path, rootDir: String, directories: List<Path>, executableFileMatchers: Collection<PathMatcher>, buildDateInSeconds: Long) {
val normalizedRootDir = rootDir.removeSuffix("/")
FileSystemIndependentTarGzCompressor(archive) { entryName: String, fileSystemMode: Int ->
FileSystemIndependentTarGzCompressor(archive) { entryName, fileSystemMode ->
val relativePath = Path.of(entryName.removePrefix(rootDir).removePrefix("/"))
if (executableFileMatchers.any { it.matches(relativePath) } ||
PosixFilePermission.OWNER_EXECUTE in PosixFilePermissionsUtil.fromUnixMode(fileSystemMode)) {
@@ -24,21 +22,25 @@ fun tar(archive: Path, rootDir: String, directories: List<Path>, executableFileM
}
else 0
}.use { compressor ->
directories.forEach {
require(it.isDirectory())
compressor.addDirectory(normalizedRootDir, it, buildDateInSeconds)
for (dir in directories) {
require(Files.isDirectory(dir))
compressor.addDirectory(normalizedRootDir, dir, buildDateInSeconds)
}
}
}
private class FileSystemIndependentTarGzCompressor(archive: Path, val mode: (String, Int) -> Int) : Compressor.Tar(archive,
Compression.GZIP) {
override fun writeFileEntry(name: String,
source: InputStream,
length: Long,
timestamp: Long,
fileSystemMode: Int,
symlinkTarget: String?) {
private class FileSystemIndependentTarGzCompressor(
archive: Path,
@JvmField val mode: (String, Int) -> Int,
) : Compressor.Tar(archive, Compression.GZIP) {
override fun writeFileEntry(
name: String,
source: InputStream,
length: Long,
timestamp: Long,
fileSystemMode: Int,
symlinkTarget: String?,
) {
super.writeFileEntry(name, source, length, timestamp, mode(name, fileSystemMode), symlinkTarget)
}
}