mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-14 18:05:27 +07:00
Cleanup (minor optimization; obsolete API; quickfixes; typos; formatting)
GitOrigin-RevId: e66c5fe72bf30981bb564a0fd8744e439df5e5a7
This commit is contained in:
committed by
intellij-monorepo-bot
parent
3b8e9b6693
commit
07a2facf94
@@ -1,11 +1,11 @@
|
||||
// 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
|
||||
|
||||
import com.intellij.openapi.util.io.NioFiles
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.NonCancellable
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.intellij.build.impl.*
|
||||
import org.jetbrains.intellij.build.io.deleteDir
|
||||
import org.jetbrains.intellij.build.io.zipWithCompression
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
@@ -13,10 +13,12 @@ import java.nio.file.Path
|
||||
/**
|
||||
* Creates JARs containing classes required to run the external build for IDEA project without IDE.
|
||||
*/
|
||||
suspend fun buildCommunityStandaloneJpsBuilder(targetDir: Path,
|
||||
context: BuildContext,
|
||||
dryRun: Boolean = false,
|
||||
layoutCustomizer: ((BaseLayout) -> Unit) = {}) {
|
||||
suspend fun buildCommunityStandaloneJpsBuilder(
|
||||
targetDir: Path,
|
||||
context: BuildContext,
|
||||
dryRun: Boolean = false,
|
||||
layoutCustomizer: ((BaseLayout) -> Unit) = {},
|
||||
) {
|
||||
val layout = PlatformLayout()
|
||||
|
||||
layout.withModules(sequenceOf(
|
||||
@@ -121,34 +123,29 @@ suspend fun buildCommunityStandaloneJpsBuilder(targetDir: Path,
|
||||
Files.createTempDirectory(targetDir, "jps-standalone-community-")
|
||||
}
|
||||
try {
|
||||
JarPackager.pack(includedModules = layout.includedModules,
|
||||
outputDir = tempDir,
|
||||
context = context,
|
||||
layout = layout,
|
||||
platformLayout = null,
|
||||
isRootDir = false,
|
||||
isCodesignEnabled = false,
|
||||
moduleOutputPatcher = ModuleOutputPatcher(),
|
||||
dryRun = dryRun)
|
||||
JarPackager.pack(
|
||||
layout.includedModules, tempDir, isRootDir = false, isCodesignEnabled = false, layout, platformLayout = null, ModuleOutputPatcher(),
|
||||
dryRun, context = context
|
||||
)
|
||||
|
||||
val targetFile = targetDir.resolve("standalone-jps-$buildNumber.zip")
|
||||
withContext(Dispatchers.IO) {
|
||||
buildJar(targetFile = tempDir.resolve("jps-build-test-$buildNumber.jar"),
|
||||
moduleNames = listOf(
|
||||
"intellij.platform.jps.build",
|
||||
"intellij.platform.jps.model.tests",
|
||||
"intellij.platform.jps.model.serialization.tests"
|
||||
),
|
||||
context = context)
|
||||
|
||||
zipWithCompression(targetFile = targetFile, dirs = mapOf(tempDir to ""))
|
||||
buildJar(
|
||||
targetFile = tempDir.resolve("jps-build-test-$buildNumber.jar"),
|
||||
moduleNames = listOf(
|
||||
"intellij.platform.jps.build",
|
||||
"intellij.platform.jps.model.tests",
|
||||
"intellij.platform.jps.model.serialization.tests"
|
||||
),
|
||||
context)
|
||||
zipWithCompression(targetFile, dirs = mapOf(tempDir to ""))
|
||||
}
|
||||
|
||||
context.notifyArtifactBuilt(targetFile)
|
||||
}
|
||||
finally {
|
||||
withContext(Dispatchers.IO + NonCancellable) {
|
||||
deleteDir(tempDir)
|
||||
NioFiles.deleteRecursively(tempDir)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// 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.io
|
||||
|
||||
import com.intellij.openapi.util.text.Formats
|
||||
@@ -6,7 +6,6 @@ import io.opentelemetry.api.common.AttributeKey
|
||||
import io.opentelemetry.api.common.Attributes
|
||||
import io.opentelemetry.api.trace.Span
|
||||
import org.jetbrains.annotations.ApiStatus.Internal
|
||||
import java.io.IOException
|
||||
import java.nio.channels.FileChannel
|
||||
import java.nio.file.*
|
||||
import java.nio.file.attribute.BasicFileAttributes
|
||||
@@ -92,52 +91,6 @@ private class CopyDirectoryVisitor(
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteDir(startDir: Path) {
|
||||
if (!Files.exists(startDir)) {
|
||||
return
|
||||
}
|
||||
|
||||
Files.walkFileTree(startDir, object : SimpleFileVisitor<Path>() {
|
||||
override fun visitFile(file: Path, attrs: BasicFileAttributes): FileVisitResult {
|
||||
deleteFile(file)
|
||||
return FileVisitResult.CONTINUE
|
||||
}
|
||||
|
||||
override fun postVisitDirectory(dir: Path, exception: IOException?): FileVisitResult {
|
||||
if (exception != null) {
|
||||
throw exception
|
||||
}
|
||||
|
||||
Files.deleteIfExists(dir)
|
||||
return FileVisitResult.CONTINUE
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun deleteFile(file: Path) {
|
||||
// repeated delete is required for bad OS like Windows
|
||||
val maxAttemptCount = 10
|
||||
var attemptCount = 0
|
||||
while (true) {
|
||||
try {
|
||||
Files.deleteIfExists(file)
|
||||
return
|
||||
}
|
||||
catch (e: IOException) {
|
||||
if (++attemptCount == maxAttemptCount) {
|
||||
throw e
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(10)
|
||||
}
|
||||
catch (_: InterruptedException) {
|
||||
throw e
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun substituteTemplatePlaceholders(
|
||||
inputFile: Path,
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
@file:Suppress("ReplacePutWithAssignment", "ReplaceGetOrSet")
|
||||
|
||||
// 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.io
|
||||
|
||||
import com.fasterxml.jackson.jr.ob.JSON
|
||||
@@ -8,17 +6,14 @@ import com.intellij.openapi.util.io.FileUtilRt
|
||||
import io.opentelemetry.api.common.AttributeKey
|
||||
import io.opentelemetry.api.trace.Span
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.channels.ClosedSendChannelException
|
||||
import kotlinx.coroutines.channels.toList
|
||||
import org.jetbrains.annotations.ApiStatus.Obsolete
|
||||
import org.jetbrains.intellij.build.telemetry.TraceManager.spanBuilder
|
||||
import org.jetbrains.intellij.build.telemetry.use
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import java.nio.charset.MalformedInputException
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.util.*
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
import kotlin.time.Duration.Companion.minutes
|
||||
@@ -55,11 +50,7 @@ suspend fun runJava(mainClass: String,
|
||||
try {
|
||||
val classpathFile = Files.createTempFile("classpath-", ".txt").also(toDelete::add)
|
||||
val classPathStringBuilder = createClassPathFile(classPath, classpathFile)
|
||||
val processArgs = createProcessArgs(javaExe = javaExe,
|
||||
jvmArgs = jvmArgs,
|
||||
classpathFile = classpathFile,
|
||||
mainClass = mainClass,
|
||||
args = args)
|
||||
val processArgs = createProcessArgs(javaExe, jvmArgs, classpathFile, mainClass, args)
|
||||
span.setAttribute(AttributeKey.stringArrayKey("processArgs"), processArgs)
|
||||
val errorOutputFile = Files.createTempFile("error-out-", ".txt").also(toDelete::add)
|
||||
val outputFile = customOutputFile?.also { customOutputFile.parent?.let { Files.createDirectories(it) } }
|
||||
@@ -79,9 +70,10 @@ suspend fun runJava(mainClass: String,
|
||||
span.setAttribute("output", runCatching { Files.readString(outputFile) }.getOrNull() ?: "output file doesn't exist")
|
||||
val errorOutput = runCatching { Files.readString(errorOutputFile) }.getOrNull()
|
||||
val output = runCatching { Files.readString(outputFile) }.getOrNull()
|
||||
val errorMessage = StringBuilder("Cannot execute $mainClass: $reason\n${processArgs.joinToString(separator = " ")}" +
|
||||
"\n--- error output ---\n" +
|
||||
"$errorOutput")
|
||||
val errorMessage = StringBuilder(
|
||||
"Cannot execute $mainClass: $reason\n${processArgs.joinToString(separator = " ")}" +
|
||||
"\n--- error output ---\n" +
|
||||
"$errorOutput")
|
||||
if (!useJsonOutput) {
|
||||
errorMessage.append("\n--- output ---\n$output\n")
|
||||
}
|
||||
@@ -147,8 +139,8 @@ private fun checkOutput(outputFile: Path, span: Span, errorConsumer: (String) ->
|
||||
.forEach { line ->
|
||||
if (line.startsWith('{')) {
|
||||
val item = JSON.std.mapFrom(line)
|
||||
val message = (item.get("message") as? String) ?: error("Missing field: 'message' in $line")
|
||||
val level = (item.get("level") as? String) ?: error("Missing field: 'level' in $line")
|
||||
val message = (item["message"] as? String) ?: error("Missing field: 'message' in $line")
|
||||
val level = (item["level"] as? String) ?: error("Missing field: 'level' in $line")
|
||||
messages.append(message).append('\n')
|
||||
if (level == "SEVERE") {
|
||||
errorConsumer("Error reported from child process logger: $message")
|
||||
@@ -182,7 +174,8 @@ private fun createClassPathFile(classPath: Collection<String>, classpathFile: Pa
|
||||
classPathStringBuilder.append("-classpath").append('\n')
|
||||
for (s in classPath) {
|
||||
appendArg(s, classPathStringBuilder)
|
||||
classPathStringBuilder.append(File.pathSeparator)
|
||||
@Suppress("IO_FILE_USAGE")
|
||||
classPathStringBuilder.append(java.io.File.pathSeparator)
|
||||
}
|
||||
classPathStringBuilder.setLength(classPathStringBuilder.length - 1)
|
||||
Files.writeString(classpathFile, classPathStringBuilder)
|
||||
@@ -193,13 +186,7 @@ private fun createClassPathFile(classPath: Collection<String>, classpathFile: Pa
|
||||
@Obsolete
|
||||
fun runProcessBlocking(args: List<String>, workingDir: Path? = null, timeoutMillis: Long = DEFAULT_TIMEOUT.inWholeMilliseconds) {
|
||||
runBlocking {
|
||||
runProcess(
|
||||
args = args,
|
||||
workingDir = workingDir,
|
||||
timeout = timeoutMillis.milliseconds,
|
||||
additionalEnvVariables = emptyMap(),
|
||||
inheritOut = false,
|
||||
)
|
||||
runProcess(args, workingDir, timeoutMillis.milliseconds)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,7 +222,7 @@ suspend fun runProcess(
|
||||
builder.redirectErrorStream(inheritErrToOut)
|
||||
}
|
||||
}.start()
|
||||
val outputChannel = Channel<String>(capacity = Channel.UNLIMITED)
|
||||
val outputLines = Collections.synchronizedList(ArrayList<String>())
|
||||
if (!inheritOut) {
|
||||
launch(Dispatchers.Default) {
|
||||
withTimeout(timeout) {
|
||||
@@ -243,11 +230,7 @@ suspend fun runProcess(
|
||||
span.addEvent(it)
|
||||
stdOutConsumer(it)
|
||||
if (attachStdOutToException) {
|
||||
try {
|
||||
outputChannel.send(it)
|
||||
}
|
||||
catch (_: ClosedSendChannelException) {
|
||||
}
|
||||
outputLines += it
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -257,11 +240,7 @@ suspend fun runProcess(
|
||||
process.errorStream.consume(process) {
|
||||
span.addEvent(it)
|
||||
stdErrConsumer(it)
|
||||
try {
|
||||
outputChannel.send(it)
|
||||
}
|
||||
catch (_: ClosedSendChannelException) {
|
||||
}
|
||||
outputLines += it
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -279,16 +258,13 @@ suspend fun runProcess(
|
||||
}
|
||||
catch (e: TimeoutCancellationException) {
|
||||
throw e.apply {
|
||||
addSuppressed(RuntimeException("Process '$commandLine' (pid=$pid) failed to complete in $timeout" + toLines(outputChannel)))
|
||||
addSuppressed(RuntimeException("Process '$commandLine' (pid=$pid) failed to complete in $timeout" + merge(outputLines)))
|
||||
}
|
||||
}
|
||||
finally {
|
||||
outputChannel.close()
|
||||
}
|
||||
|
||||
val exitCode = process.exitValue()
|
||||
if (exitCode != 0) {
|
||||
throw RuntimeException("Process '$commandLine' (pid=$pid) finished with exitCode $exitCode" + toLines(outputChannel))
|
||||
throw RuntimeException("Process '$commandLine' (pid=$pid) finished with exitCode $exitCode" + merge(outputLines))
|
||||
}
|
||||
}
|
||||
finally {
|
||||
@@ -349,13 +325,6 @@ private suspend fun InputStream.consume(process: Process, consume: suspend (line
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun toLines(channel: Channel<String>): String {
|
||||
channel.close()
|
||||
val lines = channel.toList()
|
||||
return if (lines.any()) {
|
||||
lines.joinToString(prefix = ":\n", separator = "\n")
|
||||
}
|
||||
else {
|
||||
""
|
||||
}
|
||||
}
|
||||
private fun merge(lines: List<String>): String = synchronized(lines) {
|
||||
if (lines.any()) lines.joinToString(prefix = ":\n", separator = "\n") else ""
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// 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
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus.Internal
|
||||
@@ -39,6 +39,5 @@ interface ApplicationInfoProperties {
|
||||
* another product, to get the instance of the product currently being build, use [BuildContext.applicationInfo] instead.
|
||||
*/
|
||||
@Internal
|
||||
fun BuildContext.loadApplicationInfoPropertiesForProduct(productProperties: ProductProperties): ApplicationInfoProperties {
|
||||
return ApplicationInfoPropertiesImpl(project, productProperties, options)
|
||||
}
|
||||
fun BuildContext.loadApplicationInfoPropertiesForProduct(productProperties: ProductProperties): ApplicationInfoProperties =
|
||||
ApplicationInfoPropertiesImpl(project, productProperties, options)
|
||||
|
||||
@@ -358,25 +358,23 @@ data class BuildOptions(
|
||||
var useLocalLauncher: Boolean = false
|
||||
|
||||
/**
|
||||
* When `true`, cross-platform distribution will be packed using zip64 in AlwaysWithCompatibility mode
|
||||
* When `true`, cross-platform distribution will be packed using zip64 in AlwaysWithCompatibility mode.
|
||||
*/
|
||||
var useZip64ForCrossPlatformDistribution: Boolean = getBooleanProperty("intellij.build.cross.platform.dist.zip64", false)
|
||||
|
||||
/**
|
||||
* Pass `true` to this system property to produce .snap packages.
|
||||
* Requires Docker.
|
||||
* Pass `true` to this system property to produce .snap packages. Requires Docker.
|
||||
*/
|
||||
var buildUnixSnaps: Boolean = getBooleanProperty("intellij.build.unix.snaps", false)
|
||||
|
||||
/**
|
||||
* Docker image for snap package creation
|
||||
* Docker image for snap package creation.
|
||||
*/
|
||||
var snapDockerImage: String = System.getProperty("intellij.build.snap.docker.image") ?: DEPENDENCIES_PROPERTIES["snapDockerImage"]
|
||||
var snapDockerBuildTimeoutMin: Long = System.getProperty("intellij.build.snap.timeoutMin")?.toLong() ?: 20
|
||||
|
||||
/**
|
||||
* When `true`, `.resx` files are generated and bundled in the localization plugins.
|
||||
* Requires Docker.
|
||||
* When `true`, `.resx` files are generated and bundled in the localization plugins. Requires Docker.
|
||||
*/
|
||||
var bundleLocalizationPluginResources: Boolean = getBooleanProperty("intellij.build.localization.plugin.resources", false)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// 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
|
||||
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
@@ -20,25 +20,25 @@ open class WindowsDistributionCustomizer {
|
||||
/**
|
||||
* If `true`, *.bat files (productName.bat and inspect.bat) will be included in the distribution.
|
||||
*/
|
||||
var includeBatchLaunchers = true
|
||||
var includeBatchLaunchers: Boolean = true
|
||||
|
||||
/**
|
||||
* If `true`, build a ZIP archive with JetBrains Runtime.
|
||||
*/
|
||||
var buildZipArchiveWithBundledJre = true
|
||||
var buildZipArchiveWithBundledJre: Boolean = true
|
||||
|
||||
/**
|
||||
* If `true`, build a ZIP archive without JetBrains Runtime.
|
||||
*/
|
||||
var buildZipArchiveWithoutBundledJre = false
|
||||
var buildZipArchiveWithoutBundledJre: Boolean = false
|
||||
|
||||
var zipArchiveWithBundledJreSuffix = ".win"
|
||||
var zipArchiveWithoutBundledJreSuffix = "-no-jbr.win"
|
||||
var zipArchiveWithBundledJreSuffix: String = ".win"
|
||||
var zipArchiveWithoutBundledJreSuffix: String = "-no-jbr.win"
|
||||
|
||||
/**
|
||||
* If `true`, Windows Installer will associate *.ipr files with the IDE in Registry.
|
||||
*/
|
||||
var associateIpr = true
|
||||
var associateIpr: Boolean = true
|
||||
|
||||
/**
|
||||
* Path to a directory containing images for installer: `logo.bmp`, `headerlogo.bmp`, `install.ico`, `uninstall.ico`.
|
||||
@@ -65,9 +65,8 @@ open class WindowsDistributionCustomizer {
|
||||
/**
|
||||
* Name of the Windows installation directory and Desktop shortcut.
|
||||
*/
|
||||
open fun getNameForInstallDirAndDesktopShortcut(appInfo: ApplicationInfoProperties, buildNumber: String): String {
|
||||
return "${getFullNameIncludingEdition(appInfo)} ${if (appInfo.isEAP) buildNumber else appInfo.fullVersion}"
|
||||
}
|
||||
open fun getNameForInstallDirAndDesktopShortcut(appInfo: ApplicationInfoProperties, buildNumber: String): String =
|
||||
"${getFullNameIncludingEdition(appInfo)} ${if (appInfo.isEAP) buildNumber else appInfo.fullVersion}"
|
||||
|
||||
/**
|
||||
* Override this method to copy additional files to the Windows distribution of the product.
|
||||
@@ -84,9 +83,8 @@ open class WindowsDistributionCustomizer {
|
||||
/**
|
||||
* The returned name will be used to create links on Desktop.
|
||||
*/
|
||||
open fun getFullNameIncludingEditionAndVendor(appInfo: ApplicationInfoProperties): String {
|
||||
return appInfo.shortCompanyName + ' ' + getFullNameIncludingEdition(appInfo)
|
||||
}
|
||||
open fun getFullNameIncludingEditionAndVendor(appInfo: ApplicationInfoProperties): String =
|
||||
appInfo.shortCompanyName + ' ' + getFullNameIncludingEdition(appInfo)
|
||||
|
||||
open fun getUninstallFeedbackPageUrl(appInfo: ApplicationInfoProperties): String? = null
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
@file:Suppress("ReplaceGetOrSet")
|
||||
|
||||
package org.jetbrains.intellij.build.impl
|
||||
|
||||
import com.fasterxml.jackson.jr.ob.JSON
|
||||
@@ -145,27 +143,14 @@ internal suspend fun buildDistribution(
|
||||
|
||||
val buildNonBundledPlugins = async(CoroutineName("build non-bundled plugins")) {
|
||||
val compressPluginArchive = !isUpdateFromSources && context.options.compressZipFiles
|
||||
buildNonBundledPlugins(
|
||||
pluginsToPublish = state.pluginsToPublish,
|
||||
compressPluginArchive = compressPluginArchive,
|
||||
buildPlatformLibJob = buildPlatformJob,
|
||||
state = state,
|
||||
searchableOptionSet = searchableOptionSet,
|
||||
context = context,
|
||||
)
|
||||
buildNonBundledPlugins(state.pluginsToPublish, compressPluginArchive, buildPlatformJob, state, searchableOptionSet, context)
|
||||
}
|
||||
|
||||
val bundledPluginItems = buildBundledPluginsForAllPlatforms(
|
||||
state = state,
|
||||
pluginLayouts = pluginLayouts,
|
||||
isUpdateFromSources = isUpdateFromSources,
|
||||
buildPlatformJob = buildPlatformJob,
|
||||
searchableOptionSetDescriptor = searchableOptionSet,
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
context = context,
|
||||
state, pluginLayouts, isUpdateFromSources, buildPlatformJob, searchableOptionSet, moduleOutputPatcher, context
|
||||
)
|
||||
|
||||
ContentReport(platform = buildPlatformJob.await(), bundledPlugins = bundledPluginItems, nonBundledPlugins = buildNonBundledPlugins.await())
|
||||
ContentReport(buildPlatformJob.await(), bundledPluginItems, buildNonBundledPlugins.await())
|
||||
}
|
||||
|
||||
coroutineScope {
|
||||
@@ -202,45 +187,25 @@ private suspend fun buildBundledPluginsForAllPlatforms(
|
||||
): List<Pair<PluginBuildDescriptor, List<DistributionFileEntry>>> = coroutineScope {
|
||||
val commonDeferred = async(CoroutineName("build bundled plugins")) {
|
||||
doBuildBundledPlugins(
|
||||
state = state,
|
||||
plugins = pluginLayouts,
|
||||
isUpdateFromSources = isUpdateFromSources,
|
||||
buildPlatformJob = buildPlatformJob,
|
||||
searchableOptionSet = searchableOptionSetDescriptor,
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
context = context,
|
||||
state, pluginLayouts, isUpdateFromSources, buildPlatformJob, searchableOptionSetDescriptor, moduleOutputPatcher, context
|
||||
)
|
||||
}
|
||||
|
||||
val additionalDeferred = async(CoroutineName("build additional plugins")) {
|
||||
copyAdditionalPlugins(context = context, pluginDir = context.paths.distAllDir.resolve(PLUGINS_DIRECTORY))
|
||||
copyAdditionalPlugins(context, pluginDir = context.paths.distAllDir.resolve(PLUGINS_DIRECTORY))
|
||||
}
|
||||
|
||||
val pluginDirs = getPluginDirs(context, isUpdateFromSources)
|
||||
val specificDeferred = async(CoroutineName("build OS-specific bundled plugins")) {
|
||||
buildOsSpecificBundledPlugins(
|
||||
state = state,
|
||||
plugins = pluginLayouts,
|
||||
isUpdateFromSources = isUpdateFromSources,
|
||||
buildPlatformJob = buildPlatformJob,
|
||||
context = context,
|
||||
searchableOptionSet = searchableOptionSetDescriptor,
|
||||
pluginDirs = pluginDirs,
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
state, pluginLayouts, isUpdateFromSources, buildPlatformJob, context, searchableOptionSetDescriptor, pluginDirs, moduleOutputPatcher
|
||||
)
|
||||
}
|
||||
|
||||
val common = commonDeferred.await()
|
||||
val specific = specificDeferred.await()
|
||||
buildPlatformJob.join()
|
||||
writePluginInfo(
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
pluginDirs = pluginDirs,
|
||||
common = common,
|
||||
specific = specific,
|
||||
additional = additionalDeferred.await(),
|
||||
context = context,
|
||||
)
|
||||
writePluginInfo(moduleOutputPatcher, pluginDirs, common, specific, additionalDeferred.await(), context)
|
||||
common + specific.values.flatten()
|
||||
}
|
||||
|
||||
@@ -252,23 +217,23 @@ private fun writePluginInfo(
|
||||
additional: List<Pair<Path, List<Path>>>?,
|
||||
context: BuildContext,
|
||||
) {
|
||||
val commonClassPath = generatePluginClassPath(pluginEntries = common, moduleOutputPatcher = moduleOutputPatcher)
|
||||
val commonClassPath = generatePluginClassPath(pluginEntries = common, moduleOutputPatcher)
|
||||
val additionalClassPath = additional?.let { generatePluginClassPathFromPrebuiltPluginFiles(it) }
|
||||
|
||||
for ((supportedDist) in pluginDirs) {
|
||||
val specificList = specific.get(supportedDist)
|
||||
val specificClasspath = specificList?.let { generatePluginClassPath(pluginEntries = it, moduleOutputPatcher = moduleOutputPatcher) }
|
||||
val specificList = specific[supportedDist]
|
||||
val specificClasspath = specificList?.let { generatePluginClassPath(pluginEntries = it, moduleOutputPatcher) }
|
||||
|
||||
val byteOut = ByteArrayOutputStream()
|
||||
val out = DataOutputStream(byteOut)
|
||||
val pluginCount = common.size + (additional?.size ?: 0) + (specificList?.size ?: 0)
|
||||
writePluginClassPathHeader(out = out, isJarOnly = true, pluginCount = pluginCount, moduleOutputPatcher = moduleOutputPatcher, context = context)
|
||||
writePluginClassPathHeader(out, isJarOnly = true, pluginCount, moduleOutputPatcher, context)
|
||||
out.write(commonClassPath)
|
||||
additionalClassPath?.let { out.write(it) }
|
||||
specificClasspath?.let { out.write(it) }
|
||||
out.close()
|
||||
|
||||
context.addDistFile(DistFile(content = InMemoryDistFileContent(byteOut.toByteArray()), relativePath = PLUGIN_CLASSPATH, os = supportedDist.os, arch = supportedDist.arch, libcImpl = supportedDist.libcImpl))
|
||||
context.addDistFile(DistFile(InMemoryDistFileContent(byteOut.toByteArray()), PLUGIN_CLASSPATH, supportedDist.os, supportedDist.libcImpl, supportedDist.arch))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,16 +246,15 @@ fun validateModuleStructure(platform: PlatformLayout, context: BuildContext) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPluginDirs(context: BuildContext, isUpdateFromSources: Boolean): List<Pair<SupportedDistribution, Path>> {
|
||||
private fun getPluginDirs(context: BuildContext, isUpdateFromSources: Boolean): List<Pair<SupportedDistribution, Path>> =
|
||||
if (isUpdateFromSources) {
|
||||
return listOf(SupportedDistribution(OsFamily.currentOs, JvmArchitecture.currentJvmArch, LibcImpl.current(OsFamily.currentOs)) to context.paths.distAllDir.resolve(PLUGINS_DIRECTORY))
|
||||
listOf(SupportedDistribution(OsFamily.currentOs, JvmArchitecture.currentJvmArch, LibcImpl.current(OsFamily.currentOs)) to context.paths.distAllDir.resolve(PLUGINS_DIRECTORY))
|
||||
}
|
||||
else {
|
||||
return SUPPORTED_DISTRIBUTIONS.map {
|
||||
SUPPORTED_DISTRIBUTIONS.map {
|
||||
it to getOsAndArchSpecificDistDirectory(it.os, it.arch, it.libcImpl, context).resolve(PLUGINS_DIRECTORY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun buildBundledPlugins(
|
||||
state: DistributionBuilderState,
|
||||
@@ -299,13 +263,7 @@ suspend fun buildBundledPlugins(
|
||||
context: BuildContext,
|
||||
) {
|
||||
doBuildBundledPlugins(
|
||||
state = state,
|
||||
plugins = plugins,
|
||||
isUpdateFromSources = false,
|
||||
buildPlatformJob = null,
|
||||
searchableOptionSet = searchableOptionSetDescriptor,
|
||||
moduleOutputPatcher = ModuleOutputPatcher(),
|
||||
context = context,
|
||||
state, plugins, isUpdateFromSources = false, buildPlatformJob = null, searchableOptionSetDescriptor, ModuleOutputPatcher(), context
|
||||
)
|
||||
}
|
||||
|
||||
@@ -324,7 +282,7 @@ private suspend fun doBuildBundledPlugins(
|
||||
.setAttribute("count", plugins.size.toLong())
|
||||
.block { span ->
|
||||
val pluginsToBundle = ArrayList<PluginLayout>(plugins.size)
|
||||
plugins.filterTo(pluginsToBundle) { satisfiesBundlingRequirements(plugin = it, osFamily = null, arch = null, context = context) }
|
||||
plugins.filterTo(pluginsToBundle) { satisfiesBundlingRequirements(plugin = it, osFamily = null, arch = null, context) }
|
||||
span.setAttribute("satisfiableCount", pluginsToBundle.size.toLong())
|
||||
|
||||
// doesn't make sense to require passing here a list with a stable order (unnecessary complication, sorting by main module is enough)
|
||||
@@ -332,23 +290,15 @@ private suspend fun doBuildBundledPlugins(
|
||||
val targetDir = context.paths.distAllDir.resolve(PLUGINS_DIRECTORY)
|
||||
val platformSpecificPluginDirs = getPluginDirs(context, isUpdateFromSources)
|
||||
val entries = buildPlugins(
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
plugins = pluginsToBundle,
|
||||
os = null,
|
||||
targetDir = targetDir,
|
||||
state = state,
|
||||
context = context,
|
||||
buildPlatformJob = buildPlatformJob,
|
||||
searchableOptionSet = searchableOptionSet,
|
||||
pluginBuilt = { layout, pluginDirOrFile ->
|
||||
if (layout.hasPlatformSpecificResources) {
|
||||
buildPlatformSpecificPluginResources(plugin = layout, targetDirs = platformSpecificPluginDirs, context = context)
|
||||
}
|
||||
else {
|
||||
emptyList()
|
||||
}
|
||||
moduleOutputPatcher, pluginsToBundle, os = null, targetDir, state, context, buildPlatformJob, searchableOptionSet
|
||||
) { layout, _ ->
|
||||
if (layout.hasPlatformSpecificResources) {
|
||||
buildPlatformSpecificPluginResources(layout, platformSpecificPluginDirs, context)
|
||||
}
|
||||
)
|
||||
else {
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
entries
|
||||
}
|
||||
@@ -375,7 +325,7 @@ private suspend fun buildOsSpecificBundledPlugins(
|
||||
}
|
||||
|
||||
val osSpecificPlugins = plugins.filter {
|
||||
satisfiesBundlingRequirements(plugin = it, osFamily = os, arch = arch, context = context)
|
||||
satisfiesBundlingRequirements(it, os, arch, context)
|
||||
}
|
||||
if (osSpecificPlugins.isEmpty()) {
|
||||
return@mapNotNull null
|
||||
@@ -388,16 +338,7 @@ private suspend fun buildOsSpecificBundledPlugins(
|
||||
.setAttribute("count", osSpecificPlugins.size.toLong())
|
||||
.setAttribute("outDir", targetDir.toString())
|
||||
.use {
|
||||
buildPlugins(
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
plugins = osSpecificPlugins,
|
||||
os = os,
|
||||
targetDir = targetDir,
|
||||
state = state,
|
||||
context = context,
|
||||
buildPlatformJob = buildPlatformJob,
|
||||
searchableOptionSet = searchableOptionSet,
|
||||
)
|
||||
buildPlugins(moduleOutputPatcher, osSpecificPlugins, os, targetDir, state, context, buildPlatformJob, searchableOptionSet)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -460,14 +401,7 @@ internal suspend fun buildNonBundledPlugins(
|
||||
!context.isStepSkipped(BuildOptions.ARCHIVE_PLUGINS)
|
||||
val plugins = pluginsToPublish.sortedWith(PLUGIN_LAYOUT_COMPARATOR_BY_MAIN_MODULE)
|
||||
val mappings = buildPlugins(
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
plugins = plugins,
|
||||
os = null,
|
||||
targetDir = stageDir,
|
||||
state = state,
|
||||
context = context,
|
||||
buildPlatformJob = buildPlatformLibJob,
|
||||
searchableOptionSet = searchableOptionSet,
|
||||
moduleOutputPatcher, plugins, os = null, stageDir, state, context, buildPlatformLibJob, searchableOptionSet
|
||||
) { plugin, pluginDirOrFile ->
|
||||
val pluginVersion = if (plugin.mainModule == BUILT_IN_HELP_MODULE_NAME) {
|
||||
context.buildNumber
|
||||
@@ -489,23 +423,17 @@ internal suspend fun buildNonBundledPlugins(
|
||||
val destFile = targetDirectory.resolve("${plugin.directoryName}-$pluginVersion.zip")
|
||||
val pluginXml = moduleOutputPatcher.getPatchedPluginXml(plugin.mainModule)
|
||||
pluginSpecs.add(PluginRepositorySpec(destFile, pluginXml))
|
||||
dirToJar.add(NonBundledPlugin(sourceDir = pluginDirOrFile, targetZip = destFile, optimizedZip = !plugin.enableSymlinksAndExecutableResources))
|
||||
dirToJar.add(NonBundledPlugin(pluginDirOrFile, destFile, !plugin.enableSymlinksAndExecutableResources))
|
||||
|
||||
emptyList()
|
||||
}
|
||||
|
||||
archivePlugins(items = dirToJar, compress = compressPluginArchive, withBlockMap = compressPluginArchive, context = context)
|
||||
archivePlugins(dirToJar, compressPluginArchive, compressPluginArchive, context)
|
||||
|
||||
val helpPlugin = buildHelpPlugin(pluginVersion = context.pluginBuildNumber, context = context)
|
||||
val helpPlugin = buildHelpPlugin(context.pluginBuildNumber, context)
|
||||
if (helpPlugin != null) {
|
||||
val spec = buildHelpPlugin(
|
||||
helpPlugin = helpPlugin,
|
||||
pluginsToPublishDir = stageDir,
|
||||
targetDir = context.nonBundledPluginsToBePublished,
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
state = state,
|
||||
searchableOptionSetDescriptor = searchableOptionSet,
|
||||
context = context,
|
||||
helpPlugin, stageDir, context.nonBundledPluginsToBePublished, moduleOutputPatcher, state, searchableOptionSet, context
|
||||
)
|
||||
pluginSpecs.add(spec)
|
||||
}
|
||||
@@ -598,12 +526,7 @@ internal suspend fun generateProjectStructureMapping(platformLayout: PlatformLay
|
||||
val moduleOutputPatcher = ModuleOutputPatcher()
|
||||
val libDirLayout = async(CoroutineName("layout platform distribution")) {
|
||||
layoutPlatformDistribution(
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
targetDirectory = context.paths.distAllDir,
|
||||
platform = platformLayout,
|
||||
searchableOptionSet = null,
|
||||
copyFiles = false,
|
||||
context = context,
|
||||
moduleOutputPatcher, context.paths.distAllDir, platform = platformLayout, searchableOptionSet = null, copyFiles = false, context
|
||||
)
|
||||
}
|
||||
|
||||
@@ -616,14 +539,7 @@ internal suspend fun generateProjectStructureMapping(platformLayout: PlatformLay
|
||||
if (satisfiesBundlingRequirements(plugin, osFamily = null, arch = null, context)) {
|
||||
val targetDirectory = context.paths.distAllDir.resolve(PLUGINS_DIRECTORY).resolve(plugin.directoryName)
|
||||
entries.add(PluginBuildDescriptor(targetDirectory, os = null, plugin, moduleNames = emptyList()) to layoutDistribution(
|
||||
layout = plugin,
|
||||
platformLayout = platformLayout,
|
||||
targetDirectory = targetDirectory,
|
||||
copyFiles = false,
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
includedModules = plugin.includedModules,
|
||||
searchableOptionSet = null,
|
||||
context = context,
|
||||
plugin, platformLayout, targetDirectory, copyFiles = false, moduleOutputPatcher, plugin.includedModules, searchableOptionSet = null, context
|
||||
).first)
|
||||
}
|
||||
}
|
||||
@@ -652,16 +568,10 @@ internal suspend fun buildPlugins(
|
||||
val entries = coroutineScope {
|
||||
plugins.map { plugin ->
|
||||
if (plugin.mainModule != BUILT_IN_HELP_MODULE_NAME) {
|
||||
checkOutputOfPluginModules(mainPluginModule = plugin.mainModule, includedModules = plugin.includedModules, moduleExcludes = plugin.moduleExcludes, context = context)
|
||||
checkOutputOfPluginModules(plugin.mainModule, plugin.includedModules, plugin.moduleExcludes, context)
|
||||
patchPluginXml(
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
plugin = plugin,
|
||||
releaseDate = context.applicationInfo.majorReleaseDate,
|
||||
releaseVersion = context.applicationInfo.releaseVersionForLicensing,
|
||||
pluginsToPublish = state.pluginsToPublish,
|
||||
helper = (context as BuildContextImpl).jarPackagerDependencyHelper,
|
||||
platformLayout = state.platform,
|
||||
context = context,
|
||||
moduleOutputPatcher, plugin, context.applicationInfo.majorReleaseDate, context.applicationInfo.releaseVersionForLicensing, state.pluginsToPublish,
|
||||
(context as BuildContextImpl).jarPackagerDependencyHelper, state.platform, context
|
||||
)
|
||||
}
|
||||
|
||||
@@ -670,14 +580,7 @@ internal suspend fun buildPlugins(
|
||||
val task = async(CoroutineName("Build plugin (module=${plugin.mainModule})")) {
|
||||
spanBuilder("plugin").setAttribute("path", context.paths.buildOutputDir.relativize(pluginDir).toString()).use {
|
||||
val (entries, file) = layoutDistribution(
|
||||
layout = plugin,
|
||||
platformLayout = state.platform,
|
||||
targetDirectory = pluginDir,
|
||||
copyFiles = true,
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
includedModules = plugin.includedModules,
|
||||
searchableOptionSet = searchableOptionSet,
|
||||
context = context,
|
||||
plugin, state.platform, pluginDir, copyFiles = true, moduleOutputPatcher, plugin.includedModules, searchableOptionSet, context
|
||||
)
|
||||
|
||||
if (pluginBuilt == null) {
|
||||
@@ -762,9 +665,8 @@ fun getPluginLayoutsByJpsModuleNames(modules: Collection<String>, productLayout:
|
||||
return result
|
||||
}
|
||||
|
||||
private fun basePath(buildContext: BuildContext, moduleName: String): Path {
|
||||
return Path.of(JpsPathUtil.urlToPath(buildContext.findRequiredModule(moduleName).contentRootsList.urls.first()))
|
||||
}
|
||||
private fun basePath(buildContext: BuildContext, moduleName: String): Path =
|
||||
Path.of(JpsPathUtil.urlToPath(buildContext.findRequiredModule(moduleName).contentRootsList.urls.first()))
|
||||
|
||||
suspend fun buildLib(
|
||||
moduleOutputPatcher: ModuleOutputPatcher,
|
||||
@@ -774,12 +676,7 @@ suspend fun buildLib(
|
||||
): List<DistributionFileEntry> {
|
||||
val targetDirectory = context.paths.distAllDir
|
||||
val libDirMappings = layoutPlatformDistribution(
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
targetDirectory = targetDirectory,
|
||||
platform = platform,
|
||||
searchableOptionSet = searchableOptionSetDescriptor,
|
||||
copyFiles = true,
|
||||
context = context,
|
||||
moduleOutputPatcher, targetDirectory, platform, searchableOptionSetDescriptor, copyFiles = true, context
|
||||
)
|
||||
context.proprietaryBuildTools.scrambleTool?.validatePlatformLayout(platform.includedModules, context)
|
||||
return libDirMappings
|
||||
@@ -804,8 +701,9 @@ suspend fun layoutPlatformDistribution(
|
||||
val moduleName = "intellij.platform.core"
|
||||
val module = context.findRequiredModule(moduleName)
|
||||
val relativePath = "com/intellij/openapi/application/ApplicationNamesInfo.class"
|
||||
val result = injectAppInfo(inFileBytes = context.readFileContentFromModuleOutput(module, relativePath) ?: error("app info not found"), newFieldValue = context.appInfoXml)
|
||||
moduleOutputPatcher.patchModuleOutput(moduleName, relativePath, result)
|
||||
val sourceBytes = context.readFileContentFromModuleOutput(module, relativePath) ?: error("app info not found")
|
||||
val patchedBytes = injectAppInfo(inFileBytes = sourceBytes, newFieldValue = context.appInfoXml)
|
||||
moduleOutputPatcher.patchModuleOutput(moduleName, relativePath, patchedBytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -825,7 +723,7 @@ private suspend fun patchKeyMapWithAltClickReassignedToMultipleCarets(moduleOutp
|
||||
}
|
||||
|
||||
val moduleName = "intellij.platform.resources"
|
||||
val relativePath = "keymaps/\$default.xml"
|
||||
val relativePath = $$"keymaps/$default.xml"
|
||||
val sourceFileContent = context.readFileContentFromModuleOutput(context.findRequiredModule(moduleName), relativePath)
|
||||
?: error("Not found '$relativePath' in module $moduleName output")
|
||||
var text = String(sourceFileContent, StandardCharsets.UTF_8)
|
||||
@@ -835,9 +733,8 @@ private suspend fun patchKeyMapWithAltClickReassignedToMultipleCarets(moduleOutp
|
||||
moduleOutputPatcher.patchModuleOutput(moduleName, relativePath, text)
|
||||
}
|
||||
|
||||
fun getOsAndArchSpecificDistDirectory(osFamily: OsFamily, arch: JvmArchitecture, libc: LibcImpl, context: BuildContext): Path {
|
||||
return context.paths.buildOutputDir.resolve("dist.${osFamily.distSuffix}.${arch.name}${if (libc == LinuxLibcImpl.MUSL) { "-musl" } else {""} }")
|
||||
}
|
||||
fun getOsAndArchSpecificDistDirectory(osFamily: OsFamily, arch: JvmArchitecture, libc: LibcImpl, context: BuildContext): Path =
|
||||
context.paths.buildOutputDir.resolve("dist.${osFamily.distSuffix}.${arch.name}${if (libc == LinuxLibcImpl.MUSL) { "-musl" } else {""} }")
|
||||
|
||||
private suspend fun checkOutputOfPluginModules(
|
||||
mainPluginModule: String,
|
||||
@@ -846,13 +743,10 @@ private suspend fun checkOutputOfPluginModules(
|
||||
context: BuildContext,
|
||||
) {
|
||||
for (module in includedModules.asSequence().map { it.moduleName }.distinct()) {
|
||||
if (module == "intellij.java.guiForms.rt" ||
|
||||
!containsFileInOutput(
|
||||
moduleName = module,
|
||||
filePath = "com/intellij/uiDesigner/core/GridLayoutManager.class",
|
||||
excludes = moduleExcludes[module] ?: emptyList(),
|
||||
context,
|
||||
)) {
|
||||
if (
|
||||
module == "intellij.java.guiForms.rt" ||
|
||||
!containsFileInOutput(module, "com/intellij/uiDesigner/core/GridLayoutManager.class", moduleExcludes[module] ?: emptyList(), context)
|
||||
) {
|
||||
"Runtime classes of GUI designer must not be packaged to '$module' module in '$mainPluginModule' plugin, " +
|
||||
"because they are included into a platform JAR. Make sure that 'Automatically copy form runtime classes " +
|
||||
"to the output directory' is disabled in Settings | Editor | GUI Designer."
|
||||
@@ -860,12 +754,7 @@ private suspend fun checkOutputOfPluginModules(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun containsFileInOutput(
|
||||
moduleName: String,
|
||||
filePath: String,
|
||||
excludes: Collection<String>,
|
||||
context: BuildContext,
|
||||
): Boolean {
|
||||
private suspend fun containsFileInOutput(moduleName: String, filePath: String, excludes: Collection<String>, context: BuildContext): Boolean {
|
||||
val exists = context.hasModuleOutputPath(context.findRequiredModule(moduleName), filePath)
|
||||
if (!exists) {
|
||||
return false
|
||||
@@ -908,9 +797,7 @@ private fun CoroutineScope.createBuildThirdPartyLibraryListJob(entries: Sequence
|
||||
return createSkippableJob(spanBuilder("generate table of licenses for used third-party libraries"),
|
||||
BuildOptions.THIRD_PARTY_LIBRARIES_LIST_STEP, context) {
|
||||
val generator = createLibraryLicensesListGenerator(
|
||||
context = context,
|
||||
licenseList = context.productProperties.allLibraryLicenses,
|
||||
usedModulesNames = getIncludedModules(entries).toHashSet(),
|
||||
context, context.productProperties.allLibraryLicenses, getIncludedModules(entries).toHashSet()
|
||||
)
|
||||
val distAllDir = context.paths.distAllDir
|
||||
withContext(Dispatchers.IO) {
|
||||
@@ -981,7 +868,7 @@ private suspend fun buildKeymapPlugins(targetDir: Path, context: BuildContext):
|
||||
arrayOf("Sublime Text", "Sublime Text (Mac OS X)"),
|
||||
).map {
|
||||
async(CoroutineName("build keymap plugin for ${it[0]}")) {
|
||||
buildKeymapPlugin(keymaps = it, buildNumber = context.buildNumber, targetDir = targetDir, keymapDir = keymapDir)
|
||||
buildKeymapPlugin(keymaps = it, context.buildNumber, targetDir, keymapDir)
|
||||
}
|
||||
}
|
||||
}.map { it.getCompleted() }
|
||||
@@ -1122,7 +1009,7 @@ private fun copyIfChanged(targetDir: Path, sourceDir: Path, sourceFile: Path): B
|
||||
private suspend fun layoutAdditionalResources(layout: BaseLayout, context: BuildContext, targetDirectory: Path) {
|
||||
// quick fix for a very annoying FileAlreadyExistsException in CLion dev build
|
||||
val overwrite = ("intellij.rider.plugins.clion.radler" == (layout as? PluginLayout)?.mainModule)
|
||||
layoutResourcePaths(layout = layout, context = context, targetDirectory = targetDirectory, overwrite = overwrite)
|
||||
layoutResourcePaths(layout, context, targetDirectory, overwrite)
|
||||
if (layout !is PluginLayout) {
|
||||
return
|
||||
}
|
||||
@@ -1183,12 +1070,7 @@ private fun addArtifactMapping(artifact: JpsArtifact, entries: MutableCollection
|
||||
for (element in rootElement.children) {
|
||||
if (element is JpsProductionModuleOutputPackagingElement) {
|
||||
entries.add(ModuleOutputEntry(
|
||||
path = artifactFile,
|
||||
moduleName = element.moduleReference.moduleName,
|
||||
size = 0,
|
||||
hash = 0,
|
||||
relativeOutputFile = "",
|
||||
reason = "artifact: ${artifact.name}",
|
||||
artifactFile, element.moduleReference.moduleName, size = 0, hash = 0, relativeOutputFile = "", reason = "artifact: ${artifact.name}"
|
||||
))
|
||||
}
|
||||
else if (element is JpsTestModuleOutputPackagingElement) {
|
||||
@@ -1199,24 +1081,13 @@ private fun addArtifactMapping(artifact: JpsArtifact, entries: MutableCollection
|
||||
val parentReference = library!!.createReference().parentReference
|
||||
if (parentReference is JpsModuleReference) {
|
||||
entries.add(ModuleLibraryFileEntry(
|
||||
path = artifactFile,
|
||||
moduleName = parentReference.moduleName,
|
||||
libraryName = getLibraryFilename(library),
|
||||
libraryFile = null,
|
||||
hash = 0,
|
||||
size = 0,
|
||||
relativeOutputFile = null,
|
||||
artifactFile, parentReference.moduleName, getLibraryFilename(library), libraryFile = null, hash = 0, size = 0, relativeOutputFile = null
|
||||
))
|
||||
}
|
||||
else {
|
||||
val libraryData = ProjectLibraryData(libraryName = library.name, reason = "<- artifact ${artifact.name}")
|
||||
entries.add(ProjectLibraryEntry(
|
||||
path = artifactFile,
|
||||
data = libraryData,
|
||||
libraryFile = null,
|
||||
hash = 0,
|
||||
size = 0,
|
||||
relativeOutputFile = null,
|
||||
artifactFile, libraryData, libraryFile = null, hash = 0, size = 0, relativeOutputFile = null
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -1252,7 +1123,7 @@ private suspend fun archivePlugins(items: Collection<NonBundledPlugin>, compress
|
||||
.setAttribute("outputFile", target.toString())
|
||||
.setAttribute("optimizedZip", optimized)
|
||||
.use {
|
||||
archivePlugin(optimized = optimized, target = target, compress = compress, source = source, context = context)
|
||||
archivePlugin(optimized, target, compress, source, context)
|
||||
}
|
||||
if (withBlockMap) {
|
||||
spanBuilder("build plugin blockmap").setAttribute("file", target.toString()).use {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
// 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.openapi.util.io.FileUtil
|
||||
@@ -7,6 +7,8 @@ import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.util.regex.Pattern
|
||||
|
||||
private const val MAX_PATH = 260
|
||||
|
||||
internal class NsisFileListGenerator {
|
||||
private val directoryToFiles = LinkedHashMap<String, MutableList<Path>>()
|
||||
private val filesRelativePaths = mutableListOf<String>()
|
||||
@@ -25,7 +27,7 @@ internal class NsisFileListGenerator {
|
||||
|
||||
out.write("\n")
|
||||
|
||||
val installDir = "\$INSTDIR"
|
||||
val installDir = $$"$INSTDIR"
|
||||
scriptWithLongPathSupport(out, installDir, relativePath, files.map { it.fileName.toString() }) {
|
||||
out.write("SetOutPath \"$installDir${if (relativePath.isEmpty()) "" else "\\"}${escapeWinPath(relativePath)}\"\n")
|
||||
|
||||
@@ -37,7 +39,7 @@ internal class NsisFileListGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
fun generateUninstallerFile(outputFile: Path, installDir: String = "\$INSTDIR") {
|
||||
fun generateUninstallerFile(outputFile: Path, installDir: String = $$"$INSTDIR") {
|
||||
Files.newBufferedWriter(outputFile).use { out ->
|
||||
filesRelativePaths.sorted().forEach {
|
||||
scriptWithLongPathSupport(out, installDir, null, listOf(it)) {
|
||||
@@ -83,49 +85,45 @@ internal class NsisFileListGenerator {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun escapeWinPath(dir: String): String {
|
||||
return dir.replace('/', '\\').replace("\\$", "\\$\\$")
|
||||
}
|
||||
private fun escapeWinPath(dir: String): String = dir.replace('/', '\\').replace("\\$", "\\$\\$")
|
||||
|
||||
private fun scriptWithLongPathSupport(
|
||||
writer: BufferedWriter,
|
||||
instDirVariable: String,
|
||||
relativePath: String?,
|
||||
files: List<String>,
|
||||
actionWithOutPath: () -> Unit
|
||||
) {
|
||||
assert(instDirVariable.startsWith("$"))
|
||||
private fun scriptWithLongPathSupport(
|
||||
writer: BufferedWriter,
|
||||
instDirVariable: String,
|
||||
relativePath: String?,
|
||||
files: List<String>,
|
||||
actionWithOutPath: () -> Unit
|
||||
) {
|
||||
assert(instDirVariable.startsWith("$"))
|
||||
|
||||
val areLongPathsPresent = guessMaxPathLength(relativePath, files) > MAX_PATH
|
||||
if (areLongPathsPresent) {
|
||||
// For long paths in the installer, we perform a special maneuver.
|
||||
// Prepend the INSTDIR with "\\?\" so that WinAPI functions won't check its length and will allow working with the file.
|
||||
writer.write(
|
||||
"""
|
||||
val areLongPathsPresent = guessMaxPathLength(relativePath, files) > MAX_PATH
|
||||
if (areLongPathsPresent) {
|
||||
// For long paths in the installer, we perform a special maneuver.
|
||||
// Prepend the INSTDIR with "\\?\" so that WinAPI functions won't check its length and will allow working with the file.
|
||||
writer.write(
|
||||
"""
|
||||
Push $instDirVariable
|
||||
GetFullPathName $instDirVariable $instDirVariable
|
||||
StrCpy $instDirVariable "\\?\$instDirVariable"
|
||||
""".trimIndent() + "\n"
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
actionWithOutPath()
|
||||
|
||||
if (areLongPathsPresent) {
|
||||
// Clean up:
|
||||
writer.write("Pop $instDirVariable\n")
|
||||
}
|
||||
}
|
||||
|
||||
actionWithOutPath()
|
||||
|
||||
if (areLongPathsPresent) {
|
||||
// Clean up:
|
||||
writer.write("Pop $instDirVariable\n")
|
||||
private fun guessMaxPathLength(relativePath: String?, files: List<String>): Int {
|
||||
// Guess the typical length of $INSTDIR plus a small margin to be safe.
|
||||
// NOTE: The AppData path for non-admin installation might be longer than the one in Program Files, so let's consider that here.
|
||||
// Also, "IntelliJ IDEA Community Edition" is the longest product name so far.
|
||||
val instDirGuessedLength = "C:\\Users\\some-reasonably-long-user-name\\AppData\\Local\\JetBrains\\IntelliJ IDEA Community Edition 2024.1.2.SNAPSHOT\\".length + 10
|
||||
val directoryPathLength = instDirGuessedLength + (relativePath?.length?.let { it + 1 /* backslash */ } ?: 0)
|
||||
return directoryPathLength + (files.maxOfOrNull { it.length } ?: 0)
|
||||
}
|
||||
}
|
||||
|
||||
private fun guessMaxPathLength(relativePath: String?, files: List<String>): Int {
|
||||
// Guess the typical length of $INSTDIR plus a small margin to be safe.
|
||||
// NOTE: The AppData path for non-admin installation might be longer than the one in Program Files, so let's consider that here.
|
||||
// Also, "IntelliJ IDEA Community Edition" is the longest product name so far.
|
||||
val instDirGuessedLength = "C:\\Users\\some-reasonably-long-user-name\\AppData\\Local\\JetBrains\\IntelliJ IDEA Community Edition 2024.1.2.SNAPSHOT\\".length + 10
|
||||
val directoryPathLength = instDirGuessedLength + (relativePath?.length?.let { it + 1 /* backslash */ } ?: 0)
|
||||
return directoryPathLength + (files.maxOfOrNull { it.length } ?: 0)
|
||||
}
|
||||
|
||||
private const val MAX_PATH = 260
|
||||
@@ -2,7 +2,6 @@
|
||||
package org.jetbrains.intellij.build.impl
|
||||
|
||||
import com.intellij.openapi.util.SystemInfoRt
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.io.FileUtilRt
|
||||
import com.intellij.openapi.util.io.NioFiles
|
||||
import com.intellij.openapi.util.text.StringUtilRt
|
||||
@@ -395,11 +394,10 @@ internal class WindowsDistributionBuilder(
|
||||
.setAttribute("zipPath", zipPath.toString())
|
||||
.setAttribute("exePath", exePath.toString())
|
||||
.use {
|
||||
|
||||
runProcess(args = listOf("7z", "x", "-bd", exePath.toString()), workingDir = tempExe)
|
||||
// deleting NSIS-related files that appear after manual unpacking of .exe installer and do not belong to its contents
|
||||
@Suppress("SpellCheckingInspection")
|
||||
NioFiles.deleteRecursively(tempExe.resolve("\$PLUGINSDIR"))
|
||||
NioFiles.deleteRecursively(tempExe.resolve($$"$PLUGINSDIR"))
|
||||
Files.deleteIfExists(tempExe.resolve("bin/Uninstall.exe.nsis"))
|
||||
Files.deleteIfExists(tempExe.resolve("bin/Uninstall.exe"))
|
||||
|
||||
@@ -426,7 +424,7 @@ internal class WindowsDistributionBuilder(
|
||||
else if (!compareStreams(fileInExe.inputStream().buffered(FileUtilRt.MEGABYTE), zipFile.getInputStream(entry).buffered(FileUtilRt.MEGABYTE))) {
|
||||
differ.add(entryPath.toString())
|
||||
}
|
||||
FileUtil.delete(fileInExe)
|
||||
NioFiles.deleteRecursively(fileInExe)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user