mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 15:19:59 +07:00
Cleanup (minor optimization; NIO; quickfixes; typos; formatting)
GitOrigin-RevId: 529bc820f714a9b7918a2c9d25240e44ae929f53
This commit is contained in:
committed by
intellij-monorepo-bot
parent
80a4a5e8fa
commit
4b38f00a72
@@ -1,6 +1,7 @@
|
||||
// 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
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.plus
|
||||
import org.jetbrains.intellij.build.BuildPaths.Companion.COMMUNITY_ROOT
|
||||
@@ -14,16 +15,12 @@ import java.nio.file.Path
|
||||
internal suspend fun createCommunityBuildContext(
|
||||
options: BuildOptions = BuildOptions(),
|
||||
projectHome: Path = COMMUNITY_ROOT.communityRoot,
|
||||
): BuildContext {
|
||||
return BuildContextImpl.createContext(projectHome = projectHome,
|
||||
productProperties = IdeaCommunityProperties(COMMUNITY_ROOT.communityRoot),
|
||||
setupTracer = true,
|
||||
options = options)
|
||||
}
|
||||
): BuildContext = BuildContextImpl.createContext(
|
||||
projectHome, IdeaCommunityProperties(COMMUNITY_ROOT.communityRoot), setupTracer = true, options = options)
|
||||
|
||||
open class IdeaCommunityProperties(private val communityHomeDir: Path) : BaseIdeaProperties() {
|
||||
companion object {
|
||||
val MAVEN_ARTIFACTS_ADDITIONAL_MODULES = persistentListOf(
|
||||
val MAVEN_ARTIFACTS_ADDITIONAL_MODULES: PersistentList<String> = persistentListOf(
|
||||
"intellij.tools.jps.build.standalone",
|
||||
"intellij.devkit.runtimeModuleRepository.jps",
|
||||
"intellij.devkit.jps",
|
||||
@@ -37,8 +34,7 @@ open class IdeaCommunityProperties(private val communityHomeDir: Path) : BaseIde
|
||||
)
|
||||
}
|
||||
|
||||
override val baseFileName: String
|
||||
get() = "idea"
|
||||
override val baseFileName: String = "idea"
|
||||
|
||||
init {
|
||||
platformPrefix = "Idea"
|
||||
@@ -51,9 +47,11 @@ open class IdeaCommunityProperties(private val communityHomeDir: Path) : BaseIde
|
||||
"intellij.platform.starter",
|
||||
"intellij.idea.community.customization",
|
||||
)
|
||||
productLayout.bundledPluginModules = IDEA_BUNDLED_PLUGINS + sequenceOf("intellij.javaFX.community",
|
||||
"intellij.vcs.github.community",
|
||||
"intellij.vcs.gitlab.community")
|
||||
productLayout.bundledPluginModules = IDEA_BUNDLED_PLUGINS + sequenceOf(
|
||||
"intellij.javaFX.community",
|
||||
"intellij.vcs.github.community",
|
||||
"intellij.vcs.gitlab.community"
|
||||
)
|
||||
|
||||
productLayout.prepareCustomPluginRepositoryForPublishedPlugins = false
|
||||
productLayout.buildAllCompatiblePlugins = false
|
||||
@@ -79,6 +77,7 @@ open class IdeaCommunityProperties(private val communityHomeDir: Path) : BaseIde
|
||||
baseDownloadUrl = "https://download.jetbrains.com/idea/"
|
||||
buildDocAuthoringAssets = true
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
qodanaProductProperties = QodanaProductProperties("QDJVMC", "Qodana Community for JVM")
|
||||
additionalVmOptions = persistentListOf("-Dllm.show.ai.promotion.window.on.start=false")
|
||||
enableKotlinPluginK2ByDefault()
|
||||
@@ -94,15 +93,11 @@ open class IdeaCommunityProperties(private val communityHomeDir: Path) : BaseIde
|
||||
sourceDir = context.paths.communityHomeDir.resolve("build/conf/ideaCE/common/bin"),
|
||||
targetDir = targetDir.resolve("bin"),
|
||||
)
|
||||
|
||||
bundleExternalPlugins(context, targetDir)
|
||||
}
|
||||
|
||||
protected open suspend fun bundleExternalPlugins(context: BuildContext, targetDirectory: Path) {
|
||||
//temporary unbundle VulnerabilitySearch
|
||||
//ExternalPluginBundler.bundle('VulnerabilitySearch',
|
||||
// "$buildContext.paths.communityHome/build/dependencies",
|
||||
// buildContext, targetDirectory)
|
||||
}
|
||||
protected open suspend fun bundleExternalPlugins(context: BuildContext, targetDirectory: Path) { }
|
||||
|
||||
override fun createWindowsCustomizer(projectHome: String): WindowsDistributionCustomizer = CommunityWindowsDistributionCustomizer()
|
||||
override fun createLinuxCustomizer(projectHome: String): LinuxDistributionCustomizer = CommunityLinuxDistributionCustomizer()
|
||||
@@ -116,13 +111,12 @@ open class IdeaCommunityProperties(private val communityHomeDir: Path) : BaseIde
|
||||
fileAssociations = listOf("java", "gradle", "groovy", "kt", "kts", "pom")
|
||||
}
|
||||
|
||||
override fun getFullNameIncludingEdition(appInfo: ApplicationInfoProperties) = "IntelliJ IDEA Community Edition"
|
||||
override fun getFullNameIncludingEdition(appInfo: ApplicationInfoProperties): String = "IntelliJ IDEA Community Edition"
|
||||
|
||||
override fun getFullNameIncludingEditionAndVendor(appInfo: ApplicationInfoProperties) = "IntelliJ IDEA Community Edition"
|
||||
override fun getFullNameIncludingEditionAndVendor(appInfo: ApplicationInfoProperties): String = "IntelliJ IDEA Community Edition"
|
||||
|
||||
override fun getUninstallFeedbackPageUrl(appInfo: ApplicationInfoProperties): String {
|
||||
return "https://www.jetbrains.com/idea/uninstall/?edition=IC-${appInfo.majorVersion}.${appInfo.minorVersion}"
|
||||
}
|
||||
override fun getUninstallFeedbackPageUrl(appInfo: ApplicationInfoProperties): String =
|
||||
"https://www.jetbrains.com/idea/uninstall/?edition=IC-${appInfo.majorVersion}.${appInfo.minorVersion}"
|
||||
}
|
||||
|
||||
protected open inner class CommunityLinuxDistributionCustomizer : LinuxDistributionCustomizer() {
|
||||
@@ -135,13 +129,12 @@ open class IdeaCommunityProperties(private val communityHomeDir: Path) : BaseIde
|
||||
"Together, powerful static code analysis and ergonomic design make development not only productive but also an enjoyable experience."
|
||||
}
|
||||
|
||||
override fun getRootDirectoryName(appInfo: ApplicationInfoProperties, buildNumber: String) = "idea-IC-$buildNumber"
|
||||
override fun getRootDirectoryName(appInfo: ApplicationInfoProperties, buildNumber: String): String = "idea-IC-$buildNumber"
|
||||
|
||||
override fun generateExecutableFilesPatterns(context: BuildContext, includeRuntime: Boolean, arch: JvmArchitecture): Sequence<String> {
|
||||
return super.generateExecutableFilesPatterns(context, includeRuntime, arch)
|
||||
override fun generateExecutableFilesPatterns(context: BuildContext, includeRuntime: Boolean, arch: JvmArchitecture): Sequence<String> =
|
||||
super.generateExecutableFilesPatterns(context, includeRuntime, arch)
|
||||
.plus(KotlinBinaries.kotlinCompilerExecutables)
|
||||
.filterNot { it == "plugins/**/*.sh" }
|
||||
}
|
||||
}
|
||||
|
||||
protected open inner class CommunityMacDistributionCustomizer : MacDistributionCustomizer() {
|
||||
@@ -155,27 +148,20 @@ open class IdeaCommunityProperties(private val communityHomeDir: Path) : BaseIde
|
||||
dmgImagePath = "${communityHomeDir}/build/conf/ideaCE/mac/images/dmg_background.tiff"
|
||||
}
|
||||
|
||||
override fun getRootDirectoryName(appInfo: ApplicationInfoProperties, buildNumber: String): String {
|
||||
return if (appInfo.isEAP) {
|
||||
"IntelliJ IDEA ${appInfo.majorVersion}.${appInfo.minorVersionMainPart} CE EAP.app"
|
||||
}
|
||||
else {
|
||||
"IntelliJ IDEA CE.app"
|
||||
}
|
||||
}
|
||||
override fun getRootDirectoryName(appInfo: ApplicationInfoProperties, buildNumber: String): String =
|
||||
if (appInfo.isEAP) "IntelliJ IDEA ${appInfo.majorVersion}.${appInfo.minorVersionMainPart} CE EAP.app"
|
||||
else "IntelliJ IDEA CE.app"
|
||||
|
||||
override fun generateExecutableFilesPatterns(context: BuildContext, includeRuntime: Boolean, arch: JvmArchitecture): Sequence<String> {
|
||||
return super.generateExecutableFilesPatterns(context, includeRuntime, arch)
|
||||
override fun generateExecutableFilesPatterns(context: BuildContext, includeRuntime: Boolean, arch: JvmArchitecture): Sequence<String> =
|
||||
super.generateExecutableFilesPatterns(context, includeRuntime, arch)
|
||||
.plus(KotlinBinaries.kotlinCompilerExecutables)
|
||||
.filterNot { it == "plugins/**/*.sh" }
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSystemSelector(appInfo: ApplicationInfoProperties, buildNumber: String): String {
|
||||
return "IdeaIC${appInfo.majorVersion}.${appInfo.minorVersionMainPart}"
|
||||
}
|
||||
override fun getSystemSelector(appInfo: ApplicationInfoProperties, buildNumber: String): String =
|
||||
"IdeaIC${appInfo.majorVersion}.${appInfo.minorVersionMainPart}"
|
||||
|
||||
override fun getBaseArtifactName(appInfo: ApplicationInfoProperties, buildNumber: String) = "ideaIC-$buildNumber"
|
||||
override fun getBaseArtifactName(appInfo: ApplicationInfoProperties, buildNumber: String): String = "ideaIC-$buildNumber"
|
||||
|
||||
override fun getOutputDirectoryName(appInfo: ApplicationInfoProperties) = "idea-ce"
|
||||
override fun getOutputDirectoryName(appInfo: ApplicationInfoProperties): String = "idea-ce"
|
||||
}
|
||||
|
||||
@@ -1,5 +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("unused", "ReplaceJavaStaticMethodWithKotlinAnalog")
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
@file:JvmName("DevMainImpl")
|
||||
package org.jetbrains.intellij.build.devServer
|
||||
|
||||
@@ -8,17 +7,16 @@ import com.intellij.util.SystemProperties
|
||||
import org.jetbrains.intellij.build.BuildOptions
|
||||
import org.jetbrains.intellij.build.dev.BuildRequest
|
||||
import org.jetbrains.intellij.build.dev.buildProductInProcess
|
||||
import org.jetbrains.intellij.build.dev.getAdditionalPluginMainModules
|
||||
import org.jetbrains.intellij.build.dev.getIdeSystemProperties
|
||||
import org.jetbrains.intellij.build.telemetry.withTracer
|
||||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
|
||||
@Suppress("unused", "IO_FILE_USAGE")
|
||||
fun buildDevMain(): Collection<Path> {
|
||||
//TracerProviderManager.setOutput(Path.of(System.getProperty("user.home"), "trace.json"))
|
||||
@Suppress("TestOnlyProblems")
|
||||
val ideaProjectRoot = Path.of(PathManager.getHomePathFor(PathManager::class.java)!!)
|
||||
System.setProperty("idea.dev.project.root", ideaProjectRoot.toString().replace(File.separator, "/"))
|
||||
System.setProperty("idea.dev.project.root", ideaProjectRoot.toString().replace(java.io.File.separator, "/"))
|
||||
|
||||
var homePath: String? = null
|
||||
var newClassPath: Collection<Path>? = null
|
||||
@@ -31,7 +29,7 @@ fun buildDevMain(): Collection<Path> {
|
||||
keepHttpClient = false,
|
||||
platformClassPathConsumer = { classPath, runDir ->
|
||||
newClassPath = classPath
|
||||
homePath = runDir.toString().replace(File.separator, "/")
|
||||
homePath = runDir.toString().replace(java.io.File.separator, "/")
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
val exceptions = setOf("jna.boot.library.path", "pty4j.preferred.native.folder", "jna.nosys", "jna.noclasspath", "jb.vmOptionsFile")
|
||||
@@ -51,4 +49,7 @@ fun buildDevMain(): Collection<Path> {
|
||||
System.setProperty(PathManager.PROPERTY_HOME_PATH, it)
|
||||
}
|
||||
return newClassPath!!
|
||||
}
|
||||
}
|
||||
|
||||
private fun getAdditionalPluginMainModules(): List<String> =
|
||||
System.getProperty("additional.modules")?.splitToSequence(',')?.map { it.trim() }?.filter { it.isNotEmpty() }?.toList() ?: emptyList()
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
@file:Suppress("ReplaceJavaStaticMethodWithKotlinAnalog")
|
||||
|
||||
// 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.util.containers.withAll
|
||||
import kotlinx.collections.immutable.PersistentList
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
import kotlinx.collections.immutable.plus
|
||||
@@ -11,26 +8,6 @@ import org.jetbrains.intellij.build.impl.PlatformJarNames.TEST_FRAMEWORK_JAR
|
||||
import org.jetbrains.intellij.build.impl.PlatformLayout
|
||||
import org.jetbrains.intellij.build.kotlin.KotlinPluginBuilder
|
||||
|
||||
private val BASE_CLASS_VERSIONS: Map<String, String> = java.util.Map.copyOf(hashMapOf(
|
||||
"" to "17",
|
||||
"lib/idea_rt.jar" to "1.7",
|
||||
"lib/forms_rt.jar" to "1.8",
|
||||
"lib/annotations.jar" to "1.8",
|
||||
"lib/util_rt.jar" to "1.7",
|
||||
"lib/util-8.jar" to "1.8",
|
||||
"lib/external-system-rt.jar" to "1.8",
|
||||
"plugins/java-coverage/lib/java-coverage-rt.jar" to "1.8",
|
||||
"plugins/junit/lib/junit-rt.jar" to "1.7",
|
||||
"plugins/junit/lib/junit5-rt.jar" to "1.8",
|
||||
"plugins/gradle/lib/gradle-tooling-extension-api.jar" to "1.8",
|
||||
"plugins/gradle/lib/gradle-tooling-extension-impl.jar" to "1.8",
|
||||
"plugins/maven-server/lib/maven-server.jar" to "1.8",
|
||||
"plugins/maven-model/lib/maven-model.jar" to "1.8",
|
||||
"plugins/maven/lib/maven3-server-common.jar" to "1.8",
|
||||
"plugins/maven/lib/maven3-server.jar" to "1.8",
|
||||
"plugins/maven/lib/artifact-resolver-m31.jar" to "1.8",
|
||||
))
|
||||
|
||||
/**
|
||||
* Default bundled plugins for all editions of IntelliJ IDEA.
|
||||
* See also [DEFAULT_BUNDLED_PLUGINS].
|
||||
@@ -94,13 +71,30 @@ val IDEA_BUNDLED_PLUGINS: PersistentList<String> = DEFAULT_BUNDLED_PLUGINS + seq
|
||||
"intellij.turboComplete",
|
||||
)
|
||||
|
||||
val CE_CLASS_VERSIONS: Map<String, String> = BASE_CLASS_VERSIONS.withAll(hashMapOf(
|
||||
val CE_CLASS_VERSIONS: Map<String, String> = mapOf(
|
||||
"" to "17",
|
||||
"lib/idea_rt.jar" to "1.7",
|
||||
"lib/forms_rt.jar" to "1.8",
|
||||
"lib/annotations.jar" to "1.8",
|
||||
"lib/util_rt.jar" to "1.7",
|
||||
"lib/util-8.jar" to "1.8",
|
||||
"lib/external-system-rt.jar" to "1.8",
|
||||
"plugins/java-coverage/lib/java-coverage-rt.jar" to "1.8",
|
||||
"plugins/junit/lib/junit-rt.jar" to "1.7",
|
||||
"plugins/junit/lib/junit5-rt.jar" to "1.8",
|
||||
"plugins/gradle/lib/gradle-tooling-extension-api.jar" to "1.8",
|
||||
"plugins/gradle/lib/gradle-tooling-extension-impl.jar" to "1.8",
|
||||
"plugins/maven-server/lib/maven-server.jar" to "1.8",
|
||||
"plugins/maven-model/lib/maven-model.jar" to "1.8",
|
||||
"plugins/maven/lib/maven3-server-common.jar" to "1.8",
|
||||
"plugins/maven/lib/maven3-server.jar" to "1.8",
|
||||
"plugins/maven/lib/artifact-resolver-m31.jar" to "1.8",
|
||||
"plugins/java/lib/jshell-frontend.jar" to "9",
|
||||
"plugins/java/lib/sa-jdwp" to "", // ignored
|
||||
"plugins/java/lib/rt/debugger-agent.jar" to "1.7",
|
||||
"plugins/Groovy/lib/groovy-rt.jar" to "1.7",
|
||||
"plugins/Groovy/lib/groovy-constants-rt.jar" to "1.7",
|
||||
))
|
||||
)
|
||||
|
||||
val TEST_FRAMEWORK_LAYOUT_CUSTOMIZER: (PlatformLayout, BuildContext) -> Unit = { layout, _ ->
|
||||
for (name in listOf(
|
||||
@@ -159,7 +153,7 @@ abstract class BaseIdeaProperties : JetBrainsProductProperties() {
|
||||
// TODO should be used as regular project library when the issue will be fixed at the Gradle tooling api side https://github.com/gradle/gradle/issues/8431 and the patched class will be removed
|
||||
layout.withoutProjectLibrary("Gradle")
|
||||
|
||||
// this library is placed into subdirectory of the 'lib' directory in Android plugin layout, so we need to exclude it from the platform layout explicitly
|
||||
// this library is placed into a subdirectory of the 'lib' directory in the Android plugin layout, so we need to exclude it from the platform layout explicitly
|
||||
layout.withoutProjectLibrary("layoutlib")
|
||||
|
||||
layout.withoutProjectLibrary("jetbrains.qodana.cloud.kotlin.client")
|
||||
|
||||
@@ -222,7 +222,7 @@ sealed interface DistFileContent {
|
||||
}
|
||||
|
||||
data class LocalDistFileContent(@JvmField val file: Path, val isExecutable: Boolean = false) : DistFileContent {
|
||||
override fun readAsStringForDebug() = Files.newInputStream(file).readNBytes(1024).decodeToString()
|
||||
override fun readAsStringForDebug(): String = Files.newInputStream(file).readNBytes(1024).decodeToString()
|
||||
|
||||
override fun toString(): String = "LocalDistFileContent(file=$file, isExecutable=$isExecutable)"
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -46,12 +46,12 @@ interface CompilationContext {
|
||||
fun findModule(name: String): JpsModule?
|
||||
|
||||
/**
|
||||
* Could be directory or jar file
|
||||
* A directory or a .jar file.
|
||||
*/
|
||||
suspend fun getModuleOutputDir(module: JpsModule, forTests: Boolean = false): Path
|
||||
|
||||
/**
|
||||
* Could be directory or jar file
|
||||
* A directory or a .jar file.
|
||||
*/
|
||||
suspend fun getModuleTestsOutputDir(module: JpsModule): Path
|
||||
|
||||
@@ -102,4 +102,3 @@ interface CompilationTasks {
|
||||
|
||||
suspend fun generateRuntimeModuleRepository()
|
||||
}
|
||||
|
||||
|
||||
@@ -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 com.intellij.platform.ijent.community.buildConstants.IJENT_BOOT_CLASSPATH_MODULE
|
||||
@@ -17,7 +17,7 @@ import java.nio.file.Path
|
||||
import java.util.function.BiPredicate
|
||||
|
||||
/**
|
||||
* Describes distribution of an in-house IntelliJ-based IDE hosted in IntelliJ repository.
|
||||
* Describes a distribution of an IntelliJ-based IDE hosted in the IntelliJ repository.
|
||||
*/
|
||||
abstract class JetBrainsProductProperties : ProductProperties() {
|
||||
init {
|
||||
@@ -29,18 +29,14 @@ abstract class JetBrainsProductProperties : ProductProperties() {
|
||||
productLayout.addPlatformSpec { layout, _ -> layout.withModule(IJENT_BOOT_CLASSPATH_MODULE, PLATFORM_CORE_NIO_FS) }
|
||||
}
|
||||
|
||||
protected fun isCommunityModule(module: JpsModule, context: BuildContext): Boolean {
|
||||
return module.contentRootsList.urls.all { url ->
|
||||
protected fun isCommunityModule(module: JpsModule, context: BuildContext): Boolean =
|
||||
module.contentRootsList.urls.all { url ->
|
||||
Path.of(JpsPathUtil.urlToPath(url)).startsWith(context.paths.communityHomeDir)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun copyAdditionalFiles(context: BuildContext, targetDir: Path) {
|
||||
}
|
||||
override suspend fun copyAdditionalFiles(context: BuildContext, targetDir: Path) { }
|
||||
|
||||
private class InvalidPluginDescriptorError(message: String) : InvalidDescriptorProblem(
|
||||
detailedMessage = message, descriptorPath = "",
|
||||
) {
|
||||
private class InvalidPluginDescriptorError(message: String) : InvalidDescriptorProblem(detailedMessage = message, descriptorPath = "") {
|
||||
override val level = Level.ERROR
|
||||
}
|
||||
|
||||
@@ -92,9 +88,7 @@ abstract class JetBrainsProductProperties : ProductProperties() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 🌲
|
||||
* see KTIJ-30761
|
||||
* @see org.jetbrains.intellij.build.sharedIndexes.PreSharedIndexesGenerator
|
||||
* See KTIJ-30761, `org.jetbrains.intellij.build.sharedIndexes.PreSharedIndexesGenerator`.
|
||||
*/
|
||||
protected fun enableKotlinPluginK2ByDefault() {
|
||||
additionalVmOptions += "-Didea.kotlin.plugin.use.k2=true"
|
||||
|
||||
@@ -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 com.intellij.platform.buildData.productInfo.CustomProperty
|
||||
@@ -26,10 +26,10 @@ import java.util.function.BiPredicate
|
||||
abstract class ProductProperties {
|
||||
/**
|
||||
* The base name (i.e., a name without the extension and architecture suffix)
|
||||
* of launcher files (bin/xxx64.exe, bin/xxx.bat, bin/xxx.sh, MacOS/xxx),
|
||||
* of launcher files ('bin/xxx64.exe', 'bin/xxx.bat', 'bin/xxx.sh', 'Contents/MacOS/xxx'),
|
||||
* usually a short product name in lower case (`"idea"` for IntelliJ IDEA, `"webstorm"` for WebStorm, etc.).
|
||||
*
|
||||
* **Important:** please make sure that this property and the `//names@script` attribute in the product's `*ApplicationInfo.xml` file
|
||||
* **Important**: please make sure that this property and the `//names@script` attribute in the product's `*ApplicationInfo.xml` file
|
||||
* have the same value.
|
||||
*/
|
||||
abstract val baseFileName: String
|
||||
@@ -65,7 +65,7 @@ abstract class ProductProperties {
|
||||
var fastInstanceActivation: Boolean = true
|
||||
|
||||
/**
|
||||
* An entry point into application's Java code, usually [com.intellij.idea.Main].
|
||||
* An entry point into application's Java code, usually `com.intellij.idea.Main`.
|
||||
* Use [BuildContext.ideMainClassName] if you need to access this value in the build scripts.
|
||||
*/
|
||||
var mainClassName: String = "com.intellij.idea.Main"
|
||||
@@ -79,8 +79,8 @@ abstract class ProductProperties {
|
||||
|
||||
/**
|
||||
* Name of the command which runs IDE in 'offline inspections' mode
|
||||
* (returned by [com.intellij.openapi.application.ApplicationStarter.getCommandName]).
|
||||
* This property will be also used to name sh/bat scripts which execute this command.
|
||||
* (as returned by `com.intellij.openapi.application.ApplicationStarter.getCommandName`).
|
||||
* This property will be also used to name .sh/.bat scripts which execute the command.
|
||||
*/
|
||||
var inspectCommandName: String = "inspect"
|
||||
|
||||
@@ -108,18 +108,21 @@ abstract class ProductProperties {
|
||||
var enableCds: Boolean = false
|
||||
|
||||
/**
|
||||
* Additional arguments which will be added to JVM command line in IDE launchers for all operating systems.
|
||||
*/
|
||||
var additionalIdeJvmArguments: MutableList<String> = mutableListOf()
|
||||
|
||||
/**
|
||||
* Additional arguments which will be added to VM options for all operating systems.
|
||||
* Difference between this property and [org.jetbrains.intellij.build.ProductProperties.additionalIdeJvmArguments] is this one could be
|
||||
* used to put options to `*.vmoptions` file while arguments from [org.jetbrains.intellij.build.ProductProperties.additionalIdeJvmArguments]
|
||||
* are used in command line in `*.sh` scripts or similar
|
||||
* Additional options to add to a `*.vmoptions` file for all operating systems.
|
||||
* A user might override these options.
|
||||
*
|
||||
* See also [additionalIdeJvmArguments].
|
||||
*/
|
||||
var additionalVmOptions: PersistentList<String> = persistentListOf()
|
||||
|
||||
/**
|
||||
* Additional options to append to the JVM command line by IDE launchers for all operating systems.
|
||||
* These options have the highest precedence and cannot be overridden by a user.
|
||||
*
|
||||
* See also [additionalVmOptions].
|
||||
*/
|
||||
var additionalIdeJvmArguments: MutableList<String> = mutableListOf()
|
||||
|
||||
/**
|
||||
* The specified options will be used instead of/in addition to the default JVM memory options for all operating systems.
|
||||
*/
|
||||
@@ -139,13 +142,13 @@ abstract class ProductProperties {
|
||||
var reassignAltClickToMultipleCarets: Boolean = false
|
||||
|
||||
/**
|
||||
* Now file containing information about third-party libraries is bundled and shown inside the IDE.
|
||||
* Now a file containing information about third-party libraries is bundled and shown inside the IDE.
|
||||
* If `true`, HTML & JSON files of third-party libraries will be placed alongside built artifacts.
|
||||
*/
|
||||
var generateLibraryLicensesTable: Boolean = true
|
||||
|
||||
/**
|
||||
* List of licenses information about all libraries which can be used in the product modules.
|
||||
* List of licenses information about all libraries that can be used in the product modules.
|
||||
*/
|
||||
var allLibraryLicenses: List<LibraryLicense> = CommunityLibraryLicenses.LICENSES_LIST
|
||||
|
||||
@@ -171,13 +174,14 @@ abstract class ProductProperties {
|
||||
* It's used by the build scripts for the following:
|
||||
* * to inject URL of *.manifest file produced by [RepairUtilityBuilder][org.jetbrains.intellij.build.impl.support.RepairUtilityBuilder] and
|
||||
* in `repair` executable;
|
||||
* * to specify URL of distributions in [SBOM][SoftwareBillOfMaterials] files.
|
||||
* * to specify URL of distributions in [SoftwareBillOfMaterials] files.
|
||||
*/
|
||||
var baseDownloadUrl: String? = null
|
||||
|
||||
/**
|
||||
* See [SoftwareBillOfMaterials]
|
||||
*/
|
||||
@Suppress("SpellCheckingInspection")
|
||||
val sbomOptions: SoftwareBillOfMaterials.Options = SoftwareBillOfMaterials.Options()
|
||||
|
||||
/**
|
||||
@@ -197,13 +201,13 @@ abstract class ProductProperties {
|
||||
var embeddedFrontendRootModule: String? = null
|
||||
|
||||
/**
|
||||
* Specifies a factory function for an instance which will be used to generate launchers for the embedded frontend variant (JetBrains Client).
|
||||
* Specifies a factory function which will be used to generate launchers for the embedded frontend variant (JetBrains Client).
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
var embeddedFrontendProperties: (() -> ProductProperties)? = null
|
||||
|
||||
/**
|
||||
* Set to the root product module (the one containing product-modules.xml file) to enable using module-based loader for the product.
|
||||
* Set to the root product module (the one containing the "product-modules.xml" file) to enable using a module-based loader for the product.
|
||||
* [BuildOptions.useModularLoader] will be used to determine whether the produced distribution will actually use this way.
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
@@ -214,6 +218,7 @@ abstract class ProductProperties {
|
||||
* [the modular loader][com.intellij.platform.bootstrap.ModuleBasedProductLoadingStrategy].
|
||||
* This property makes sense only if [rootModuleForModularLoader] is set to a non-null value.
|
||||
*/
|
||||
@Suppress("KDocUnresolvedReference")
|
||||
@ApiStatus.Experimental
|
||||
var productMode: ProductMode = ProductMode.MONOLITH
|
||||
|
||||
@@ -227,7 +232,7 @@ abstract class ProductProperties {
|
||||
/**
|
||||
* A config map for [org.jetbrains.intellij.build.impl.ClassFileChecker], when .class file version verification is necessary.
|
||||
*/
|
||||
var versionCheckerConfig: Map<String, String> = java.util.Map.of()
|
||||
var versionCheckerConfig: Map<String, String> = mapOf()
|
||||
|
||||
/**
|
||||
* Strings which are forbidden as a part of the resulting class file path. E.g.:
|
||||
@@ -236,18 +241,19 @@ abstract class ProductProperties {
|
||||
var forbiddenClassFileSubPaths: PersistentList<String> = persistentListOf()
|
||||
|
||||
/**
|
||||
* Exceptions from forbiddenClassFileSubPaths. Must contain full string with the offending class, including the jar path. E.g.:
|
||||
* "plugins/sample/lib/sample.jar!/com/sample/license/ThirdPartyLicensesDialog.class"
|
||||
* Exceptions from [forbiddenClassFileSubPaths].
|
||||
* Must contain a full string with the offending class, including the .jar path.
|
||||
* E.g., "plugins/sample/lib/sample.jar!/com/sample/license/ThirdPartyLicensesDialog.class".
|
||||
*/
|
||||
var forbiddenClassFileSubPathExceptions: PersistentList<String> = persistentListOf()
|
||||
|
||||
/**
|
||||
* Paths to properties files the content of which should be appended to idea.properties file.
|
||||
* Paths to files, the content of which should be appended to the 'idea.properties' file.
|
||||
*/
|
||||
var additionalIDEPropertiesFilePaths: List<Path> = emptyList()
|
||||
|
||||
/**
|
||||
* Paths to directories the content of which should be added to 'license' directory of IDE distribution.
|
||||
* Paths to directories, the content of which should be added to the 'license' directory of IDE distribution.
|
||||
*/
|
||||
var additionalDirectoriesWithLicenses: List<Path> = emptyList()
|
||||
|
||||
@@ -257,7 +263,7 @@ abstract class ProductProperties {
|
||||
abstract fun getBaseArtifactName(appInfo: ApplicationInfoProperties, buildNumber: String): String
|
||||
|
||||
/**
|
||||
* `<productName>-<buildNumber>` for any (nightly, EAP or release) build, e.g. ideaIC-232.9999
|
||||
* `<productName>-<buildNumber>` for any (nightly, EAP, or release) build, e.g., 'ideaIC-232.9999'
|
||||
*
|
||||
* See [getBaseArtifactName].
|
||||
*/
|
||||
@@ -312,7 +318,7 @@ abstract class ProductProperties {
|
||||
* to allow users to customize location of the product runtime (`<PRODUCT>_JDK` variable),
|
||||
* *.vmoptions file (`<PRODUCT>_VM_OPTIONS`), `idea.properties` file (`<PRODUCT>_PROPERTIES`).
|
||||
*/
|
||||
open fun getEnvironmentVariableBaseName(appInfo: ApplicationInfoProperties) = appInfo.launcherName.uppercase().replace('-', '_')
|
||||
open fun getEnvironmentVariableBaseName(appInfo: ApplicationInfoProperties): String = appInfo.launcherName.uppercase().replace('-', '_')
|
||||
|
||||
/**
|
||||
* Override this method to copy additional files to distributions of all operating systems.
|
||||
@@ -324,7 +330,7 @@ abstract class ProductProperties {
|
||||
* @return the name of a subdirectory under `projectHome/out` where build artifacts will be placed,
|
||||
* must be unique among all products built from the same sources.
|
||||
*/
|
||||
open fun getOutputDirectoryName(appInfo: ApplicationInfoProperties) = appInfo.fullProductName.lowercase(Locale.ROOT)
|
||||
open fun getOutputDirectoryName(appInfo: ApplicationInfoProperties): String = appInfo.fullProductName.lowercase(Locale.ROOT)
|
||||
|
||||
/**
|
||||
* Paths to externally built plugins to be included in the IDE.
|
||||
@@ -341,6 +347,7 @@ abstract class ProductProperties {
|
||||
/**
|
||||
* @return custom properties for [org.jetbrains.intellij.build.impl.productInfo.ProductInfoData].
|
||||
*/
|
||||
@Suppress("KDocUnresolvedReference")
|
||||
open fun generateCustomPropertiesForProductInfo(): List<CustomProperty> = emptyList()
|
||||
|
||||
/**
|
||||
@@ -358,7 +365,7 @@ abstract class ProductProperties {
|
||||
open fun validateLayout(platformLayout: PlatformLayout, context: BuildContext) {}
|
||||
|
||||
/**
|
||||
* Copies additional localization resources to the plugin generated localization resources directory.
|
||||
* Copies additional localization resources to the plugin-generated localization resources directory.
|
||||
*/
|
||||
@ApiStatus.Internal
|
||||
open suspend fun copyAdditionalLocalizationResourcesToPlugin(context: BuildContext, lang: String, targetDir: Path) {}
|
||||
@@ -384,7 +391,7 @@ abstract class ProductProperties {
|
||||
|
||||
/**
|
||||
* When set to true, invokes keymap and inspections description generators during build.
|
||||
* These generators produce artifacts utilized by documentation authoring tools and builds.
|
||||
* These generators produce artifacts used by documentation-authoring tools and builds.
|
||||
*/
|
||||
var buildDocAuthoringAssets: Boolean = false
|
||||
|
||||
@@ -393,6 +400,7 @@ abstract class ProductProperties {
|
||||
* todo: remove me when platform is ready
|
||||
*/
|
||||
@Deprecated("Do not use it. Needed only for JetBrains Client per-ide customisation + it's temporary")
|
||||
@Suppress("DEPRECATION")
|
||||
open fun applicationInfoOverride(project: JpsProject): ApplicationInfoOverrides? = null
|
||||
|
||||
@Deprecated("Do not use it. Needed only for JetBrains Client per-ide customisation + it's temporary")
|
||||
|
||||
@@ -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", "ReplaceJavaStaticMethodWithKotlinAnalog")
|
||||
|
||||
package org.jetbrains.intellij.build
|
||||
|
||||
import com.intellij.platform.ijent.community.buildConstants.isIjentWslFsEnabledByDefaultForProduct
|
||||
@@ -51,7 +49,7 @@ private val sourceToNames: Map<String, MutableList<String>> by lazy {
|
||||
}
|
||||
|
||||
suspend fun reorderJar(relativePath: String, file: Path) {
|
||||
val orderedNames = sourceToNames.get(relativePath) ?: return
|
||||
val orderedNames = sourceToNames[relativePath] ?: return
|
||||
spanBuilder("reorder jar")
|
||||
.setAttribute("relativePath", relativePath)
|
||||
.setAttribute("file", file.toString())
|
||||
@@ -186,8 +184,9 @@ internal fun writePluginClassPathHeader(out: DataOutputStream, isJarOnly: Boolea
|
||||
out.write(if (isJarOnly) 1 else 0)
|
||||
|
||||
// main plugin
|
||||
val mainDescriptor = moduleOutputPatcher.getPatchedContent(context.productProperties.applicationInfoModule)
|
||||
.let { it.get("META-INF/plugin.xml") ?: it.get("META-INF/${context.productProperties.platformPrefix}Plugin.xml") }
|
||||
val mainDescriptor = moduleOutputPatcher.getPatchedContent(context.productProperties.applicationInfoModule).let {
|
||||
it["META-INF/plugin.xml"] ?: it["META-INF/${context.productProperties.platformPrefix}Plugin.xml"]
|
||||
}
|
||||
|
||||
val mainPluginDescriptorContent = requireNotNull(mainDescriptor) {
|
||||
"Cannot find core plugin descriptor (module=${context.productProperties.applicationInfoModule})"
|
||||
@@ -278,7 +277,7 @@ internal fun generatePluginClassPathFromPrebuiltPluginFiles(pluginEntries: List<
|
||||
putMoreLikelyPluginJarsFirst(pluginDir.fileName.toString(), filesInLibUnderPluginDir = files)
|
||||
}
|
||||
|
||||
// move dir with plugin.xml to top (it may not exist if for some reason the main module dir still being packed into JAR)
|
||||
// move a dir with "plugin.xml" to the top (it may not exist if for some reason the main module dir still being packed into JAR)
|
||||
writeEntry(out = out, files = files, pluginDir = pluginDir, pluginDescriptorContent = reorderPluginClassPath(files))
|
||||
}
|
||||
|
||||
|
||||
@@ -123,19 +123,13 @@ private fun createConfiguration(productionClassOutput: Path, homePath: Path): Co
|
||||
return Json.decodeFromString(Configuration.serializer(), Files.readString(projectPropertiesPath))
|
||||
}
|
||||
|
||||
internal fun getProductPropertiesPath(homePath: Path): Path {
|
||||
internal fun getProductPropertiesPath(homePath: Path): Path =
|
||||
// handle a custom product properties path
|
||||
val customPath = System.getProperty(CUSTOM_PRODUCT_PROPERTIES_PATH)?.let { homePath.resolve(it) }
|
||||
if (customPath != null && Files.exists(customPath)) {
|
||||
return customPath
|
||||
}
|
||||
return homePath.resolve(PRODUCTS_PROPERTIES_PATH)
|
||||
}
|
||||
System.getProperty(CUSTOM_PRODUCT_PROPERTIES_PATH)?.let { homePath.resolve(it) }?.takeIf { Files.exists(it) }
|
||||
?: homePath.resolve(PRODUCTS_PROPERTIES_PATH)
|
||||
|
||||
private fun getProductConfiguration(configuration: Configuration, platformPrefix: String): ProductConfiguration {
|
||||
return configuration.products.get(platformPrefix) ?: throw ConfigurationException(
|
||||
"No production configuration for platform prefix `$platformPrefix` please add to `$PRODUCTS_PROPERTIES_PATH` if needed"
|
||||
)
|
||||
}
|
||||
private fun getProductConfiguration(configuration: Configuration, platformPrefix: String): ProductConfiguration =
|
||||
configuration.products[platformPrefix]
|
||||
?: throw ConfigurationException("No production configuration for platform prefix `${platformPrefix}`; please add to `${PRODUCTS_PROPERTIES_PATH}` if needed")
|
||||
|
||||
internal class ConfigurationException(message: String) : RuntimeException(message)
|
||||
|
||||
@@ -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("ReplacePutWithAssignment")
|
||||
|
||||
package org.jetbrains.intellij.build.dev
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashFunnel
|
||||
@@ -58,8 +56,8 @@ data class BuildRequest(
|
||||
@JvmField val platformClassPathConsumer: ((classPath: Set<Path>, runDir: Path) -> Unit)? = null,
|
||||
/**
|
||||
* If `true`, the dev build will include a [runtime module repository](psi_element://com.intellij.platform.runtime.repository).
|
||||
* It's currently used only to run an instance of JetBrains Client from IDE's installation,
|
||||
* and its generation makes build a little longer, so it should be enabled only if needed.
|
||||
* It is currently used only to run an instance of JetBrains Client from IDE's installation,
|
||||
* and its generation makes the project build a little longer, so it should be enabled only if needed.
|
||||
*/
|
||||
@JvmField val generateRuntimeModuleRepository: Boolean = false,
|
||||
|
||||
@@ -84,7 +82,7 @@ data class BuildRequest(
|
||||
internal suspend fun buildProduct(request: BuildRequest, createProductProperties: suspend (CompilationContext) -> ProductProperties): Path {
|
||||
val rootDir = withContext(Dispatchers.IO) {
|
||||
val rootDir = request.devRootDir
|
||||
// if symlinked to ram disk, use a real path for performance reasons and avoid any issues in ant/other code
|
||||
// if symlinked to RAM disk, use a real path for performance reasons and avoid any issues in ant/other code
|
||||
if (Files.exists(rootDir)) {
|
||||
// toRealPath must be called only on an existing file
|
||||
rootDir.toRealPath()
|
||||
@@ -121,14 +119,14 @@ internal suspend fun buildProduct(request: BuildRequest, createProductProperties
|
||||
}
|
||||
|
||||
val runDir = buildDir
|
||||
val context = createBuildContext(createProductProperties = createProductProperties, request = request, runDir = runDir, jarCacheDir = request.jarCacheDir, buildDir = buildDir)
|
||||
val context = createBuildContext(createProductProperties, request, runDir, request.jarCacheDir, buildDir)
|
||||
compileIfNeeded(context)
|
||||
|
||||
coroutineScope {
|
||||
val moduleOutputPatcher = ModuleOutputPatcher()
|
||||
|
||||
val platformLayout = async(CoroutineName("create platform layout")) {
|
||||
createPlatformLayout(context = context)
|
||||
createPlatformLayout(context)
|
||||
}
|
||||
|
||||
val searchableOptionSet = getSearchableOptionSet(context)
|
||||
@@ -139,7 +137,7 @@ internal suspend fun buildProduct(request: BuildRequest, createProductProperties
|
||||
val binDir = Files.createDirectories(runDir.resolve("bin"))
|
||||
val oldFiles = Files.newDirectoryStream(binDir).use { it.toCollection(HashSet()) }
|
||||
|
||||
val osDistributionBuilder = getOsDistributionBuilder(os = OsFamily.currentOs, context = context)
|
||||
val osDistributionBuilder = getOsDistributionBuilder(OsFamily.currentOs, context)
|
||||
if (osDistributionBuilder != null) {
|
||||
oldFiles.remove(osDistributionBuilder.writeVmOptions(binDir))
|
||||
// the file cannot be placed right into the distribution as it throws off home dir detection in `PathManager#getHomeDirFor`
|
||||
@@ -153,21 +151,13 @@ internal suspend fun buildProduct(request: BuildRequest, createProductProperties
|
||||
Files.writeString(ideaPropertyFile, createIdeaPropertyFile(context))
|
||||
oldFiles.remove(ideaPropertyFile)
|
||||
|
||||
if (oldFiles.isNotEmpty()) {
|
||||
for (oldFile in oldFiles) {
|
||||
NioFiles.deleteRecursively(oldFile)
|
||||
}
|
||||
for (oldFile in oldFiles) {
|
||||
NioFiles.deleteRecursively(oldFile)
|
||||
}
|
||||
}
|
||||
|
||||
val (platformDistributionEntries, classPath) = spanBuilder("layout platform").use {
|
||||
layoutPlatform(
|
||||
runDir = runDir,
|
||||
platformLayout = platformLayout.await(),
|
||||
searchableOptionSet = searchableOptionSet,
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
context = context,
|
||||
)
|
||||
layoutPlatform(runDir, platformLayout.await(), searchableOptionSet, context, moduleOutputPatcher)
|
||||
}
|
||||
|
||||
if (request.writeCoreClasspath) {
|
||||
@@ -193,29 +183,20 @@ internal suspend fun buildProduct(request: BuildRequest, createProductProperties
|
||||
}
|
||||
|
||||
val pluginDistributionEntriesDeferred = async(CoroutineName("build plugins")) {
|
||||
buildPlugins(
|
||||
request = request,
|
||||
runDir = runDir,
|
||||
platformLayout = platformLayout,
|
||||
artifactTask = artifactTask,
|
||||
searchableOptionSet = searchableOptionSet,
|
||||
buildPlatformJob = platformDistributionEntriesDeferred,
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
context = context,
|
||||
)
|
||||
buildPlugins(request, context, runDir, platformLayout, artifactTask, searchableOptionSet, platformDistributionEntriesDeferred, moduleOutputPatcher)
|
||||
}
|
||||
|
||||
launch {
|
||||
val (pluginEntries, additionalEntries) = pluginDistributionEntriesDeferred.await()
|
||||
spanBuilder("generate plugin classpath").use(Dispatchers.IO) {
|
||||
val mainData = generatePluginClassPath(pluginEntries = pluginEntries, moduleOutputPatcher = moduleOutputPatcher)
|
||||
val mainData = generatePluginClassPath(pluginEntries, moduleOutputPatcher)
|
||||
val additionalData = additionalEntries?.let { generatePluginClassPathFromPrebuiltPluginFiles(it) }
|
||||
|
||||
val byteOut = ByteArrayOutputStream()
|
||||
val out = DataOutputStream(byteOut)
|
||||
val pluginCount = pluginEntries.size + (additionalEntries?.size ?: 0)
|
||||
platformDistributionEntriesDeferred.join()
|
||||
writePluginClassPathHeader(out = out, isJarOnly = !request.isUnpackedDist, pluginCount = pluginCount, moduleOutputPatcher = moduleOutputPatcher, context = context)
|
||||
writePluginClassPathHeader(out, isJarOnly = !request.isUnpackedDist, pluginCount, moduleOutputPatcher, context)
|
||||
out.write(mainData)
|
||||
additionalData?.let { out.write(it) }
|
||||
out.close()
|
||||
@@ -227,41 +208,33 @@ internal suspend fun buildProduct(request: BuildRequest, createProductProperties
|
||||
launch {
|
||||
val allDistributionEntries = platformDistributionEntriesDeferred.await().asSequence() + pluginDistributionEntriesDeferred.await().first.asSequence().flatMap { it.second }
|
||||
spanBuilder("generate runtime repository").use(Dispatchers.IO) {
|
||||
generateRuntimeModuleRepositoryForDevBuild(entries = allDistributionEntries, targetDirectory = runDir, context = context)
|
||||
generateRuntimeModuleRepositoryForDevBuild(allDistributionEntries, runDir, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
launch {
|
||||
computeIdeFingerprint(
|
||||
platformDistributionEntriesDeferred = platformDistributionEntriesDeferred,
|
||||
pluginDistributionEntriesDeferred = pluginDistributionEntriesDeferred,
|
||||
runDir = runDir,
|
||||
homePath = request.projectDir,
|
||||
)
|
||||
computeIdeFingerprint(platformDistributionEntriesDeferred, pluginDistributionEntriesDeferred, runDir, request.projectDir)
|
||||
}
|
||||
|
||||
launch(Dispatchers.IO) {
|
||||
platformDistributionEntriesDeferred.await() // ensure platform dist files added to the list
|
||||
pluginDistributionEntriesDeferred.await() // ensure plugins dist files added to the list
|
||||
copyDistFiles(context = context, newDir = runDir, os = OsFamily.currentOs, arch = JvmArchitecture.currentJvmArch)
|
||||
copyDistFiles(context, runDir, OsFamily.currentOs, JvmArchitecture.currentJvmArch)
|
||||
}
|
||||
}.invokeOnCompletion {
|
||||
// close debug logging to prevent locking of the output directory on Windows
|
||||
context.messages.close()
|
||||
}
|
||||
.invokeOnCompletion {
|
||||
// close debug logging to prevent locking of output directory on Windows
|
||||
context.messages.close()
|
||||
}
|
||||
return runDir
|
||||
}
|
||||
|
||||
private suspend fun getSearchableOptionSet(context: BuildContext): SearchableOptionSetDescriptor? {
|
||||
return withContext(Dispatchers.IO) {
|
||||
try {
|
||||
readSearchableOptionIndex(context.paths.searchableOptionDir)
|
||||
}
|
||||
catch (_: NoSuchFileException) {
|
||||
null
|
||||
}
|
||||
private suspend fun getSearchableOptionSet(context: BuildContext): SearchableOptionSetDescriptor? = withContext(Dispatchers.IO) {
|
||||
try {
|
||||
readSearchableOptionIndex(context.paths.searchableOptionDir)
|
||||
}
|
||||
catch (_: NoSuchFileException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,7 +375,7 @@ private suspend fun buildPlugins(
|
||||
val pluginRootDir = runDir.resolve("plugins")
|
||||
|
||||
val plugins = getPluginLayoutsByJpsModuleNames(bundledMainModuleNames, context.productProperties.productLayout)
|
||||
.filter { isPluginApplicable(bundledMainModuleNames = bundledMainModuleNames, plugin = it, context = context) }
|
||||
.filter { isPluginApplicable(bundledMainModuleNames, plugin = it, context) }
|
||||
|
||||
withContext(Dispatchers.IO) {
|
||||
Files.createDirectories(pluginRootDir)
|
||||
@@ -410,15 +383,7 @@ private suspend fun buildPlugins(
|
||||
|
||||
artifactTask.join()
|
||||
|
||||
val pluginEntries = buildPlugins(
|
||||
plugins = plugins,
|
||||
platformLayout = platformLayout.await(),
|
||||
searchableOptionSet = searchableOptionSet,
|
||||
pluginRootDir = pluginRootDir,
|
||||
buildPlatformJob = buildPlatformJob,
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
context = context,
|
||||
)
|
||||
val pluginEntries = buildPlugins(plugins, platformLayout.await(), searchableOptionSet, context, pluginRootDir, buildPlatformJob, moduleOutputPatcher)
|
||||
val additionalPlugins = copyAdditionalPlugins(context, pluginRootDir)
|
||||
return pluginEntries to additionalPlugins
|
||||
}
|
||||
@@ -448,7 +413,7 @@ private suspend fun createBuildContext(
|
||||
spanBuilder("create build context").use {
|
||||
// we cannot inject a proper build time as it is a part of resources, so, set to the first day of the current month
|
||||
val options = BuildOptions(
|
||||
jarCacheDir = jarCacheDir,
|
||||
jarCacheDir,
|
||||
buildDateInSeconds = getBuildDateInSeconds(),
|
||||
printFreeSpace = false,
|
||||
validateImplicitPlatformModule = false,
|
||||
@@ -503,8 +468,7 @@ private suspend fun createBuildContext(
|
||||
projectHome = request.projectDir,
|
||||
buildOutputRootEvaluator = { _ -> runDir },
|
||||
setupTracer = false,
|
||||
// will be enabled later in [com.intellij.platform.ide.bootstrap.enableJstack] instead
|
||||
enableCoroutinesDump = false,
|
||||
enableCoroutinesDump = false, // will be enabled later in [com.intellij.platform.ide.bootstrap.enableJstack] instead
|
||||
options = options,
|
||||
customBuildPaths = result,
|
||||
)
|
||||
@@ -519,7 +483,6 @@ private suspend fun createBuildContext(
|
||||
|
||||
val compilationContext = compilationContextDeferred.await()
|
||||
|
||||
// ~1 second
|
||||
val productProperties = async(CoroutineName("create product properties")) {
|
||||
createProductProperties(compilationContext)
|
||||
}
|
||||
@@ -566,8 +529,8 @@ private fun isPluginApplicable(bundledMainModuleNames: Set<String>, plugin: Plug
|
||||
return true
|
||||
}
|
||||
|
||||
return satisfiesBundlingRequirements(plugin = plugin, osFamily = OsFamily.currentOs, arch = JvmArchitecture.currentJvmArch, context = context) ||
|
||||
satisfiesBundlingRequirements(plugin = plugin, osFamily = null, arch = JvmArchitecture.currentJvmArch, context = context)
|
||||
return satisfiesBundlingRequirements(plugin, OsFamily.currentOs, JvmArchitecture.currentJvmArch, context) ||
|
||||
satisfiesBundlingRequirements(plugin, osFamily = null, JvmArchitecture.currentJvmArch, context)
|
||||
}
|
||||
|
||||
internal suspend fun createProductProperties(productConfiguration: ProductConfiguration, compilationContext: CompilationContext, request: BuildRequest): ProductProperties {
|
||||
@@ -618,14 +581,7 @@ private suspend fun layoutPlatform(
|
||||
context: BuildContext,
|
||||
moduleOutputPatcher: ModuleOutputPatcher,
|
||||
): Pair<List<DistributionFileEntry>, Set<Path>> {
|
||||
val entries = layoutPlatformDistribution(
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
targetDirectory = runDir,
|
||||
platform = platformLayout,
|
||||
searchableOptionSet = searchableOptionSet,
|
||||
copyFiles = true,
|
||||
context = context,
|
||||
)
|
||||
val entries = layoutPlatformDistribution(moduleOutputPatcher, runDir, platformLayout, searchableOptionSet, copyFiles = true, context)
|
||||
lateinit var sortedClassPath: Set<Path>
|
||||
coroutineScope {
|
||||
launch {
|
||||
@@ -674,8 +630,5 @@ private fun computeAdditionalModulesFingerprint(additionalModules: List<String>)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getCommunityHomePath(homePath: Path): Path = if (Files.isDirectory(homePath.resolve("community"))) homePath.resolve("community") else homePath
|
||||
|
||||
fun getAdditionalPluginMainModules(): List<String> {
|
||||
return System.getProperty("additional.modules")?.splitToSequence(',')?.map { it.trim() }?.filter { it.isNotEmpty() }?.toList() ?: emptyList()
|
||||
}
|
||||
private fun getCommunityHomePath(homePath: Path): Path =
|
||||
if (Files.isDirectory(homePath.resolve("community"))) homePath.resolve("community") else homePath
|
||||
|
||||
@@ -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", "ReplaceJavaStaticMethodWithKotlinAnalog")
|
||||
|
||||
package org.jetbrains.intellij.build.impl
|
||||
|
||||
import com.dynatrace.hash4j.hashing.HashStream64
|
||||
@@ -43,9 +41,7 @@ class BuildContextImpl internal constructor(
|
||||
override val macDistributionCustomizer: MacDistributionCustomizer?,
|
||||
override val proprietaryBuildTools: ProprietaryBuildTools,
|
||||
override val applicationInfo: ApplicationInfoProperties = ApplicationInfoPropertiesImpl(
|
||||
project = compilationContext.project,
|
||||
productProperties = productProperties,
|
||||
buildOptions = compilationContext.options,
|
||||
compilationContext.project, productProperties, compilationContext.options
|
||||
),
|
||||
@JvmField internal val jarCacheManager: JarCacheManager,
|
||||
) : BuildContext, CompilationContext by compilationContext {
|
||||
@@ -84,7 +80,7 @@ class BuildContextImpl internal constructor(
|
||||
jarCacheManager.cleanup()
|
||||
}
|
||||
|
||||
override var bootClassPathJarNames: List<String> = java.util.List.of(PLATFORM_LOADER_JAR)
|
||||
override var bootClassPathJarNames: List<String> = listOf(PLATFORM_LOADER_JAR)
|
||||
|
||||
override val ideMainClassName: String
|
||||
get() = if (useModularLoader) "com.intellij.platform.runtime.loader.IntellijLoader" else productProperties.mainClassName
|
||||
@@ -118,9 +114,8 @@ class BuildContextImpl internal constructor(
|
||||
options.buildStepsToSkip += productProperties.incompatibleBuildSteps
|
||||
if (!options.buildStepsToSkip.isEmpty()) {
|
||||
Span.current().addEvent(
|
||||
"build steps to be skipped", Attributes.of(
|
||||
AttributeKey.stringArrayKey("stepsToSkip"), java.util.List.copyOf(options.buildStepsToSkip)
|
||||
)
|
||||
"build steps to be skipped",
|
||||
Attributes.of(AttributeKey.stringArrayKey("stepsToSkip"), java.util.List.copyOf(options.buildStepsToSkip))
|
||||
)
|
||||
}
|
||||
if (!options.compatiblePluginsToIgnore.isEmpty()) {
|
||||
@@ -141,12 +136,9 @@ class BuildContextImpl internal constructor(
|
||||
options: BuildOptions = BuildOptions(),
|
||||
): BuildContext {
|
||||
val compilationContext = CompilationContextImpl.createCompilationContext(
|
||||
projectHome = projectHome,
|
||||
setupTracer = setupTracer,
|
||||
buildOutputRootEvaluator = createBuildOutputRootEvaluator(projectHome = projectHome, productProperties = productProperties, buildOptions = options),
|
||||
options = options,
|
||||
projectHome, createBuildOutputRootEvaluator(projectHome, productProperties, options), options, setupTracer
|
||||
)
|
||||
return createContext(compilationContext = compilationContext, projectHome = projectHome, productProperties = productProperties, proprietaryBuildTools = proprietaryBuildTools)
|
||||
return createContext(compilationContext, projectHome, productProperties, proprietaryBuildTools)
|
||||
}
|
||||
|
||||
fun createContext(
|
||||
@@ -278,11 +270,7 @@ class BuildContextImpl internal constructor(
|
||||
options = options,
|
||||
paths = computeBuildPaths(
|
||||
options = options,
|
||||
buildOut = options.outRootDir ?: createBuildOutputRootEvaluator(
|
||||
projectHome = paths.projectHome,
|
||||
productProperties = productProperties,
|
||||
buildOptions = options,
|
||||
)(project),
|
||||
buildOut = options.outRootDir ?: createBuildOutputRootEvaluator(paths.projectHome, productProperties, options)(project),
|
||||
projectHome = paths.projectHome,
|
||||
artifactDir = if (prepareForBuild) {
|
||||
@Suppress("DEPRECATION")
|
||||
@@ -309,7 +297,7 @@ class BuildContextImpl internal constructor(
|
||||
return copy
|
||||
}
|
||||
|
||||
override suspend fun includeBreakGenLibraries() = getBundledPluginModules().contains(JavaPluginLayout.MAIN_MODULE_NAME)
|
||||
override suspend fun includeBreakGenLibraries(): Boolean = getBundledPluginModules().contains(JavaPluginLayout.MAIN_MODULE_NAME)
|
||||
|
||||
override fun patchInspectScript(path: Path) {
|
||||
//todo use placeholder in inspect.sh/inspect.bat file instead
|
||||
@@ -335,35 +323,35 @@ class BuildContextImpl internal constructor(
|
||||
|
||||
if (productProperties.enableCds) {
|
||||
val cacheDir = if (os == OsFamily.WINDOWS) "%IDE_CACHE_DIR%\\" else "\$IDE_CACHE_DIR/"
|
||||
jvmArgs.add("-XX:SharedArchiveFile=${cacheDir}${productProperties.baseFileName}${buildNumber}.jsa")
|
||||
jvmArgs.add("-XX:+AutoCreateSharedArchive")
|
||||
jvmArgs += "-XX:SharedArchiveFile=${cacheDir}${productProperties.baseFileName}${buildNumber}.jsa"
|
||||
jvmArgs += "-XX:+AutoCreateSharedArchive"
|
||||
}
|
||||
else {
|
||||
productProperties.classLoader?.let {
|
||||
jvmArgs.add("-Djava.system.class.loader=${it}")
|
||||
jvmArgs += "-Djava.system.class.loader=${it}"
|
||||
}
|
||||
}
|
||||
|
||||
jvmArgs.add("-Didea.vendor.name=${applicationInfo.shortCompanyName}")
|
||||
jvmArgs.add("-Didea.paths.selector=${systemSelector}")
|
||||
jvmArgs += "-Didea.vendor.name=${applicationInfo.shortCompanyName}"
|
||||
jvmArgs += "-Didea.paths.selector=${systemSelector}"
|
||||
|
||||
jvmArgs.add("-Djna.boot.library.path=${macroName}/lib/jna/${arch.dirName}".let { if (isScript) '"' + it + '"' else it })
|
||||
jvmArgs.add("-Dpty4j.preferred.native.folder=${macroName}/lib/pty4j".let { if (isScript) '"' + it + '"' else it })
|
||||
// require bundled JNA dispatcher lib
|
||||
jvmArgs.add("-Djna.nosys=true")
|
||||
jvmArgs.add("-Djna.noclasspath=true")
|
||||
jvmArgs.add("-Dio.netty.allocator.type=pooled")
|
||||
jvmArgs += "-Djna.boot.library.path=${macroName}/lib/jna/${arch.dirName}".let { if (isScript) '"' + it + '"' else it }
|
||||
jvmArgs += "-Djna.nosys=true"
|
||||
jvmArgs += "-Djna.noclasspath=true"
|
||||
jvmArgs += "-Dpty4j.preferred.native.folder=${macroName}/lib/pty4j".let { if (isScript) '"' + it + '"' else it }
|
||||
jvmArgs += "-Dio.netty.allocator.type=pooled"
|
||||
|
||||
if (useModularLoader || generateRuntimeModuleRepository) {
|
||||
jvmArgs.add("-Dintellij.platform.runtime.repository.path=${macroName}/${MODULE_DESCRIPTORS_JAR_PATH}".let { if (isScript) '"' + it + '"' else it })
|
||||
jvmArgs += "-Dintellij.platform.runtime.repository.path=${macroName}/${MODULE_DESCRIPTORS_JAR_PATH}".let { if (isScript) '"' + it + '"' else it }
|
||||
}
|
||||
if (useModularLoader) {
|
||||
jvmArgs.add("-Dintellij.platform.root.module=${productProperties.rootModuleForModularLoader!!}")
|
||||
jvmArgs.add("-Dintellij.platform.product.mode=${productProperties.productMode.id}")
|
||||
jvmArgs += "-Dintellij.platform.root.module=${productProperties.rootModuleForModularLoader!!}"
|
||||
jvmArgs += "-Dintellij.platform.product.mode=${productProperties.productMode.id}"
|
||||
}
|
||||
|
||||
if (productProperties.platformPrefix != null) {
|
||||
jvmArgs.add("-Didea.platform.prefix=${productProperties.platformPrefix}")
|
||||
jvmArgs += "-Didea.platform.prefix=${productProperties.platformPrefix}"
|
||||
}
|
||||
|
||||
if (os == OsFamily.WINDOWS) {
|
||||
@@ -373,31 +361,31 @@ class BuildContextImpl internal constructor(
|
||||
}
|
||||
}
|
||||
|
||||
jvmArgs.addAll(productProperties.additionalIdeJvmArguments)
|
||||
jvmArgs.addAll(productProperties.getAdditionalContextDependentIdeJvmArguments(this))
|
||||
jvmArgs += productProperties.additionalIdeJvmArguments
|
||||
jvmArgs += productProperties.getAdditionalContextDependentIdeJvmArguments(this)
|
||||
|
||||
if (productProperties.useSplash) {
|
||||
@Suppress("SpellCheckingInspection", "RedundantSuppression")
|
||||
jvmArgs.add("-Dsplash=true")
|
||||
jvmArgs += ("-Dsplash=true")
|
||||
}
|
||||
|
||||
// https://youtrack.jetbrains.com/issue/IDEA-269280
|
||||
jvmArgs.add("-Daether.connector.resumeDownloads=false")
|
||||
jvmArgs += "-Daether.connector.resumeDownloads=false"
|
||||
|
||||
jvmArgs.add("-Dcompose.swing.render.on.graphics=true")
|
||||
jvmArgs += "-Dcompose.swing.render.on.graphics=true"
|
||||
|
||||
jvmArgs.addAll(getCommandLineArgumentsForOpenPackages(this, os))
|
||||
jvmArgs += getCommandLineArgumentsForOpenPackages(context = this, os)
|
||||
|
||||
return jvmArgs
|
||||
}
|
||||
|
||||
override fun addExtraExecutablePattern(os: OsFamily, pattern: String) {
|
||||
extraExecutablePatterns.updateAndGet { prev ->
|
||||
prev.with(os, (prev.get(os) ?: persistentListOf()).add(pattern))
|
||||
prev.with(os, (prev[os] ?: persistentListOf()).add(pattern))
|
||||
}
|
||||
}
|
||||
|
||||
override fun getExtraExecutablePattern(os: OsFamily): List<String> = extraExecutablePatterns.get().get(os) ?: java.util.List.of()
|
||||
override fun getExtraExecutablePattern(os: OsFamily): List<String> = extraExecutablePatterns.get()[os] ?: listOf()
|
||||
|
||||
override suspend fun buildJar(targetFile: Path, sources: List<Source>, compress: Boolean) {
|
||||
jarCacheManager.computeIfAbsent(
|
||||
@@ -420,8 +408,8 @@ class BuildContextImpl internal constructor(
|
||||
)
|
||||
}
|
||||
|
||||
override val appInfoXml by lazy {
|
||||
return@lazy computeAppInfoXml(context = this, appInfo = applicationInfo)
|
||||
override val appInfoXml: String by lazy {
|
||||
computeAppInfoXml(context = this, appInfo = applicationInfo)
|
||||
}
|
||||
|
||||
@OptIn(DelicateCoroutinesApi::class)
|
||||
@@ -462,7 +450,7 @@ class BuildContextImpl internal constructor(
|
||||
|
||||
private fun createBuildOutputRootEvaluator(projectHome: Path, productProperties: ProductProperties, buildOptions: BuildOptions): (JpsProject) -> Path {
|
||||
return { project ->
|
||||
val appInfo = ApplicationInfoPropertiesImpl(project = project, productProperties = productProperties, buildOptions = buildOptions)
|
||||
val appInfo = ApplicationInfoPropertiesImpl(project, productProperties, buildOptions)
|
||||
projectHome.resolve("out/${productProperties.getOutputDirectoryName(appInfo)}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.SystemInfoRt
|
||||
@@ -17,8 +17,8 @@ import org.jetbrains.intellij.build.impl.maven.MavenArtifactData
|
||||
import org.jetbrains.intellij.build.impl.maven.MavenArtifactsBuilder
|
||||
import org.jetbrains.intellij.build.impl.moduleBased.findProductModulesFile
|
||||
import org.jetbrains.intellij.build.impl.productInfo.PRODUCT_INFO_FILE_NAME
|
||||
import org.jetbrains.intellij.build.impl.productInfo.checkInArchive
|
||||
import org.jetbrains.intellij.build.impl.productInfo.generateProductInfoJson
|
||||
import org.jetbrains.intellij.build.impl.productInfo.validateProductJson
|
||||
import org.jetbrains.intellij.build.impl.projectStructureMapping.ContentReport
|
||||
import org.jetbrains.intellij.build.impl.projectStructureMapping.getIncludedModules
|
||||
import org.jetbrains.intellij.build.impl.sbom.SoftwareBillOfMaterialsImpl
|
||||
@@ -83,7 +83,7 @@ internal class BuildTasksImpl(private val context: BuildContextImpl) : BuildTask
|
||||
layoutShared(context)
|
||||
if (includeBinAndRuntime) {
|
||||
val propertiesFile = createIdeaPropertyFile(context)
|
||||
val builder = getOsDistributionBuilder(currentOs, propertiesFile, context)!!
|
||||
val builder = getOsDistributionBuilder(currentOs, context, propertiesFile)!!
|
||||
builder.copyFilesForOsDistribution(targetDirectory, arch)
|
||||
context.bundledRuntime.extractTo(currentOs, targetDirectory.resolve("jbr"), arch)
|
||||
updateExecutablePermissions(targetDirectory, builder.generateExecutableFilesMatchers(includeRuntime = true, arch).keys)
|
||||
@@ -243,7 +243,7 @@ private suspend fun buildOsSpecificDistributions(context: BuildContext): List<Di
|
||||
|
||||
spanBuilder("Adjust executable permissions on common dist").use {
|
||||
val matchers = SUPPORTED_DISTRIBUTIONS.mapNotNull {
|
||||
getOsDistributionBuilder(it.os, null, context)
|
||||
getOsDistributionBuilder(it.os, context)
|
||||
}.flatMap { builder ->
|
||||
JvmArchitecture.entries.flatMap { arch ->
|
||||
builder.generateExecutableFilesMatchers(includeRuntime = true, arch).keys
|
||||
@@ -258,7 +258,7 @@ private suspend fun buildOsSpecificDistributions(context: BuildContext): List<Di
|
||||
return@mapNotNull null
|
||||
}
|
||||
|
||||
val builder = getOsDistributionBuilder(os, ideaPropertyFileContent, context) ?: return@mapNotNull null
|
||||
val builder = getOsDistributionBuilder(os, context, ideaPropertyFileContent) ?: return@mapNotNull null
|
||||
|
||||
val stepId = "${os.osId} ${arch.name}"
|
||||
if (context.options.buildStepsToSkip.contains(stepId)) {
|
||||
@@ -808,7 +808,7 @@ private suspend fun buildCrossPlatformZip(distResults: List<DistributionForOsTas
|
||||
val extraFiles = mapOf("dependencies.txt" to copyDependenciesFile(context))
|
||||
crossPlatformZip(context, distResults, targetFile, executableName, productJson, extraFiles, runtimeModuleRepositoryPath)
|
||||
|
||||
checkInArchive(targetFile, pathInArchive = "", context)
|
||||
validateProductJson(targetFile, pathInArchive = "", context)
|
||||
|
||||
context.notifyArtifactBuilt(targetFile)
|
||||
return targetFile
|
||||
@@ -850,7 +850,7 @@ private fun checkPlatformSpecificPluginResources(pluginLayouts: List<PluginLayou
|
||||
}
|
||||
}
|
||||
|
||||
fun getOsDistributionBuilder(os: OsFamily, ideaProperties: CharSequence? = null, context: BuildContext): OsSpecificDistributionBuilder? = when (os) {
|
||||
fun getOsDistributionBuilder(os: OsFamily, context: BuildContext, ideaProperties: CharSequence? = null): OsSpecificDistributionBuilder? = when (os) {
|
||||
OsFamily.WINDOWS -> context.windowsDistributionCustomizer?.let {
|
||||
WindowsDistributionBuilder(context, customizer = it, ideaProperties)
|
||||
}
|
||||
|
||||
@@ -1,7 +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("ReplaceGetOrSet", "ReplaceNegatedIsEmptyWithIsNotEmpty")
|
||||
@file:OptIn(ExperimentalPathApi::class)
|
||||
|
||||
// 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.diagnostic.COROUTINE_DUMP_HEADER
|
||||
@@ -61,10 +58,8 @@ fun createCompilationContextBlocking(
|
||||
projectHome: Path,
|
||||
defaultOutputRoot: Path,
|
||||
options: BuildOptions = BuildOptions(),
|
||||
): CompilationContextImpl {
|
||||
return runBlocking(Dispatchers.Default) {
|
||||
createCompilationContext(projectHome = projectHome, defaultOutputRoot = defaultOutputRoot, options = options)
|
||||
}
|
||||
): CompilationContextImpl = runBlocking(Dispatchers.Default) {
|
||||
createCompilationContext(projectHome, defaultOutputRoot, options)
|
||||
}
|
||||
|
||||
suspend fun createCompilationContext(
|
||||
@@ -74,15 +69,10 @@ suspend fun createCompilationContext(
|
||||
): CompilationContextImpl {
|
||||
val logDir = options.logDir ?: (options.outRootDir ?: defaultOutputRoot).resolve("log")
|
||||
JaegerJsonSpanExporterManager.setOutput(logDir.toAbsolutePath().normalize().resolve("trace.json"))
|
||||
return CompilationContextImpl.createCompilationContext(
|
||||
projectHome = projectHome,
|
||||
setupTracer = false,
|
||||
buildOutputRootEvaluator = { defaultOutputRoot },
|
||||
options = options,
|
||||
)
|
||||
return CompilationContextImpl.createCompilationContext(projectHome, { defaultOutputRoot }, options, setupTracer = false)
|
||||
}
|
||||
|
||||
internal fun computeBuildPaths(options: BuildOptions, buildOut: Path, artifactDir: Path? = null, projectHome: Path): BuildPaths {
|
||||
internal fun computeBuildPaths(options: BuildOptions, buildOut: Path, projectHome: Path, artifactDir: Path? = null): BuildPaths {
|
||||
val tempDir = buildOut.resolve("temp")
|
||||
val result = BuildPaths(
|
||||
communityHomeDirRoot = COMMUNITY_ROOT,
|
||||
@@ -193,13 +183,9 @@ class CompilationContextImpl private constructor(
|
||||
logFreeDiskSpace(dir = projectHome, phase = "before downloading dependencies")
|
||||
}
|
||||
|
||||
val model = loadProject(
|
||||
projectHome = projectHome,
|
||||
kotlinBinaries = KotlinBinaries(COMMUNITY_ROOT),
|
||||
isCompilationRequired = isCompilationRequired(options),
|
||||
)
|
||||
val model = loadProject(projectHome, KotlinBinaries(COMMUNITY_ROOT), isCompilationRequired(options))
|
||||
|
||||
val buildPaths = customBuildPaths ?: computeBuildPaths(buildOut = options.outRootDir ?: buildOutputRootEvaluator(model.project), options = options, projectHome = projectHome)
|
||||
val buildPaths = customBuildPaths ?: computeBuildPaths(options, options.outRootDir ?: buildOutputRootEvaluator(model.project), projectHome)
|
||||
|
||||
// not as part of prepareForBuild because prepareForBuild may be called several times per each product or another flavor
|
||||
// (see createCopyForProduct)
|
||||
@@ -232,17 +218,8 @@ class CompilationContextImpl private constructor(
|
||||
}
|
||||
}
|
||||
|
||||
override fun createCopy(
|
||||
messages: BuildMessages,
|
||||
options: BuildOptions,
|
||||
paths: BuildPaths,
|
||||
): CompilationContext {
|
||||
val copy = CompilationContextImpl(
|
||||
model = projectModel,
|
||||
messages = messages,
|
||||
paths = paths,
|
||||
options = options,
|
||||
)
|
||||
override fun createCopy(messages: BuildMessages, options: BuildOptions, paths: BuildPaths): CompilationContext {
|
||||
val copy = CompilationContextImpl(projectModel, messages, paths, options)
|
||||
copy.compilationData = compilationData
|
||||
return copy
|
||||
}
|
||||
@@ -256,7 +233,7 @@ class CompilationContextImpl private constructor(
|
||||
Files.newDirectoryStream(logDir).use { stream ->
|
||||
for (file in stream) {
|
||||
if (!file.endsWith("trace.json")) {
|
||||
file.deleteRecursively()
|
||||
NioFiles.deleteRecursively(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -281,7 +258,7 @@ class CompilationContextImpl private constructor(
|
||||
suppressWarnings(project)
|
||||
ConsoleSpanExporter.setPathRoot(paths.buildOutputDir)
|
||||
if (options.cleanOutDir || options.forceRebuild) {
|
||||
cleanOutput(this@CompilationContextImpl, keepCompilationState = keepCompilationState(options))
|
||||
cleanOutput(context = this@CompilationContextImpl, keepCompilationState(options))
|
||||
}
|
||||
else {
|
||||
Span.current().addEvent("skip output cleaning", Attributes.of(
|
||||
@@ -300,7 +277,7 @@ class CompilationContextImpl private constructor(
|
||||
spanBuilder("resolve dependencies and compile modules").use { span ->
|
||||
compileMutex.withReentrantLock {
|
||||
resolveProjectDependencies(this@CompilationContextImpl)
|
||||
reuseOrCompile(context = this@CompilationContextImpl, moduleNames = moduleNames, includingTestsInModules = includingTestsInModules, span = span)
|
||||
reuseOrCompile(context = this@CompilationContextImpl, moduleNames, includingTestsInModules, span)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -325,7 +302,7 @@ class CompilationContextImpl private constructor(
|
||||
return module
|
||||
}
|
||||
|
||||
override fun findModule(name: String): JpsModule? = nameToModule.get(name.removeSuffix("._test"))
|
||||
override fun findModule(name: String): JpsModule? = nameToModule[name.removeSuffix("._test")]
|
||||
|
||||
override suspend fun getModuleOutputDir(module: JpsModule, forTests: Boolean): Path {
|
||||
val url = JpsJavaExtensionService.getInstance().getOutputUrl(/* module = */ module, /* forTests = */ forTests)
|
||||
@@ -345,7 +322,7 @@ class CompilationContextImpl private constructor(
|
||||
|
||||
override suspend fun getModuleRuntimeClasspath(module: JpsModule, forTests: Boolean): List<String> {
|
||||
val enumerator = JpsJavaExtensionService.dependencies(module).recursively()
|
||||
// if a project requires different SDKs, they all shouldn't be added to test classpath
|
||||
// if a project requires different SDKs, they all shouldn't be added to the test classpath
|
||||
.also { if (forTests) it.withoutSdk() }
|
||||
.includedIn(JpsJavaClasspathKind.runtime(forTests))
|
||||
return enumerator.classes().paths.map { it.toString() }
|
||||
@@ -517,16 +494,16 @@ internal suspend fun cleanOutput(context: CompilationContext, keepCompilationSta
|
||||
}
|
||||
|
||||
private fun printEnvironmentDebugInfo() {
|
||||
// print it to the stdout since TeamCity will remove any sensitive fields from build log automatically
|
||||
// print it to the stdout since TeamCity will remove any sensitive fields from the build log automatically
|
||||
// don't write it to a debug log file!
|
||||
val env = System.getenv()
|
||||
for (key in env.keys.sorted()) {
|
||||
println("ENV $key = ${env.get(key)}")
|
||||
println("ENV $key = ${env[key]}")
|
||||
}
|
||||
|
||||
val properties = System.getProperties()
|
||||
for (propertyName in properties.keys.sortedBy { it as String }) {
|
||||
println("PROPERTY $propertyName = ${properties.get(propertyName).toString()}")
|
||||
println("PROPERTY $propertyName = ${properties[propertyName].toString()}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -66,7 +64,7 @@ internal suspend fun buildDistribution(
|
||||
val productRunner = context.createProductRunner()
|
||||
if (context.productProperties.buildDocAuthoringAssets) {
|
||||
launch(CoroutineName("build authoring assets")) {
|
||||
buildAdditionalAuthoringArtifacts(productRunner = productRunner, context = context)
|
||||
buildAdditionalAuthoringArtifacts(productRunner, context)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +72,7 @@ internal suspend fun buildDistribution(
|
||||
val contentReport = coroutineScope {
|
||||
// must be completed before plugin building
|
||||
val searchableOptionSet = context.executeStep(spanBuilder("build searchable options index"), BuildOptions.SEARCHABLE_OPTIONS_INDEX_STEP) {
|
||||
buildSearchableOptions(productRunner = productRunner, context = context)
|
||||
buildSearchableOptions(productRunner, context)
|
||||
}
|
||||
|
||||
val pluginLayouts = getPluginLayoutsByJpsModuleNames(
|
||||
@@ -84,7 +82,7 @@ internal suspend fun buildDistribution(
|
||||
val moduleOutputPatcher = ModuleOutputPatcher()
|
||||
val buildPlatformJob: Deferred<List<DistributionFileEntry>> = async(traceContext + CoroutineName("build platform lib")) {
|
||||
spanBuilder("build platform lib").use {
|
||||
val result = buildLib(moduleOutputPatcher = moduleOutputPatcher, platform = state.platform, searchableOptionSetDescriptor = searchableOptionSet, context = context)
|
||||
val result = buildLib(moduleOutputPatcher, state.platform, searchableOptionSet, context)
|
||||
if (!isUpdateFromSources && context.productProperties.scrambleMainJar) {
|
||||
scramble(state.platform, context)
|
||||
}
|
||||
@@ -94,31 +92,15 @@ internal suspend fun buildDistribution(
|
||||
}
|
||||
|
||||
val buildNonBundledPlugins = async(CoroutineName("build non-bundled plugins")) {
|
||||
buildNonBundledPlugins(
|
||||
pluginsToPublish = state.pluginsToPublish,
|
||||
compressPluginArchive = !isUpdateFromSources && context.options.compressZipFiles,
|
||||
buildPlatformLibJob = buildPlatformJob,
|
||||
state = state,
|
||||
searchableOptionSet = searchableOptionSet,
|
||||
context = context,
|
||||
)
|
||||
val compressPluginArchive = !isUpdateFromSources && context.options.compressZipFiles
|
||||
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 {
|
||||
@@ -127,7 +109,7 @@ internal suspend fun buildDistribution(
|
||||
Files.createDirectories(context.paths.artifactDir)
|
||||
val contentReportFile = context.paths.artifactDir.resolve("content-report.zip")
|
||||
writeNewZipWithoutIndex(contentReportFile) { zipFileWriter ->
|
||||
buildJarContentReport(contentReport = contentReport, zipFileWriter = zipFileWriter, buildPaths = context.paths, context = context)
|
||||
buildJarContentReport(contentReport, zipFileWriter, context.paths, context)
|
||||
}
|
||||
context.notifyArtifactBuilt(contentReportFile)
|
||||
}
|
||||
@@ -152,51 +134,25 @@ private suspend fun buildBundledPluginsForAllPlatforms(
|
||||
searchableOptionSetDescriptor: SearchableOptionSetDescriptor?,
|
||||
moduleOutputPatcher: ModuleOutputPatcher,
|
||||
context: BuildContext,
|
||||
): List<Pair<PluginBuildDescriptor, List<DistributionFileEntry>>> {
|
||||
return coroutineScope {
|
||||
val commonDeferred = async(CoroutineName("build bundled plugins")) {
|
||||
doBuildBundledPlugins(
|
||||
state = state,
|
||||
plugins = pluginLayouts,
|
||||
isUpdateFromSources = isUpdateFromSources,
|
||||
buildPlatformJob = buildPlatformJob,
|
||||
searchableOptionSet = searchableOptionSetDescriptor,
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
context = context,
|
||||
)
|
||||
}
|
||||
): List<Pair<PluginBuildDescriptor, List<DistributionFileEntry>>> = coroutineScope {
|
||||
val commonDeferred = async(CoroutineName("build bundled plugins")) {
|
||||
doBuildBundledPlugins(state, pluginLayouts, isUpdateFromSources, buildPlatformJob, searchableOptionSetDescriptor, moduleOutputPatcher, context)
|
||||
}
|
||||
|
||||
val additionalDeferred = async(CoroutineName("build additional plugins")) {
|
||||
copyAdditionalPlugins(context = context, pluginDir = context.paths.distAllDir.resolve(PLUGINS_DIRECTORY))
|
||||
}
|
||||
val additionalDeferred = async(CoroutineName("build additional plugins")) {
|
||||
copyAdditionalPlugins(context, pluginDir = context.paths.distAllDir.resolve(PLUGINS_DIRECTORY))
|
||||
}
|
||||
|
||||
val pluginDirs = getPluginDirs(context = context, isUpdateFromSources = 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,
|
||||
)
|
||||
}
|
||||
val pluginDirs = getPluginDirs(context, isUpdateFromSources)
|
||||
val specificDeferred = async(CoroutineName("build OS-specific bundled plugins")) {
|
||||
buildOsSpecificBundledPlugins(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,
|
||||
)
|
||||
listOf(common, specific.values.flatten())
|
||||
}.flatten()
|
||||
val common = commonDeferred.await()
|
||||
val specific = specificDeferred.await()
|
||||
buildPlatformJob.join()
|
||||
writePluginInfo(moduleOutputPatcher, pluginDirs, common, specific, additionalDeferred.await(), context)
|
||||
common + specific.values.flatten()
|
||||
}
|
||||
|
||||
private fun writePluginInfo(
|
||||
@@ -207,23 +163,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(relativePath = PLUGIN_CLASSPATH, content = InMemoryDistFileContent(byteOut.toByteArray()), os = supportedDist.os, arch = supportedDist.arch))
|
||||
context.addDistFile(DistFile(InMemoryDistFileContent(byteOut.toByteArray()), PLUGIN_CLASSPATH, supportedDist.os, supportedDist.arch))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,16 +192,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) to context.paths.distAllDir.resolve(PLUGINS_DIRECTORY))
|
||||
listOf(SupportedDistribution(OsFamily.currentOs, JvmArchitecture.currentJvmArch) to context.paths.distAllDir.resolve(PLUGINS_DIRECTORY))
|
||||
}
|
||||
else {
|
||||
return SUPPORTED_DISTRIBUTIONS.map {
|
||||
it to getOsAndArchSpecificDistDirectory(osFamily = it.os, arch = it.arch, context = context).resolve(PLUGINS_DIRECTORY)
|
||||
SUPPORTED_DISTRIBUTIONS.map {
|
||||
it to getOsAndArchSpecificDistDirectory(it.os, it.arch, context).resolve(PLUGINS_DIRECTORY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun buildBundledPlugins(
|
||||
state: DistributionBuilderState,
|
||||
@@ -256,15 +211,7 @@ suspend fun buildBundledPlugins(
|
||||
moduleOutputPatcher: ModuleOutputPatcher,
|
||||
context: BuildContext,
|
||||
) {
|
||||
doBuildBundledPlugins(
|
||||
state = state,
|
||||
plugins = plugins,
|
||||
isUpdateFromSources = isUpdateFromSources,
|
||||
buildPlatformJob = buildPlatformJob,
|
||||
searchableOptionSet = searchableOptionSetDescriptor,
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
context = context,
|
||||
)
|
||||
doBuildBundledPlugins(state, plugins, isUpdateFromSources, buildPlatformJob, searchableOptionSetDescriptor, moduleOutputPatcher, context)
|
||||
}
|
||||
|
||||
private suspend fun doBuildBundledPlugins(
|
||||
@@ -288,21 +235,12 @@ private suspend fun doBuildBundledPlugins(
|
||||
// doesn't make sense to require passing here a list with a stable order (unnecessary complication, sorting by main module is enough)
|
||||
pluginsToBundle.sortWith(PLUGIN_LAYOUT_COMPARATOR_BY_MAIN_MODULE)
|
||||
val targetDir = context.paths.distAllDir.resolve(PLUGINS_DIRECTORY)
|
||||
val entries = buildPlugins(
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
plugins = pluginsToBundle,
|
||||
targetDir = targetDir,
|
||||
state = state,
|
||||
context = context,
|
||||
buildPlatformJob = buildPlatformJob,
|
||||
os = null,
|
||||
searchableOptionSet = searchableOptionSet,
|
||||
)
|
||||
val entries = buildPlugins(moduleOutputPatcher, pluginsToBundle, os = null, targetDir, state, context, buildPlatformJob, searchableOptionSet)
|
||||
|
||||
buildPlatformSpecificPluginResources(
|
||||
plugins = pluginsToBundle.filter { it.platformResourceGenerators.isNotEmpty() },
|
||||
targetDirs = getPluginDirs(context, isUpdateFromSources),
|
||||
context = context,
|
||||
context,
|
||||
)
|
||||
|
||||
entries
|
||||
@@ -327,12 +265,12 @@ private suspend fun buildOsSpecificBundledPlugins(
|
||||
.use {
|
||||
pluginDirs.mapNotNull { (dist, targetDir) ->
|
||||
val (os, arch) = dist
|
||||
if (arch != currentArch || !context.shouldBuildDistributionForOS(os = os, arch = arch)) {
|
||||
if (arch != currentArch || !context.shouldBuildDistributionForOS(os, arch)) {
|
||||
return@mapNotNull null
|
||||
}
|
||||
|
||||
val osSpecificPlugins = plugins.filter {
|
||||
satisfiesBundlingRequirements(plugin = it, osFamily = os, arch = arch, context = context)
|
||||
satisfiesBundlingRequirements(plugin = it, os, arch, context)
|
||||
}
|
||||
if (osSpecificPlugins.isEmpty()) {
|
||||
return@mapNotNull null
|
||||
@@ -345,16 +283,7 @@ private suspend fun buildOsSpecificBundledPlugins(
|
||||
.setAttribute("count", osSpecificPlugins.size.toLong())
|
||||
.setAttribute("outDir", targetDir.toString())
|
||||
.use {
|
||||
buildPlugins(
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
plugins = osSpecificPlugins,
|
||||
targetDir = targetDir,
|
||||
state = state,
|
||||
context = context,
|
||||
os = os,
|
||||
buildPlatformJob = buildPlatformJob,
|
||||
searchableOptionSet = searchableOptionSet,
|
||||
)
|
||||
buildPlugins(moduleOutputPatcher, osSpecificPlugins, os, targetDir, state, context, buildPlatformJob, searchableOptionSet)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -398,12 +327,12 @@ internal suspend fun buildNonBundledPlugins(
|
||||
return@executeStep emptyList()
|
||||
}
|
||||
|
||||
var buildKeymapPluginsTask = if (context.options.buildStepsToSkip.contains(BuildOptions.KEYMAP_PLUGINS_STEP)) {
|
||||
val buildKeymapPluginsTask = if (context.options.buildStepsToSkip.contains(BuildOptions.KEYMAP_PLUGINS_STEP)) {
|
||||
null
|
||||
}
|
||||
else {
|
||||
async(CoroutineName("build keymap plugins")) {
|
||||
buildKeymapPlugins(targetDir = context.nonBundledPluginsToBePublished, context = context)
|
||||
buildKeymapPlugins(targetDir = context.nonBundledPluginsToBePublished, context)
|
||||
}
|
||||
}
|
||||
val moduleOutputPatcher = ModuleOutputPatcher()
|
||||
@@ -413,18 +342,11 @@ internal suspend fun buildNonBundledPlugins(
|
||||
|
||||
// buildPlugins pluginBuilt listener is called concurrently
|
||||
val pluginSpecs = ConcurrentLinkedQueue<PluginRepositorySpec>()
|
||||
val prepareCustomPluginRepository = context.productProperties.productLayout.prepareCustomPluginRepositoryForPublishedPlugins &&
|
||||
!context.isStepSkipped(BuildOptions.ARCHIVE_PLUGINS)
|
||||
val mappings = buildPlugins(
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
plugins = pluginsToPublish.sortedWith(PLUGIN_LAYOUT_COMPARATOR_BY_MAIN_MODULE),
|
||||
targetDir = stageDir,
|
||||
state = state,
|
||||
searchableOptionSet = searchableOptionSet,
|
||||
context = context,
|
||||
buildPlatformJob = buildPlatformLibJob,
|
||||
os = null,
|
||||
) { plugin, pluginDirOrFile ->
|
||||
val prepareCustomPluginRepository =
|
||||
context.productProperties.productLayout.prepareCustomPluginRepositoryForPublishedPlugins &&
|
||||
!context.isStepSkipped(BuildOptions.ARCHIVE_PLUGINS)
|
||||
val plugins = pluginsToPublish.sortedWith(PLUGIN_LAYOUT_COMPARATOR_BY_MAIN_MODULE)
|
||||
val mappings = buildPlugins(moduleOutputPatcher, plugins, os = null, stageDir, state, context, buildPlatformLibJob, searchableOptionSet) { plugin, pluginDirOrFile ->
|
||||
val pluginVersion = if (plugin.mainModule == BUILT_IN_HELP_MODULE_NAME) {
|
||||
context.buildNumber
|
||||
}
|
||||
@@ -432,7 +354,7 @@ internal suspend fun buildNonBundledPlugins(
|
||||
plugin.versionEvaluator.evaluate(
|
||||
pluginXmlSupplier = { (context as BuildContextImpl).jarPackagerDependencyHelper.getPluginXmlContent(context.findRequiredModule(plugin.mainModule)) },
|
||||
ideBuildVersion = context.pluginBuildNumber,
|
||||
context = context,
|
||||
context,
|
||||
).pluginVersion
|
||||
}
|
||||
|
||||
@@ -447,19 +369,11 @@ internal suspend fun buildNonBundledPlugins(
|
||||
dirToJar.add(NonBundledPlugin(sourceDir = pluginDirOrFile, targetZip = destFile, optimizedZip = !plugin.enableSymlinksAndExecutableResources))
|
||||
}
|
||||
|
||||
archivePlugins(items = dirToJar, compress = compressPluginArchive, withBlockMap = compressPluginArchive, context = context)
|
||||
archivePlugins(items = dirToJar, compress = compressPluginArchive, withBlockMap = compressPluginArchive, context)
|
||||
|
||||
val helpPlugin = buildHelpPlugin(pluginVersion = context.pluginBuildNumber, context = context)
|
||||
val helpPlugin = buildHelpPlugin(pluginVersion = context.pluginBuildNumber, context)
|
||||
if (helpPlugin != null) {
|
||||
val spec = buildHelpPlugin(
|
||||
helpPlugin = helpPlugin,
|
||||
pluginsToPublishDir = stageDir,
|
||||
targetDir = context.nonBundledPluginsToBePublished,
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
state = state,
|
||||
searchableOptionSetDescriptor = searchableOptionSet,
|
||||
context = context,
|
||||
)
|
||||
val spec = buildHelpPlugin(helpPlugin, stageDir, context.nonBundledPluginsToBePublished, moduleOutputPatcher, state, searchableOptionSet, context)
|
||||
pluginSpecs.add(spec)
|
||||
}
|
||||
|
||||
@@ -496,7 +410,7 @@ private suspend fun validatePlugins(context: BuildContext, pluginSpecs: Collecti
|
||||
continue
|
||||
}
|
||||
launch(CoroutineName("$path plugin validation")) {
|
||||
validatePlugin(file = path, context = context, span = span)
|
||||
validatePlugin(path, context, span)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -514,10 +428,8 @@ private fun validatePlugin(file: Path, context: BuildContext, span: Span) {
|
||||
if (problems.isNotEmpty()) {
|
||||
span.addEvent("failed", Attributes.of(AttributeKey.stringKey("path"), "$file"))
|
||||
context.messages.reportBuildProblem(
|
||||
problems.joinToString(
|
||||
prefix = "${id ?: file}: ",
|
||||
separator = ". ",
|
||||
), identity = "${id ?: file}"
|
||||
description = problems.joinToString(". ", prefix = "${id ?: file}: "),
|
||||
identity = "${id ?: file}"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -534,17 +446,9 @@ private suspend fun buildHelpPlugin(
|
||||
val directory = helpPlugin.directoryName
|
||||
val destFile = targetDir.resolve("$directory.zip")
|
||||
spanBuilder("build help plugin").setAttribute("dir", directory).use {
|
||||
buildPlugins(
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
plugins = listOf(helpPlugin),
|
||||
targetDir = pluginsToPublishDir.resolve(directory),
|
||||
state = state,
|
||||
context = context,
|
||||
searchableOptionSet = searchableOptionSetDescriptor,
|
||||
buildPlatformJob = null,
|
||||
os = null,
|
||||
)
|
||||
zipWithCompression(targetFile = destFile, dirs = mapOf(pluginsToPublishDir.resolve(directory) to ""))
|
||||
val targetDir = pluginsToPublishDir.resolve(directory)
|
||||
buildPlugins(moduleOutputPatcher, listOf(helpPlugin), os = null, targetDir, state, context, buildPlatformJob = null, searchableOptionSetDescriptor)
|
||||
zipWithCompression(targetFile = destFile, dirs = mapOf(targetDir to ""))
|
||||
null
|
||||
}
|
||||
return PluginRepositorySpec(pluginZip = destFile, pluginXml = moduleOutputPatcher.getPatchedPluginXml(helpPlugin.mainModule))
|
||||
@@ -555,12 +459,12 @@ internal suspend fun generateProjectStructureMapping(platformLayout: PlatformLay
|
||||
val moduleOutputPatcher = ModuleOutputPatcher()
|
||||
val libDirLayout = async(CoroutineName("layout platform distribution")) {
|
||||
layoutPlatformDistribution(
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
moduleOutputPatcher,
|
||||
targetDirectory = context.paths.distAllDir,
|
||||
platform = platformLayout,
|
||||
context = context,
|
||||
searchableOptionSet = null,
|
||||
copyFiles = false,
|
||||
context,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -570,17 +474,17 @@ internal suspend fun generateProjectStructureMapping(platformLayout: PlatformLay
|
||||
)
|
||||
val entries = mutableListOf<Pair<PluginBuildDescriptor, List<DistributionFileEntry>>>()
|
||||
for (plugin in allPlugins) {
|
||||
if (satisfiesBundlingRequirements(plugin = plugin, osFamily = null, arch = null, context = context)) {
|
||||
if (satisfiesBundlingRequirements(plugin, osFamily = null, arch = null, context)) {
|
||||
val targetDirectory = context.paths.distAllDir.resolve(PLUGINS_DIRECTORY).resolve(plugin.directoryName)
|
||||
entries.add(PluginBuildDescriptor(dir = targetDirectory, layout = plugin, os = null, moduleNames = emptyList()) to layoutDistribution(
|
||||
layout = plugin,
|
||||
platformLayout = platformLayout,
|
||||
targetDirectory = targetDirectory,
|
||||
platformLayout,
|
||||
targetDirectory,
|
||||
copyFiles = false,
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
moduleOutputPatcher,
|
||||
includedModules = plugin.includedModules,
|
||||
searchableOptionSet = null,
|
||||
context = context,
|
||||
context,
|
||||
).first)
|
||||
}
|
||||
}
|
||||
@@ -609,16 +513,16 @@ 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,
|
||||
moduleOutputPatcher,
|
||||
plugin,
|
||||
context.applicationInfo.majorReleaseDate,
|
||||
context.applicationInfo.releaseVersionForLicensing,
|
||||
state.pluginsToPublish,
|
||||
helper = (context as BuildContextImpl).jarPackagerDependencyHelper,
|
||||
platformLayout = state.platform,
|
||||
context = context,
|
||||
context,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -631,10 +535,10 @@ internal suspend fun buildPlugins(
|
||||
platformLayout = state.platform,
|
||||
targetDirectory = pluginDir,
|
||||
copyFiles = true,
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
includedModules = plugin.includedModules,
|
||||
searchableOptionSet = searchableOptionSet,
|
||||
context = context,
|
||||
moduleOutputPatcher,
|
||||
plugin.includedModules,
|
||||
searchableOptionSet,
|
||||
context,
|
||||
)
|
||||
pluginBuilt?.invoke(plugin, file)
|
||||
entries
|
||||
@@ -651,11 +555,11 @@ internal suspend fun buildPlugins(
|
||||
}
|
||||
else {
|
||||
// we cannot start executing right now because the plugin can use other plugins in a scramble classpath
|
||||
scrambleTasks.add(ScrambleTask(plugin = plugin, pluginDir = pluginDir, targetDir = targetDir))
|
||||
scrambleTasks.add(ScrambleTask(plugin, pluginDir, targetDir))
|
||||
}
|
||||
}
|
||||
|
||||
PluginBuildDescriptor(dir = pluginDir, layout = plugin, os = os, moduleNames = emptyList()) to task.await()
|
||||
PluginBuildDescriptor(pluginDir, os, layout = plugin, moduleNames = emptyList()) to task.await()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -674,7 +578,7 @@ internal suspend fun buildPlugins(
|
||||
targetDir = scrambleTask.pluginDir,
|
||||
additionalPluginDir = scrambleTask.targetDir,
|
||||
layouts = plugins,
|
||||
context = context,
|
||||
context,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -752,14 +656,8 @@ suspend fun buildLib(
|
||||
searchableOptionSetDescriptor: SearchableOptionSetDescriptor?,
|
||||
context: BuildContext,
|
||||
): List<DistributionFileEntry> {
|
||||
val libDirMappings = layoutPlatformDistribution(
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
targetDirectory = context.paths.distAllDir,
|
||||
platform = platform,
|
||||
copyFiles = true,
|
||||
searchableOptionSet = searchableOptionSetDescriptor,
|
||||
context = context,
|
||||
)
|
||||
val targetDirectory = context.paths.distAllDir
|
||||
val libDirMappings = layoutPlatformDistribution(moduleOutputPatcher, targetDirectory, platform, searchableOptionSetDescriptor, copyFiles = true, context)
|
||||
context.proprietaryBuildTools.scrambleTool?.validatePlatformLayout(platform.includedModules, context)
|
||||
return libDirMappings
|
||||
}
|
||||
@@ -774,9 +672,9 @@ suspend fun layoutPlatformDistribution(
|
||||
): List<DistributionFileEntry> {
|
||||
if (copyFiles) {
|
||||
coroutineScope {
|
||||
createStatisticsRecorderBundledMetadataProviderTask(moduleOutputPatcher = moduleOutputPatcher, context = context)
|
||||
createStatisticsRecorderBundledMetadataProviderTask(moduleOutputPatcher, context)
|
||||
launch(CoroutineName("patch keymap with Alt click reassigned to multiple carets")) {
|
||||
patchKeyMapWithAltClickReassignedToMultipleCarets(moduleOutputPatcher = moduleOutputPatcher, context = context)
|
||||
patchKeyMapWithAltClickReassignedToMultipleCarets(moduleOutputPatcher, context)
|
||||
}
|
||||
launch(CoroutineName("write patched app info")) {
|
||||
spanBuilder("write patched app info").use {
|
||||
@@ -793,16 +691,8 @@ suspend fun layoutPlatformDistribution(
|
||||
return spanBuilder("layout lib")
|
||||
.setAttribute("path", targetDirectory.toString())
|
||||
.use {
|
||||
layoutDistribution(
|
||||
layout = platform,
|
||||
platformLayout = platform,
|
||||
targetDirectory = targetDirectory,
|
||||
copyFiles = copyFiles,
|
||||
moduleOutputPatcher = moduleOutputPatcher,
|
||||
includedModules = platform.includedModules,
|
||||
searchableOptionSet = searchableOptionSet,
|
||||
context = context,
|
||||
).first
|
||||
layoutDistribution(layout = platform, platformLayout = platform, targetDirectory, copyFiles, moduleOutputPatcher, platform.includedModules, searchableOptionSet, context)
|
||||
.first
|
||||
}
|
||||
}
|
||||
|
||||
@@ -838,7 +728,7 @@ private suspend fun checkOutputOfPluginModules(
|
||||
moduleName = module,
|
||||
filePath = "com/intellij/uiDesigner/core/GridLayoutManager.class",
|
||||
excludes = moduleExcludes[module] ?: emptyList(),
|
||||
context = context,
|
||||
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 " +
|
||||
@@ -968,7 +858,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() }
|
||||
@@ -994,7 +884,7 @@ suspend fun layoutDistribution(
|
||||
}
|
||||
}
|
||||
|
||||
// patchers must be executed _before_ pack because patcher patches module output
|
||||
// patchers must be executed _before_ packing, because patchers patch the module output
|
||||
val patchers = layout.patchers
|
||||
if (!patchers.isEmpty()) {
|
||||
spanBuilder("execute custom patchers").setAttribute("count", patchers.size.toLong()).use {
|
||||
@@ -1012,8 +902,8 @@ suspend fun layoutDistribution(
|
||||
tasks.add(async(CoroutineName("pack $outputDir")) {
|
||||
spanBuilder("pack").setAttribute("outputDir", outputDir.toString()).use {
|
||||
JarPackager.pack(
|
||||
includedModules = includedModules,
|
||||
outputDir = outputDir,
|
||||
includedModules,
|
||||
outputDir,
|
||||
isRootDir = layout is PlatformLayout,
|
||||
layout = layout,
|
||||
platformLayout = platformLayout,
|
||||
@@ -1025,12 +915,14 @@ suspend fun layoutDistribution(
|
||||
}
|
||||
})
|
||||
|
||||
if (copyFiles &&
|
||||
!context.options.skipCustomResourceGenerators &&
|
||||
(layout.resourcePaths.isNotEmpty() || layout is PluginLayout && !layout.resourceGenerators.isEmpty())) {
|
||||
if (
|
||||
copyFiles &&
|
||||
!context.options.skipCustomResourceGenerators &&
|
||||
(layout.resourcePaths.isNotEmpty() || layout is PluginLayout && !layout.resourceGenerators.isEmpty())
|
||||
) {
|
||||
tasks.add(async(Dispatchers.IO + CoroutineName("pack additional resources")) {
|
||||
spanBuilder("pack additional resources").use {
|
||||
layoutAdditionalResources(layout = layout, context = context, targetDirectory = targetDirectory)
|
||||
layoutAdditionalResources(layout, context, targetDirectory)
|
||||
emptyList()
|
||||
}
|
||||
})
|
||||
@@ -1039,7 +931,7 @@ suspend fun layoutDistribution(
|
||||
if (!layout.includedArtifacts.isEmpty()) {
|
||||
tasks.add(async(CoroutineName("pack artifacts")) {
|
||||
spanBuilder("pack artifacts").use {
|
||||
layoutArtifacts(layout = layout, context = context, copyFiles = copyFiles, targetDirectory = targetDirectory)
|
||||
layoutArtifacts(layout, context, copyFiles, targetDirectory)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1051,7 +943,7 @@ suspend fun layoutDistribution(
|
||||
|
||||
private fun layoutResourcePaths(layout: BaseLayout, context: BuildContext, targetDirectory: Path, overwrite: Boolean) {
|
||||
for (resourceData in layout.resourcePaths) {
|
||||
val source = basePath(buildContext = context, moduleName = resourceData.moduleName).resolve(resourceData.resourcePath).normalize()
|
||||
val source = basePath(context, resourceData.moduleName).resolve(resourceData.resourcePath).normalize()
|
||||
var target = targetDirectory.resolve(resourceData.relativeOutputPath).normalize()
|
||||
if (resourceData.packToZip) {
|
||||
if (Files.isDirectory(source)) {
|
||||
@@ -1076,12 +968,12 @@ private fun layoutResourcePaths(layout: BaseLayout, context: BuildContext, targe
|
||||
}
|
||||
else {
|
||||
if (overwrite) {
|
||||
copyDir(sourceDir = source, targetDir = target, fileFilter = Predicate {
|
||||
copyDir(source, target, fileFilter = Predicate {
|
||||
copyIfChanged(target, source, it)
|
||||
})
|
||||
}
|
||||
else {
|
||||
copyDir(sourceDir = source, targetDir = target)
|
||||
copyDir(source, target)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1107,7 +999,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 = overwrite)
|
||||
if (layout !is PluginLayout) {
|
||||
return
|
||||
}
|
||||
@@ -1156,7 +1048,7 @@ private suspend fun layoutArtifacts(layout: BaseLayout,
|
||||
}
|
||||
}
|
||||
}
|
||||
addArtifactMapping(artifact = artifact, entries = entries, artifactFile = artifactPath)
|
||||
addArtifactMapping(artifact, entries, artifactPath)
|
||||
}
|
||||
return entries
|
||||
}
|
||||
@@ -1231,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 {
|
||||
@@ -1245,7 +1137,7 @@ private suspend fun archivePlugins(items: Collection<NonBundledPlugin>, compress
|
||||
|
||||
private fun archivePlugin(optimized: Boolean, target: Path, compress: Boolean, source: Path, context: BuildContext) {
|
||||
if (optimized) {
|
||||
writeNewZipWithoutIndex(target, compress = compress) { zipCreator ->
|
||||
writeNewZipWithoutIndex(target, compress) { zipCreator ->
|
||||
ZipArchiver(zipCreator).use { archiver ->
|
||||
if (Files.isDirectory(source)) {
|
||||
archiver.setRootDir(source, source.fileName.toString())
|
||||
@@ -1260,7 +1152,7 @@ private fun archivePlugin(optimized: Boolean, target: Path, compress: Boolean, s
|
||||
}
|
||||
else {
|
||||
writeNewFile(target) { outFileChannel ->
|
||||
NoDuplicateZipArchiveOutputStream(outFileChannel, compress = context.options.compressZipFiles).use { out ->
|
||||
NoDuplicateZipArchiveOutputStream(outFileChannel, context.options.compressZipFiles).use { out ->
|
||||
out.setUseZip64(Zip64Mode.Never)
|
||||
out.dir(source, "${source.fileName}/", entryCustomizer = { entry, file, _ ->
|
||||
if (Files.isExecutable(file)) {
|
||||
@@ -1273,7 +1165,7 @@ private fun archivePlugin(optimized: Boolean, target: Path, compress: Boolean, s
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a blockmap and hash files for plugin to provide downloading plugins via incremental downloading algorithm Blockmap.
|
||||
* Builds a blockmap and hash files for a plugin.
|
||||
*/
|
||||
private fun buildBlockMap(file: Path, json: JSON) {
|
||||
val algorithm = "SHA-256"
|
||||
@@ -1312,8 +1204,8 @@ private fun sortEntries(unsorted: List<DistributionFileEntry>): List<Distributio
|
||||
// also, put libraries from Maven repo ahead of others, for them to not depend on the lexicographical order of Maven repo and source path
|
||||
private fun isFromLocalMavenRepo(path: Path) = path.startsWith(MAVEN_REPO)
|
||||
|
||||
suspend fun createIdeClassPath(platform: PlatformLayout, context: BuildContext): Collection<String> {
|
||||
val contentReport = generateProjectStructureMapping(context = context, platformLayout = platform)
|
||||
suspend fun createIdeClassPath(platformLayout: PlatformLayout, context: BuildContext): Collection<String> {
|
||||
val contentReport = generateProjectStructureMapping(platformLayout, context)
|
||||
|
||||
val pluginLayouts = context.productProperties.productLayout.pluginLayouts
|
||||
val classPath = LinkedHashSet<Path>()
|
||||
@@ -1339,7 +1231,7 @@ suspend fun createIdeClassPath(platform: PlatformLayout, context: BuildContext):
|
||||
val pluginDir = context.paths.distAllDir.resolve(PLUGINS_DIRECTORY)
|
||||
for (entry in contentReport.bundledPlugins.flatMap { it.second }) {
|
||||
val relativePath = pluginDir.relativize(entry.path)
|
||||
// for plugins, our classloader load jars only from lib folder
|
||||
// for plugins, our classloader load JARs only from the "lib/" directory
|
||||
if (relativePath.nameCount != 3 || relativePath.getName(1).toString() != LIB_DIRECTORY) {
|
||||
continue
|
||||
}
|
||||
@@ -1352,8 +1244,7 @@ suspend fun createIdeClassPath(platform: PlatformLayout, context: BuildContext):
|
||||
}
|
||||
}
|
||||
is LibraryFileEntry -> classPath.add(entry.libraryFile!!)
|
||||
is CustomAssetEntry -> {
|
||||
}
|
||||
is CustomAssetEntry -> { }
|
||||
else -> throw UnsupportedOperationException("Entry $entry is not supported")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ class LinuxDistributionBuilder(
|
||||
.use(Dispatchers.IO) {
|
||||
val executableFileMatchers = generateExecutableFilesMatchers(includeRuntime = runtimeDir != null, arch).keys
|
||||
tar(tarPath, tarRoot, dirs, executableFileMatchers, context.options.buildDateInSeconds)
|
||||
checkInArchive(tarPath, tarRoot, context)
|
||||
validateProductJson(tarPath, tarRoot, context)
|
||||
context.notifyArtifactBuilt(tarPath)
|
||||
checkExecutablePermissions(tarPath, rootDirectoryName, includeRuntime = runtimeDir != null, arch)
|
||||
}
|
||||
@@ -271,7 +271,7 @@ class LinuxDistributionBuilder(
|
||||
val productJsonDir = context.paths.tempDir.resolve("linux.dist.snap.product-info.json.$architecture")
|
||||
val productJsonFile = writeProductJsonFile(productJsonDir, arch)
|
||||
val installationDirectories = listOf(context.paths.distAllDir, unixDistPath, runtimeDir)
|
||||
validateProductJson(jsonText = productJsonFile.readText(), relativePathToProductJson = "", installationDirectories, installationArchives = emptyList(), context)
|
||||
validateProductJson(jsonText = productJsonFile.readText(), installationDirectories, installationArchives = emptyList(), context)
|
||||
val resultDir = snapDir.resolve("result")
|
||||
Files.createDirectories(resultDir)
|
||||
|
||||
|
||||
@@ -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.SystemInfoRt
|
||||
@@ -142,7 +142,7 @@ class MacDistributionBuilder(
|
||||
val extraFiles = context.getDistFiles(os = OsFamily.MACOS, arch)
|
||||
val directories = listOf(context.paths.distAllDir, osAndArchSpecificDistPath, runtimeDir)
|
||||
val builder = this@MacDistributionBuilder
|
||||
val productJson = generateProductJson(context, arch = arch, withRuntime = true)
|
||||
val productJson = generateProductJson(context, arch, withRuntime = true)
|
||||
buildMacZip(
|
||||
macDistributionBuilder = builder,
|
||||
targetFile = macZip,
|
||||
@@ -161,7 +161,7 @@ class MacDistributionBuilder(
|
||||
targetFile = macZipWithoutRuntime,
|
||||
zipRoot = zipRoot,
|
||||
arch = arch,
|
||||
productJson = generateProductJson(context, arch = arch, withRuntime = false),
|
||||
productJson = generateProductJson(context, arch, withRuntime = false),
|
||||
directories = directories.filterNot { it == runtimeDir },
|
||||
extraFiles = extraFiles,
|
||||
includeRuntime = false,
|
||||
@@ -344,29 +344,29 @@ class MacDistributionBuilder(
|
||||
|
||||
override fun isRuntimeBundled(file: Path): Boolean = !file.name.contains(NO_RUNTIME_SUFFIX)
|
||||
|
||||
private suspend fun generateProductJson(context: BuildContext, arch: JvmArchitecture, withRuntime: Boolean): String =
|
||||
generateProductInfoJson(
|
||||
relativePathToBin = "../bin",
|
||||
builtinModules = context.builtinModule,
|
||||
launch = listOf(createProductInfoLaunchData(context, arch, withRuntime)),
|
||||
context
|
||||
)
|
||||
|
||||
private suspend fun createProductInfoLaunchData(context: BuildContext, arch: JvmArchitecture, withRuntime: Boolean): ProductInfoLaunchData {
|
||||
private suspend fun generateProductJson(context: BuildContext, arch: JvmArchitecture, withRuntime: Boolean): String {
|
||||
val embeddedFrontendLaunchData = generateEmbeddedFrontendLaunchData(arch, OsFamily.MACOS, context) {
|
||||
"../bin/${it.productProperties.baseFileName}.vmoptions"
|
||||
}
|
||||
val qodanaCustomLaunchData = generateQodanaLaunchData(context, arch, OsFamily.MACOS)
|
||||
return ProductInfoLaunchData.create(
|
||||
OsFamily.MACOS.osName,
|
||||
arch.dirName,
|
||||
launcherPath = "../MacOS/${context.productProperties.baseFileName}",
|
||||
javaExecutablePath = if (withRuntime) "../jbr/Contents/Home/bin/java" else null,
|
||||
vmOptionsFilePath = "../bin/${context.productProperties.baseFileName}.vmoptions",
|
||||
bootClassPathJarNames = context.bootClassPathJarNames,
|
||||
additionalJvmArguments = context.getAdditionalJvmArguments(OsFamily.MACOS, arch),
|
||||
mainClass = context.ideMainClassName,
|
||||
customCommands = listOfNotNull(embeddedFrontendLaunchData, qodanaCustomLaunchData)
|
||||
return generateProductInfoJson(
|
||||
relativePathToBin = "../bin",
|
||||
builtinModules = context.builtinModule,
|
||||
launch = listOf(
|
||||
ProductInfoLaunchData.create(
|
||||
OsFamily.MACOS.osName,
|
||||
arch.dirName,
|
||||
launcherPath = "../MacOS/${context.productProperties.baseFileName}",
|
||||
javaExecutablePath = if (withRuntime) "../jbr/Contents/Home/bin/java" else null,
|
||||
vmOptionsFilePath = "../bin/${context.productProperties.baseFileName}.vmoptions",
|
||||
bootClassPathJarNames = context.bootClassPathJarNames,
|
||||
additionalJvmArguments = context.getAdditionalJvmArguments(OsFamily.MACOS, arch),
|
||||
mainClass = context.ideMainClassName,
|
||||
customCommands = listOfNotNull(embeddedFrontendLaunchData, qodanaCustomLaunchData)
|
||||
)
|
||||
|
||||
),
|
||||
context
|
||||
)
|
||||
}
|
||||
|
||||
@@ -444,7 +444,7 @@ class MacDistributionBuilder(
|
||||
}
|
||||
}
|
||||
|
||||
checkInArchive(targetFile, pathInArchive = "${zipRoot}/Resources", macDistributionBuilder.context)
|
||||
validateProductJson(targetFile, pathInArchive = "${zipRoot}/Resources", macDistributionBuilder.context)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -122,9 +122,8 @@ interface OsSpecificDistributionBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun checkZip(distribution: Path, root: String, patterns: Collection<PathMatcher>): List<MatchedFile> {
|
||||
return ZipFile(Files.newByteChannel(distribution)).use { zipFile ->
|
||||
return ZipFile.Builder().setSeekableByteChannel(Files.newByteChannel(distribution)).get().use { zipFile ->
|
||||
zipFile.entries.asSequence().filter { !it.isDirectory }.mapNotNull { entry ->
|
||||
var entryPath = Path.of(entry.name)
|
||||
if (!root.isEmpty()) {
|
||||
@@ -141,9 +140,7 @@ interface OsSpecificDistributionBuilder {
|
||||
|
||||
companion object {
|
||||
@Internal
|
||||
fun suffix(arch: JvmArchitecture): String = when (arch) {
|
||||
JvmArchitecture.x64 -> ""
|
||||
else -> "-${arch.fileSuffix}"
|
||||
}
|
||||
fun suffix(arch: JvmArchitecture): String =
|
||||
if (arch == JvmArchitecture.x64) "" else "-${arch.fileSuffix}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
// 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 org.jetbrains.intellij.build.FrontendModuleFilter
|
||||
|
||||
/**
|
||||
* Names of JAR files from IDE_HOME/lib directory. These names are implementation detail and may be changed in the future, code outside
|
||||
* the build scripts must not rely on them.
|
||||
* Names of JAR files from `IDE_HOME/lib` directory.
|
||||
* These names are implementation detail and may be changed in the future; code outside the build scripts must not rely on them.
|
||||
*/
|
||||
object PlatformJarNames {
|
||||
/**
|
||||
@@ -20,7 +20,7 @@ object PlatformJarNames {
|
||||
internal const val APP_CLIENT_JAR: String = "app-client.jar"
|
||||
|
||||
/**
|
||||
* Returns name of the default JAR for a platform module.
|
||||
* Returns the name of the default JAR for a platform module.
|
||||
*/
|
||||
internal fun getPlatformModuleJarName(moduleName: String, frontendModuleFilter: FrontendModuleFilter): String {
|
||||
return if (frontendModuleFilter.isModuleIncluded(moduleName)) APP_CLIENT_JAR else APP_JAR
|
||||
@@ -53,9 +53,7 @@ object PlatformJarNames {
|
||||
const val TEST_FRAMEWORK_JAR: String = "testFramework.jar"
|
||||
|
||||
/**
|
||||
* The custom filesystem implementations for:
|
||||
* * Fleet and FSD
|
||||
* * IJent on WSL
|
||||
* The custom filesystem implementations for Eel and Fleet/FSD.
|
||||
*/
|
||||
const val PLATFORM_CORE_NIO_FS: String = "nio-fs.jar"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.ReviseWhenPortedToJDK
|
||||
@@ -98,6 +98,6 @@ object VmOptionsGenerator {
|
||||
}
|
||||
|
||||
internal fun writeVmOptions(file: Path, vmOptions: Sequence<String>, separator: String) {
|
||||
Files.writeString(file, vmOptions.joinToString(separator = separator, postfix = separator), StandardCharsets.US_ASCII)
|
||||
Files.writeString(file, vmOptions.joinToString(separator, postfix = separator), StandardCharsets.US_ASCII)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ internal class WindowsDistributionBuilder(
|
||||
val productJsonDir = Files.createTempDirectory(context.paths.tempDir, "win-product-info")
|
||||
val productJsonFile = writeProductJsonFile(productJsonDir, arch)
|
||||
val installationDirectories = listOf(context.paths.distAllDir, osAndArchSpecificDistPath, runtimeDir)
|
||||
validateProductJson(jsonText = productJsonFile.readText(), relativePathToProductJson = "", installationDirectories, installationArchives = emptyList(), context)
|
||||
validateProductJson(jsonText = productJsonFile.readText(), installationDirectories, installationArchives = emptyList(), context)
|
||||
launch(Dispatchers.IO + CoroutineName("build Windows ${arch.dirName} installer")) {
|
||||
exePath = buildNsisInstaller(osAndArchSpecificDistPath, additionalDirectoryToInclude = productJsonDir, suffix(arch), customizer, runtimeDir, context)
|
||||
}
|
||||
@@ -263,7 +263,7 @@ internal class WindowsDistributionBuilder(
|
||||
else {
|
||||
zip(targetFile = targetFile, dirs = dirMap, addDirEntriesMode = AddDirEntriesMode.NONE)
|
||||
}
|
||||
checkInArchive(archiveFile = targetFile, pathInArchive = zipPrefix, context = context)
|
||||
validateProductJson(archiveFile = targetFile, pathInArchive = zipPrefix, context = context)
|
||||
context.notifyArtifactBuilt(targetFile)
|
||||
targetFile
|
||||
}
|
||||
|
||||
@@ -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.productInfo
|
||||
|
||||
import com.intellij.platform.buildData.productInfo.*
|
||||
@@ -6,7 +6,10 @@ import com.jetbrains.plugin.structure.base.utils.isDirectory
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.jetbrains.intellij.build.*
|
||||
import org.jetbrains.intellij.build.BuildContext
|
||||
import org.jetbrains.intellij.build.BuiltinModulesFileData
|
||||
import org.jetbrains.intellij.build.JvmArchitecture
|
||||
import org.jetbrains.intellij.build.OsFamily
|
||||
import org.jetbrains.intellij.build.impl.Git
|
||||
import org.jetbrains.intellij.build.impl.client.ADDITIONAL_EMBEDDED_CLIENT_VM_OPTIONS
|
||||
import org.jetbrains.intellij.build.impl.client.createFrontendContextForLaunchers
|
||||
@@ -28,7 +31,7 @@ internal val jsonEncoder: Json by lazy {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates product-info.json file containing meta-information about product installation.
|
||||
* Generates a `product-info.json` file describing product installation.
|
||||
*/
|
||||
internal fun generateProductInfoJson(
|
||||
relativePathToBin: String,
|
||||
@@ -59,10 +62,8 @@ internal fun generateProductInfoJson(
|
||||
customProperties = listOfNotNull(generateGitRevisionProperty(context)) + productProperties.generateCustomPropertiesForProductInfo(),
|
||||
bundledPlugins = builtinModules?.plugins ?: emptyList(),
|
||||
fileExtensions = builtinModules?.fileExtensions ?: emptyList(),
|
||||
|
||||
modules = (builtinModules?.layout?.asSequence() ?: emptySequence()).filter { it.kind == ProductInfoLayoutItemKind.pluginAlias }.map { it.name }.toList(),
|
||||
layout = builtinModules?.layout ?: emptyList(),
|
||||
|
||||
flavors = jbrFlavors + productFlavors,
|
||||
)
|
||||
return jsonEncoder.encodeToString<ProductInfoData>(json)
|
||||
@@ -110,4 +111,3 @@ internal suspend fun generateEmbeddedFrontendLaunchData(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2000-2023 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.productInfo
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
@@ -11,7 +11,6 @@ import org.apache.commons.compress.archivers.zip.ZipFile
|
||||
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream
|
||||
import org.jetbrains.intellij.build.BuildContext
|
||||
import org.jetbrains.intellij.build.BuildMessages
|
||||
import org.jetbrains.intellij.build.CompilationContext
|
||||
import org.jetbrains.intellij.build.OsFamily
|
||||
import java.nio.channels.FileChannel
|
||||
import java.nio.file.Files
|
||||
@@ -19,61 +18,35 @@ import java.nio.file.Path
|
||||
import java.nio.file.StandardOpenOption
|
||||
|
||||
/**
|
||||
* Checks that product-info.json file located in [archiveFile] archive in [pathInArchive] subdirectory is correct
|
||||
* Checks that 'product-info.json' file located in [archiveFile] archive in [pathInArchive] subdirectory is correct.
|
||||
*/
|
||||
internal fun checkInArchive(archiveFile: Path, pathInArchive: String, context: BuildContext) {
|
||||
internal fun validateProductJson(archiveFile: Path, pathInArchive: String, context: BuildContext) {
|
||||
val productJsonPath = joinPaths(pathInArchive, PRODUCT_INFO_FILE_NAME)
|
||||
val entryData = loadEntry(archiveFile, productJsonPath)
|
||||
?: throw RuntimeException("Failed to validate product-info.json: cannot find '${productJsonPath}' in ${archiveFile}")
|
||||
validateProductJson(jsonText = entryData.decodeToString(),
|
||||
relativePathToProductJson = "",
|
||||
installationDirectories = emptyList(),
|
||||
installationArchives = listOf(archiveFile to pathInArchive),
|
||||
context = context)
|
||||
val entryData = loadEntry(archiveFile, productJsonPath) ?: throw RuntimeException("Failed to validate product-info.json: cannot find '${productJsonPath}' in ${archiveFile}")
|
||||
validateProductJson(jsonText = entryData.decodeToString(), installationDirectories = emptyList(), installationArchives = listOf(archiveFile to pathInArchive), context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that product-info.json file is correct.
|
||||
* Checks that the 'product-info.json' file is correct.
|
||||
*
|
||||
* @param installationDirectories directories which will be included in the product installation
|
||||
* @param installationArchives archives which will be unpacked and included in the product installation
|
||||
* (the first part specifies a path to the archive, the second part - a path inside the archive)
|
||||
*/
|
||||
internal fun validateProductJson(jsonText: String,
|
||||
relativePathToProductJson: String,
|
||||
installationDirectories: List<Path>,
|
||||
installationArchives: List<Pair<Path, String>>,
|
||||
context: CompilationContext) {
|
||||
val schemaPath = context.paths.communityHomeDir
|
||||
.resolve("platform/buildData/resources/product-info.schema.json")
|
||||
val messages = context.messages
|
||||
verifyJsonBySchema(jsonText, schemaPath, messages)
|
||||
internal fun validateProductJson(jsonText: String, installationDirectories: List<Path>, installationArchives: List<Pair<Path, String>>, context: BuildContext) {
|
||||
val schemaPath = context.paths.communityHomeDir.resolve("platform/buildData/resources/product-info.schema.json")
|
||||
verifyJsonBySchema(jsonText, schemaPath, context.messages)
|
||||
|
||||
val productJson = jsonEncoder.decodeFromString<ProductInfoData>(jsonText)
|
||||
checkFileExists(path = productJson.svgIconPath,
|
||||
description = "svg icon",
|
||||
relativePathToProductJson = relativePathToProductJson,
|
||||
installationDirectories = installationDirectories,
|
||||
installationArchives = installationArchives)
|
||||
checkFileExists(productJson.svgIconPath, description = "svg icon", installationDirectories, installationArchives)
|
||||
for (item in productJson.launch) {
|
||||
val os = item.os
|
||||
check(OsFamily.ALL.any { it.osName == os }) {
|
||||
"Incorrect OS name '${os}' in ${relativePathToProductJson}/${PRODUCT_INFO_FILE_NAME}"
|
||||
"Incorrect OS name '${os}' in ${PRODUCT_INFO_FILE_NAME}"
|
||||
}
|
||||
checkFileExists(path = item.launcherPath,
|
||||
description = "${os} launcher",
|
||||
relativePathToProductJson = relativePathToProductJson,
|
||||
installationDirectories = installationDirectories,
|
||||
installationArchives = installationArchives)
|
||||
checkFileExists(path = item.javaExecutablePath,
|
||||
description = "${os} java executable",
|
||||
relativePathToProductJson = relativePathToProductJson,
|
||||
installationDirectories = installationDirectories,
|
||||
installationArchives = installationArchives)
|
||||
checkFileExists(path = item.vmOptionsFilePath,
|
||||
description = "${os} VM options file",
|
||||
relativePathToProductJson = relativePathToProductJson,
|
||||
installationDirectories = installationDirectories,
|
||||
installationArchives = installationArchives)
|
||||
checkFileExists(item.launcherPath, description = "${os} launcher", installationDirectories, installationArchives)
|
||||
checkFileExists(item.javaExecutablePath, description = "${os} java executable", installationDirectories, installationArchives)
|
||||
checkFileExists(item.vmOptionsFilePath, description = "${os} VM options file", installationDirectories, installationArchives)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,40 +54,36 @@ private fun verifyJsonBySchema(jsonData: String, jsonSchemaFile: Path, messages:
|
||||
val schema = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V7).getSchema(Files.readString(jsonSchemaFile))
|
||||
val errors = schema.validate(ObjectMapper().readTree(jsonData))
|
||||
if (!errors.isEmpty()) {
|
||||
messages.error("Unable to validate JSON against $jsonSchemaFile:" +
|
||||
"\n${errors.joinToString(separator = "\n")}\njson file content:\n$jsonData")
|
||||
messages.error("Unable to validate JSON against ${jsonSchemaFile}:\n${errors.joinToString("\n")}\nfile content:\n${jsonData}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkFileExists(path: String?,
|
||||
description: String,
|
||||
relativePathToProductJson: String,
|
||||
installationDirectories: List<Path>,
|
||||
installationArchives: List<Pair<Path, String>>) {
|
||||
private fun checkFileExists(path: String?, description: String, installationDirectories: List<Path>, installationArchives: List<Pair<Path, String>>) {
|
||||
if (path == null) {
|
||||
return
|
||||
}
|
||||
|
||||
val pathFromProductJson = relativePathToProductJson + path
|
||||
if (installationDirectories.none { Files.exists(it.resolve(pathFromProductJson)) } &&
|
||||
installationArchives.none { archiveContainsEntry(it.first, joinPaths(it.second, pathFromProductJson)) }) {
|
||||
throw RuntimeException("Incorrect path to $description '$path' in $relativePathToProductJson/product-info.json: " +
|
||||
"the specified file doesn't exist in directories $installationDirectories " +
|
||||
"and archives ${installationArchives.map { "${it.first}/${it.second}" }}")
|
||||
val pathFromProductJson = path
|
||||
if (
|
||||
installationDirectories.none { Files.exists(it.resolve(pathFromProductJson)) } &&
|
||||
installationArchives.none { archiveContainsEntry(it.first, joinPaths(it.second, pathFromProductJson)) }
|
||||
) {
|
||||
throw RuntimeException(
|
||||
"Incorrect path to ${description} '${path}' in product-info.json:" +
|
||||
" the specified file doesn't exist neither in directories ${installationDirectories}" +
|
||||
" nor in archives ${installationArchives.map { "${it.first}/${it.second}" }}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun joinPaths(parent: String, child: String): String {
|
||||
return FileUtilRt.toCanonicalPath(/* path = */ "$parent/$child", /* separatorChar = */ '/', /* removeLastSlash = */ true)
|
||||
.dropWhile { it == '/' }
|
||||
}
|
||||
private fun joinPaths(parent: String, child: String): String =
|
||||
FileUtilRt.toCanonicalPath(/*path =*/ "${parent}/${child}", /*separatorChar =*/ '/', /*removeLastSlash =*/ true).dropWhile { it == '/' }
|
||||
|
||||
private fun archiveContainsEntry(archiveFile: Path, entryPath: String): Boolean {
|
||||
val fileName = archiveFile.fileName.toString()
|
||||
if (fileName.endsWith(".zip") || fileName.endsWith(".jar")) {
|
||||
// don't use ImmutableZipFile - archive maybe more than 2GB
|
||||
FileChannel.open(archiveFile, StandardOpenOption.READ).use { channel ->
|
||||
ZipFile(channel).use {
|
||||
ZipFile.Builder().setSeekableByteChannel(channel).get().use {
|
||||
return it.getEntry(entryPath) != null
|
||||
}
|
||||
}
|
||||
@@ -134,13 +103,12 @@ private fun archiveContainsEntry(archiveFile: Path, entryPath: String): Boolean
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
private fun loadEntry(archiveFile: Path, entryPath: String): ByteArray? {
|
||||
val fileName = archiveFile.fileName.toString()
|
||||
if (fileName.endsWith(".zip") || fileName.endsWith(".jar")) {
|
||||
// don't use ImmutableZipFile - archive maybe more than 2GB
|
||||
FileChannel.open(archiveFile, StandardOpenOption.READ).use { channel ->
|
||||
ZipFile(channel).use {
|
||||
ZipFile.Builder().setSeekableByteChannel(channel).get().use {
|
||||
return it.getInputStream(it.getEntry(entryPath)).readAllBytes()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
// 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.qodana
|
||||
|
||||
import com.intellij.platform.buildData.productInfo.CustomCommandLaunchData
|
||||
import org.jetbrains.intellij.build.BuildContext
|
||||
import org.jetbrains.intellij.build.JvmArchitecture
|
||||
import org.jetbrains.intellij.build.OsFamily
|
||||
import com.intellij.platform.buildData.productInfo.CustomCommandLaunchData
|
||||
|
||||
|
||||
internal fun generateQodanaLaunchData(
|
||||
ideContext: BuildContext,
|
||||
arch: JvmArchitecture,
|
||||
os: OsFamily,
|
||||
): CustomCommandLaunchData? {
|
||||
internal fun generateQodanaLaunchData(ideContext: BuildContext, arch: JvmArchitecture, os: OsFamily): CustomCommandLaunchData? {
|
||||
val qodanaProductProperties = ideContext.productProperties.qodanaProductProperties ?: return null
|
||||
val vmOptions = ideContext.getAdditionalJvmArguments(os, arch, isQodana = true) + qodanaProductProperties.getAdditionalVmOptions(ideContext)
|
||||
return CustomCommandLaunchData(
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
// 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 com.intellij.platform.buildScripts.testFramework
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.io.NioFiles
|
||||
import com.intellij.platform.buildScripts.testFramework.binaryReproducibility.BuildArtifactsReproducibilityTest
|
||||
import com.intellij.platform.runtime.product.ProductMode
|
||||
@@ -39,16 +38,15 @@ fun createBuildOptionsForTest(productProperties: ProductProperties, homeDir: Pat
|
||||
jarCacheDir = homeDir.resolve("out/dev-run/jar-cache"),
|
||||
compressZipFiles = false,
|
||||
)
|
||||
customizeBuildOptionsForTest(options = options, outDir = outDir, skipDependencySetup = skipDependencySetup, testInfo = testInfo)
|
||||
customizeBuildOptionsForTest(options, outDir, skipDependencySetup, testInfo)
|
||||
return options
|
||||
}
|
||||
|
||||
fun createTestBuildOutDir(productProperties: ProductProperties): Path {
|
||||
return FileUtil.createTempDirectory("test-build-${productProperties.baseFileName}", null, false).toPath()
|
||||
}
|
||||
fun createTestBuildOutDir(productProperties: ProductProperties): Path =
|
||||
Files.createTempDirectory("test-build-${productProperties.baseFileName}")
|
||||
|
||||
private inline fun createBuildOptionsForTest(productProperties: ProductProperties, homeDir: Path, testInfo: TestInfo, customizer: (BuildOptions) -> Unit): BuildOptions {
|
||||
val options = createBuildOptionsForTest(productProperties = productProperties, homeDir = homeDir, testInfo = testInfo)
|
||||
val options = createBuildOptionsForTest(productProperties, homeDir, testInfo = testInfo)
|
||||
customizer(options)
|
||||
return options
|
||||
}
|
||||
@@ -56,10 +54,7 @@ private inline fun createBuildOptionsForTest(productProperties: ProductPropertie
|
||||
fun customizeBuildOptionsForTest(options: BuildOptions, outDir: Path, skipDependencySetup: Boolean = false, testInfo: TestInfo?) {
|
||||
options.skipDependencySetup = skipDependencySetup
|
||||
options.isTestBuild = true
|
||||
/**
|
||||
* Differs from [SnapshotBuildNumber] to closer match the production
|
||||
*/
|
||||
options.buildNumber = "${SnapshotBuildNumber.BASE}.1"
|
||||
options.buildNumber = "${SnapshotBuildNumber.BASE}.1" // differs from [SnapshotBuildNumber] to closer match the production
|
||||
options.buildStepsToSkip += listOf(
|
||||
BuildOptions.LIBRARY_URL_CHECK_STEP,
|
||||
BuildOptions.TEAMCITY_ARTIFACTS_PUBLICATION_STEP,
|
||||
@@ -85,56 +80,46 @@ suspend inline fun createBuildContext(
|
||||
buildTools: ProprietaryBuildTools = ProprietaryBuildTools.DUMMY,
|
||||
buildOptionsCustomizer: (BuildOptions) -> Unit = {},
|
||||
): BuildContext {
|
||||
val options = createBuildOptionsForTest(productProperties = productProperties, homeDir = homeDir)
|
||||
val options = createBuildOptionsForTest(productProperties, homeDir)
|
||||
buildOptionsCustomizer(options)
|
||||
return BuildContextImpl.createContext(projectHome = homeDir, productProperties = productProperties, proprietaryBuildTools = buildTools, options = options)
|
||||
return BuildContextImpl.createContext(homeDir, productProperties, proprietaryBuildTools = buildTools, options = options)
|
||||
}
|
||||
|
||||
// don't expose BuildDependenciesCommunityRoot
|
||||
fun runTestBuild(
|
||||
homePath: Path,
|
||||
productProperties: ProductProperties,
|
||||
testInfo: TestInfo,
|
||||
buildTools: ProprietaryBuildTools,
|
||||
testInfo: TestInfo,
|
||||
buildOptionsCustomizer: (BuildOptions) -> Unit = {},
|
||||
) {
|
||||
runTestBuild(
|
||||
homeDir = homePath,
|
||||
productProperties = productProperties,
|
||||
buildTools = buildTools,
|
||||
testInfo = testInfo,
|
||||
isReproducibilityTestAllowed = true,
|
||||
buildOptionsCustomizer = buildOptionsCustomizer,
|
||||
)
|
||||
runTestBuild(homePath, productProperties, testInfo, buildTools, isReproducibilityTestAllowed = true, buildOptionsCustomizer = buildOptionsCustomizer)
|
||||
}
|
||||
|
||||
fun runTestBuild(
|
||||
homeDir: Path,
|
||||
productProperties: ProductProperties,
|
||||
buildTools: ProprietaryBuildTools = ProprietaryBuildTools.DUMMY,
|
||||
testInfo: TestInfo,
|
||||
buildTools: ProprietaryBuildTools = ProprietaryBuildTools.DUMMY,
|
||||
isReproducibilityTestAllowed: Boolean = true,
|
||||
build: suspend (BuildContext) -> Unit = { buildDistributions(it) },
|
||||
build: suspend (BuildContext) -> Unit = { buildDistributions(context = it) },
|
||||
onSuccess: suspend (BuildContext) -> Unit = {},
|
||||
buildOptionsCustomizer: (BuildOptions) -> Unit = {}
|
||||
) = runBlocking(Dispatchers.Default) {
|
||||
): Unit = runBlocking(Dispatchers.Default) {
|
||||
if (isReproducibilityTestAllowed && BuildArtifactsReproducibilityTest.isEnabled) {
|
||||
val reproducibilityTest = BuildArtifactsReproducibilityTest()
|
||||
repeat(reproducibilityTest.iterations) { iterationNumber ->
|
||||
launch {
|
||||
doRunTestBuild(
|
||||
context = {
|
||||
BuildContextImpl.createContext(
|
||||
projectHome = homeDir,
|
||||
productProperties = productProperties,
|
||||
proprietaryBuildTools = buildTools,
|
||||
setupTracer = false,
|
||||
options = createBuildOptionsForTest(productProperties = productProperties, homeDir = homeDir, testInfo = testInfo, customizer = buildOptionsCustomizer).also {
|
||||
reproducibilityTest.configure(it)
|
||||
},
|
||||
)
|
||||
},
|
||||
traceSpanName = "${testInfo.spanName}#$iterationNumber",
|
||||
context = BuildContextImpl.createContext(
|
||||
homeDir,
|
||||
productProperties,
|
||||
setupTracer = false,
|
||||
buildTools,
|
||||
createBuildOptionsForTest(productProperties, homeDir, testInfo, buildOptionsCustomizer).also {
|
||||
reproducibilityTest.configure(it)
|
||||
}
|
||||
),
|
||||
traceSpanName = "${testInfo.spanName}#${iterationNumber}",
|
||||
writeTelemetry = false,
|
||||
build = { context ->
|
||||
build(context)
|
||||
@@ -147,15 +132,13 @@ fun runTestBuild(
|
||||
}
|
||||
else {
|
||||
doRunTestBuild(
|
||||
context = {
|
||||
BuildContextImpl.createContext(
|
||||
projectHome = homeDir,
|
||||
productProperties = productProperties,
|
||||
proprietaryBuildTools = buildTools,
|
||||
setupTracer = false,
|
||||
options = createBuildOptionsForTest(productProperties = productProperties, homeDir = homeDir, testInfo = testInfo, customizer = buildOptionsCustomizer),
|
||||
)
|
||||
},
|
||||
context = BuildContextImpl.createContext(
|
||||
homeDir,
|
||||
productProperties,
|
||||
setupTracer = false,
|
||||
buildTools,
|
||||
createBuildOptionsForTest(productProperties, homeDir, testInfo, buildOptionsCustomizer),
|
||||
),
|
||||
writeTelemetry = true,
|
||||
traceSpanName = testInfo.spanName,
|
||||
build = { context ->
|
||||
@@ -172,18 +155,17 @@ suspend fun runTestBuild(
|
||||
context: suspend () -> BuildContext,
|
||||
build: suspend (BuildContext) -> Unit = { buildDistributions(it) }
|
||||
) {
|
||||
doRunTestBuild(context = context, traceSpanName = testInfo.spanName, writeTelemetry = true, build = build)
|
||||
doRunTestBuild(context(), traceSpanName = testInfo.spanName, writeTelemetry = true, build = build)
|
||||
}
|
||||
|
||||
private val defaultLogFactory = Logger.getFactory()
|
||||
|
||||
private suspend fun doRunTestBuild(context: suspend () -> BuildContext, traceSpanName: String, writeTelemetry: Boolean, build: suspend (context: BuildContext) -> Unit) {
|
||||
private suspend fun doRunTestBuild(context: BuildContext, traceSpanName: String, writeTelemetry: Boolean, build: suspend (context: BuildContext) -> Unit) {
|
||||
var outDir: Path? = null
|
||||
var traceFile: Path? = null
|
||||
var error: Throwable? = null
|
||||
try {
|
||||
spanBuilder(traceSpanName).use { span ->
|
||||
val context = context()
|
||||
context.cleanupJarCache()
|
||||
outDir = context.paths.buildOutputDir
|
||||
span.setAttribute("outDir", outDir.toString())
|
||||
|
||||
@@ -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 com.intellij.platform.buildData.productInfo
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
@@ -30,12 +30,11 @@ class ProductInfoData private constructor(
|
||||
val launch: List<ProductInfoLaunchData>,
|
||||
val customProperties: List<CustomProperty> = emptyList(),
|
||||
val bundledPlugins: List<String> = emptyList(),
|
||||
// it is not modules, but plugin aliases
|
||||
val modules: List<String> = emptyList(),
|
||||
val modules: List<String> = emptyList(), // actually, it is not modules but plugin aliases
|
||||
val fileExtensions: List<String> = emptyList(),
|
||||
val flavors: List<ProductFlavorData> = emptyList(),
|
||||
|
||||
// not used by launcher, specify in the end
|
||||
// not used by the launcher; must be at the end
|
||||
@ApiStatus.Internal
|
||||
val layout: List<ProductInfoLayoutItem> = emptyList(),
|
||||
) {
|
||||
@@ -64,26 +63,10 @@ class ProductInfoData private constructor(
|
||||
fileExtensions: List<String>,
|
||||
flavors: List<ProductFlavorData>,
|
||||
layout: List<ProductInfoLayoutItem>,
|
||||
): ProductInfoData {
|
||||
return ProductInfoData(
|
||||
name = name,
|
||||
version = version,
|
||||
versionSuffix = versionSuffix,
|
||||
buildNumber = buildNumber,
|
||||
productCode = productCode,
|
||||
envVarBaseName = envVarBaseName,
|
||||
dataDirectoryName = dataDirectoryName,
|
||||
svgIconPath = svgIconPath,
|
||||
productVendor = productVendor,
|
||||
launch = launch,
|
||||
customProperties = customProperties,
|
||||
bundledPlugins = bundledPlugins,
|
||||
modules = modules,
|
||||
fileExtensions = fileExtensions,
|
||||
flavors = flavors,
|
||||
layout = layout,
|
||||
)
|
||||
}
|
||||
): ProductInfoData = ProductInfoData(
|
||||
name, version, versionSuffix, buildNumber, productCode, envVarBaseName, dataDirectoryName, svgIconPath, productVendor, launch,
|
||||
customProperties, bundledPlugins, modules, fileExtensions, flavors, layout
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,20 +108,10 @@ class ProductInfoLaunchData private constructor(
|
||||
mainClass: String,
|
||||
startupWmClass: String? = null,
|
||||
customCommands: List<CustomCommandLaunchData> = emptyList(),
|
||||
): ProductInfoLaunchData {
|
||||
return ProductInfoLaunchData(
|
||||
os = os,
|
||||
arch = arch,
|
||||
launcherPath = launcherPath,
|
||||
javaExecutablePath = javaExecutablePath,
|
||||
vmOptionsFilePath = vmOptionsFilePath,
|
||||
startupWmClass = startupWmClass,
|
||||
bootClassPathJarNames = bootClassPathJarNames,
|
||||
additionalJvmArguments = additionalJvmArguments,
|
||||
mainClass = mainClass,
|
||||
customCommands = customCommands
|
||||
)
|
||||
}
|
||||
): ProductInfoLaunchData = ProductInfoLaunchData(
|
||||
os, arch, launcherPath, javaExecutablePath, vmOptionsFilePath, startupWmClass, bootClassPathJarNames, additionalJvmArguments,
|
||||
mainClass, customCommands
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,4 +130,4 @@ class CustomCommandLaunchData @ApiStatus.Internal constructor(
|
||||
class CustomProperty @ApiStatus.Internal constructor(
|
||||
val key: String,
|
||||
val value: String,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -30,4 +30,4 @@ const val IJENT_REQUIRED_DEFAULT_NIO_FS_PROVIDER_CLASS: String = "com.intellij.p
|
||||
|
||||
val MULTI_ROUTING_FILE_SYSTEM_VMOPTIONS: List<String> = listOf(
|
||||
"-Djava.nio.file.spi.DefaultFileSystemProvider=$IJENT_REQUIRED_DEFAULT_NIO_FS_PROVIDER_CLASS",
|
||||
)
|
||||
)
|
||||
|
||||
@@ -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.pycharm
|
||||
|
||||
import com.intellij.openapi.application.PathManager
|
||||
@@ -39,14 +39,9 @@ class PyCharmCommunityBuildTest {
|
||||
fun build(testInfo: TestInfo) {
|
||||
val homePath = PathManager.getHomeDirFor(javaClass)!!
|
||||
val communityHomePath = BuildDependenciesCommunityRoot(homePath.resolve("community"))
|
||||
runTestBuild(
|
||||
homeDir = communityHomePath.communityRoot,
|
||||
testInfo = testInfo,
|
||||
productProperties = PyCharmCommunityProperties(communityHomePath.communityRoot),
|
||||
) {
|
||||
it.classOutDir = System.getProperty(BuildOptions.PROJECT_CLASSES_OUTPUT_DIRECTORY_PROPERTY)
|
||||
?: "$homePath/out/classes"
|
||||
runTestBuild(communityHomePath.communityRoot, PyCharmCommunityProperties(communityHomePath.communityRoot), testInfo) {
|
||||
it.classOutDir = System.getProperty(BuildOptions.PROJECT_CLASSES_OUTPUT_DIRECTORY_PROPERTY) ?: "${homePath}/out/classes"
|
||||
stubSkeletons(communityHomePath.communityRoot, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user