mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 11:50:54 +07:00
jps bazel compiler - part 4
GitOrigin-RevId: 3e901088d0b54fb09bdec17937f2dd74c0e56905
This commit is contained in:
committed by
intellij-monorepo-bot
parent
9d3a497d12
commit
ec80730780
3458
MODULE.bazel.lock
generated
3458
MODULE.bazel.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -588,7 +588,7 @@ def _run_jps_builder(
|
||||
|
||||
outputs = [output_jar]
|
||||
abi_jar = output_jar
|
||||
if not "kt_abi_plugin_incompatible" in ctx.attr.tags:
|
||||
if False and not "kt_abi_plugin_incompatible" in ctx.attr.tags:
|
||||
abi_jar = ctx.actions.declare_file(ctx.label.name + ".abi.jar")
|
||||
outputs.append(abi_jar)
|
||||
args.add("--abi-out", abi_jar)
|
||||
|
||||
28
build/jvm-rules/src/abi/BUILD.bazel
Normal file
28
build/jvm-rules/src/abi/BUILD.bazel
Normal file
@@ -0,0 +1,28 @@
|
||||
load("@rules_java//java:defs.bzl", "java_binary")
|
||||
load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
|
||||
|
||||
kt_jvm_library(
|
||||
name = "abi",
|
||||
srcs = glob(["*.kt"]),
|
||||
kotlinc_opts = "//:rules_jvm_bootstrap_kotlinc_options",
|
||||
deps = [
|
||||
"@lib//:kotlin-stdlib",
|
||||
"//:kotlinx-coroutines-core",
|
||||
"@lib//:asm",
|
||||
"//:kotlin-metadata",
|
||||
"//zip:build-zip",
|
||||
],
|
||||
visibility = ["//src/jps-builder/packager:__pkg__"],
|
||||
)
|
||||
|
||||
java_binary(
|
||||
name = "test-abi-generator",
|
||||
runtime_deps = [":abi"],
|
||||
main_class = "org.jetbrains.bazel.jvm.abi.TestAbiGenerator",
|
||||
jvm_flags = [
|
||||
"-Xms1024m",
|
||||
"-Xmx6144m",
|
||||
"-Djava.awt.headless=true",
|
||||
"-Dapple.awt.UIElement=true",
|
||||
],
|
||||
)
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.jetbrains.bazel.jvm.jps
|
||||
package org.jetbrains.bazel.jvm.abi
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.AnnotationVisitor
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
32
build/jvm-rules/src/abi/TestAbiGenerator.kt
Normal file
32
build/jvm-rules/src/abi/TestAbiGenerator.kt
Normal file
@@ -0,0 +1,32 @@
|
||||
package org.jetbrains.bazel.jvm.abi
|
||||
|
||||
import org.jetbrains.org.objectweb.asm.ClassReader
|
||||
import org.jetbrains.org.objectweb.asm.ClassWriter
|
||||
import java.nio.file.Path
|
||||
|
||||
internal object TestAbiGenerator {
|
||||
@JvmStatic
|
||||
fun main(args: Array<String>) {
|
||||
val userHomeDir = Path.of(System.getProperty("user.home"))
|
||||
val zip = java.util.zip.ZipFile(userHomeDir.resolve("kotlin-worker/ide-impl.jar").toFile())
|
||||
try {
|
||||
//val className = "com.intellij.codeInsight.folding.impl.FoldingUtil"
|
||||
val className = "com.intellij.ui.AppUIUtilKt"
|
||||
val classReader = ClassReader(zip.getInputStream(zip.getEntry(className.replace('.', '/') + ".class")))
|
||||
val classesToBeDeleted = HashSet<String>()
|
||||
val classWriter = ClassWriter(classReader, 0)
|
||||
val abiVisitor = AbiClassVisitor(
|
||||
classVisitor = classWriter,
|
||||
classesToBeDeleted = classesToBeDeleted,
|
||||
treatInternalAsPrivate = false,
|
||||
)
|
||||
classReader.accept(abiVisitor, ClassReader.SKIP_CODE or ClassReader.SKIP_FRAMES)
|
||||
val bytes = classWriter.toByteArray()
|
||||
//val classNode = ClassNode()
|
||||
//ClassReader(bytes).accept(classNode, 0)
|
||||
}
|
||||
finally {
|
||||
zip.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,55 @@
|
||||
package org.jetbrains.bazel.jvm.jps
|
||||
package org.jetbrains.bazel.jvm.abi
|
||||
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import org.jetbrains.intellij.build.io.writeZipUsingTempFile
|
||||
import org.jetbrains.org.objectweb.asm.*
|
||||
import org.jetbrains.org.objectweb.asm.tree.AnnotationNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.FieldNode
|
||||
import org.jetbrains.org.objectweb.asm.tree.MethodNode
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.file.Path
|
||||
import kotlin.metadata.*
|
||||
import kotlin.metadata.jvm.KotlinClassMetadata
|
||||
import kotlin.metadata.jvm.getterSignature
|
||||
import kotlin.metadata.jvm.localDelegatedProperties
|
||||
import kotlin.metadata.jvm.signature
|
||||
|
||||
suspend fun writeAbi(abiJar: Path, classChannel: Channel<Pair<ByteArray, ByteArray>>) {
|
||||
writeZipUsingTempFile(abiJar, indexWriter = null) { stream ->
|
||||
val classesToBeDeleted = HashSet<String>()
|
||||
for ((name, classData) in classChannel) {
|
||||
val classWriter = ClassWriter(0)
|
||||
val abiClassVisitor = AbiClassVisitor(
|
||||
classVisitor = classWriter,
|
||||
classesToBeDeleted = classesToBeDeleted,
|
||||
treatInternalAsPrivate = false,
|
||||
)
|
||||
ClassReader(classData).accept(abiClassVisitor, ClassReader.SKIP_CODE or ClassReader.SKIP_FRAMES)
|
||||
if (!abiClassVisitor.isApiClass) {
|
||||
continue
|
||||
}
|
||||
|
||||
val abiData = classWriter.toByteArray()
|
||||
stream.writeDataRawEntryWithoutCrc(ByteBuffer.wrap(abiData), name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ClassVisitor that strips non-public methods/fields and Kotlin `internal` methods.
|
||||
*/
|
||||
internal class AbiClassVisitor(
|
||||
classVisitor: ClassVisitor,
|
||||
private val classesToBeDeleted: MutableSet<String>,
|
||||
private val treatInternalAsPrivate: Boolean,
|
||||
) : ClassVisitor(Opcodes.API_VERSION, classVisitor) {
|
||||
// tracks if this class has any public API members
|
||||
var isApiClass: Boolean = false
|
||||
var isApiClass: Boolean = true
|
||||
private set
|
||||
|
||||
private val classAnnotations = mutableListOf<Pair<AnnotationNode, Boolean>>()
|
||||
private val visibleAnnotations = ArrayList<AnnotationNode>()
|
||||
private val invisibleAnnotations = ArrayList<AnnotationNode>()
|
||||
|
||||
private val fields = mutableListOf<FieldNode>()
|
||||
private val methods = mutableListOf<MethodNode>()
|
||||
private var kotlinMetadata: Pair<String, KotlinClassMetadata>? = null
|
||||
@@ -36,19 +64,25 @@ internal class AbiClassVisitor(
|
||||
}
|
||||
else {
|
||||
val annotationNode = AnnotationNode(api, descriptor)
|
||||
classAnnotations.add(annotationNode to visible)
|
||||
(if (visible) visibleAnnotations else invisibleAnnotations).add(annotationNode)
|
||||
return annotationNode
|
||||
}
|
||||
}
|
||||
|
||||
override fun visit(version: Int, access: Int, name: String, signature: String?, superName: String?, interfaces: Array<String>?) {
|
||||
if (access and Opcodes.ACC_PUBLIC == 0) {
|
||||
classesToBeDeleted.add(name)
|
||||
}
|
||||
else {
|
||||
isApiClass = true
|
||||
super.visit(version, access, name, signature, superName, interfaces)
|
||||
isApiClass = (access and Opcodes.ACC_PUBLIC) != 0
|
||||
if (isApiClass) {
|
||||
val visibility = getKotlinMetaClass()?.visibility
|
||||
if (visibility == null || !isPrivateVisibility(visibility, treatInternalAsPrivate)) {
|
||||
super.visit(version, access, name, signature, superName, interfaces)
|
||||
return
|
||||
}
|
||||
else {
|
||||
isApiClass = false
|
||||
}
|
||||
}
|
||||
|
||||
classesToBeDeleted.add(name)
|
||||
}
|
||||
|
||||
override fun visitField(
|
||||
@@ -58,7 +92,10 @@ internal class AbiClassVisitor(
|
||||
signature: String?,
|
||||
value: Any?,
|
||||
): FieldVisitor? {
|
||||
if (access and Opcodes.ACC_PUBLIC == 0) {
|
||||
if ((access and Opcodes.ACC_PUBLIC) == 0) {
|
||||
return null
|
||||
}
|
||||
if (treatInternalAsPrivate && isFieldKotlinInternal(name)) {
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -74,20 +111,23 @@ internal class AbiClassVisitor(
|
||||
signature: String?,
|
||||
exceptions: Array<String>?,
|
||||
): MethodVisitor? {
|
||||
// retain public methods and exclude Kotlin `internal` methods
|
||||
val isPublic = access and Opcodes.ACC_PUBLIC != 0
|
||||
val isInternal = isKotlinInternal(name)
|
||||
if (!isPublic || isInternal) {
|
||||
if ((access and Opcodes.ACC_PUBLIC) == 0) {
|
||||
return null
|
||||
}
|
||||
if (treatInternalAsPrivate && isMethodKotlinInternal(name)) {
|
||||
return null
|
||||
}
|
||||
|
||||
val methodNode = MethodNode(api, access, name, descriptor, signature, exceptions)
|
||||
methods.add(methodNode)
|
||||
return methodNode
|
||||
val method = MethodNode(api, access, name, descriptor, signature, exceptions)
|
||||
methods.add(method)
|
||||
//return ReplaceWithEmptyBody(method, (Type.getArgumentsAndReturnSizes(method.desc) shr 2) - 1)
|
||||
return method
|
||||
}
|
||||
|
||||
override fun visitEnd() {
|
||||
classAnnotations.sortBy { it.first.desc }
|
||||
visibleAnnotations.sortBy { it.desc }
|
||||
invisibleAnnotations.sortBy { it.desc }
|
||||
|
||||
fields.sortBy { it.name }
|
||||
methods.sortBy { it.name }
|
||||
|
||||
@@ -97,12 +137,16 @@ internal class AbiClassVisitor(
|
||||
descriptor = descriptor,
|
||||
classVisitor = cv,
|
||||
classesToBeDeleted = classesToBeDeleted,
|
||||
treatInternalAsPrivate = treatInternalAsPrivate,
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
for ((annotation, visible) in classAnnotations) {
|
||||
val annotationVisitor = cv.visitAnnotation(annotation.desc, visible)
|
||||
annotation.accept(annotationVisitor)
|
||||
for (annotation in visibleAnnotations) {
|
||||
annotation.accept(cv.visitAnnotation(annotation.desc, true))
|
||||
}
|
||||
for (annotation in invisibleAnnotations) {
|
||||
annotation.accept(cv.visitAnnotation(annotation.desc, false))
|
||||
}
|
||||
|
||||
for (field in fields) {
|
||||
@@ -110,22 +154,28 @@ internal class AbiClassVisitor(
|
||||
}
|
||||
|
||||
for (method in methods) {
|
||||
method.accept(cv)
|
||||
//val exceptionsArray = if (method.exceptions == null) null else method.exceptions.toTypedArray()
|
||||
//val methodVisitor = cv.visitMethod(method.access, method.name, method.desc, method.signature, exceptionsArray)
|
||||
//method.accept(methodVisitor)
|
||||
|
||||
val mv = cv.visitMethod(method.access, method.name, method.desc, method.signature, method.exceptions?.toTypedArray())
|
||||
val stripper = MethodBodyStripper(mv)
|
||||
stripper.visitCode()
|
||||
stripper.visitMaxs(0, 0)
|
||||
stripper.visitEnd()
|
||||
//ReplaceWithEmptyBody(
|
||||
// targetWriter = method,
|
||||
// newMaxLocals = (Type.getArgumentsAndReturnSizes(method.desc) shr 2) - 1,
|
||||
//)
|
||||
//
|
||||
//val mv = cv.visitMethod(method.access, method.name, method.desc, method.signature, method.exceptions?.toTypedArray())
|
||||
//val stripper = MethodBodyStripper(mv)
|
||||
//stripper.visitCode()
|
||||
//stripper.visitMaxs(0, 0)
|
||||
//stripper.visitEnd()
|
||||
}
|
||||
|
||||
super.visitEnd()
|
||||
}
|
||||
|
||||
private fun isKotlinInternal(methodName: String?): Boolean {
|
||||
val kClass = (kotlinMetadata?.second as? KotlinClassMetadata.Class)?.kmClass ?: return false
|
||||
private fun isMethodKotlinInternal(methodName: String?): Boolean {
|
||||
val kClass = getKotlinMetaClass() ?: return false
|
||||
for (function in kClass.functions) {
|
||||
if (function.visibility == Visibility.INTERNAL && function.name == methodName) {
|
||||
return true
|
||||
@@ -133,6 +183,46 @@ internal class AbiClassVisitor(
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun isFieldKotlinInternal(name: String?): Boolean {
|
||||
val kClass = getKotlinMetaClass() ?: return false
|
||||
for (property in kClass.properties) {
|
||||
if (property.visibility == Visibility.INTERNAL && property.name == name) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun getKotlinMetaClass(): KmClass? = (kotlinMetadata?.second as? KotlinClassMetadata.Class)?.kmClass
|
||||
}
|
||||
|
||||
// now, we're not passing the writer to the superclass for our radical changes
|
||||
private class ReplaceWithEmptyBody(
|
||||
private val targetWriter: MethodVisitor,
|
||||
private val newMaxLocals: Int,
|
||||
) : MethodVisitor(Opcodes.API_VERSION) {
|
||||
// we're only override the minimum to create a code attribute with a sole RETURN
|
||||
override fun visitMaxs(maxStack: Int, maxLocals: Int) {
|
||||
targetWriter.visitMaxs(0, newMaxLocals)
|
||||
}
|
||||
|
||||
override fun visitCode() {
|
||||
targetWriter.visitCode()
|
||||
targetWriter.visitInsn(Opcodes.RETURN)
|
||||
}
|
||||
|
||||
override fun visitEnd() {
|
||||
targetWriter.visitEnd()
|
||||
}
|
||||
|
||||
override fun visitAnnotation(desc: String?, visible: Boolean): AnnotationVisitor {
|
||||
return targetWriter.visitAnnotation(desc, visible)
|
||||
}
|
||||
|
||||
override fun visitParameter(name: String?, access: Int) {
|
||||
targetWriter.visitParameter(name, access)
|
||||
}
|
||||
}
|
||||
|
||||
private class MethodBodyStripper(mv: MethodVisitor) : MethodVisitor(Opcodes.API_VERSION, mv) {
|
||||
@@ -152,8 +242,8 @@ private fun transformAndWriteKotlinMetadata(
|
||||
descriptor: String,
|
||||
classVisitor: ClassVisitor,
|
||||
classesToBeDeleted: Set<String>,
|
||||
treatInternalAsPrivate: Boolean,
|
||||
) {
|
||||
val treatInternalAsPrivate = false
|
||||
when (metadata) {
|
||||
is KotlinClassMetadata.Class -> {
|
||||
removePrivateDeclarationsForClass(
|
||||
@@ -219,10 +309,10 @@ private fun removePrivateDeclarationsForClass(
|
||||
pruneClass: Boolean,
|
||||
treatInternalAsPrivate: Boolean,
|
||||
) {
|
||||
klass.constructors.removeIf { pruneClass || it.visibility.shouldRemove(treatInternalAsPrivate) }
|
||||
klass.constructors.removeIf { pruneClass || isPrivateVisibility(it.visibility, treatInternalAsPrivate) }
|
||||
removePrivateDeclarationsForDeclarationContainer(
|
||||
container = klass as KmDeclarationContainer,
|
||||
copyFunShouldBeDeleted = klass.copyFunShouldBeDeleted(removeDataClassCopy = removeCopyAlongWithConstructor),
|
||||
copyFunShouldBeDeleted = copyFunShouldBeDeleted(klass = klass, removeDataClassCopy = removeCopyAlongWithConstructor),
|
||||
preserveDeclarationOrder = preserveDeclarationOrder,
|
||||
pruneClass = pruneClass,
|
||||
treatInternalAsPrivate = treatInternalAsPrivate,
|
||||
@@ -232,12 +322,15 @@ private fun removePrivateDeclarationsForClass(
|
||||
klass.localDelegatedProperties.clear()
|
||||
}
|
||||
|
||||
private fun KmClass.copyFunShouldBeDeleted(removeDataClassCopy: Boolean): Boolean {
|
||||
return removeDataClassCopy && isData && constructors.none { !it.isSecondary }
|
||||
private fun copyFunShouldBeDeleted(klass: KmClass, removeDataClassCopy: Boolean): Boolean {
|
||||
return removeDataClassCopy && klass.isData && klass.constructors.none { !it.isSecondary }
|
||||
}
|
||||
|
||||
private fun Visibility.shouldRemove(treatInternalAsPrivate: Boolean): Boolean {
|
||||
return this == Visibility.PRIVATE || this == Visibility.PRIVATE_TO_THIS || this == Visibility.LOCAL || (treatInternalAsPrivate && this == Visibility.INTERNAL)
|
||||
private fun isPrivateVisibility(visibility: Visibility, treatInternalAsPrivate: Boolean): Boolean {
|
||||
return visibility == Visibility.PRIVATE ||
|
||||
visibility == Visibility.PRIVATE_TO_THIS ||
|
||||
visibility == Visibility.LOCAL ||
|
||||
(treatInternalAsPrivate && visibility == Visibility.INTERNAL)
|
||||
}
|
||||
|
||||
private fun removePrivateDeclarationsForDeclarationContainer(
|
||||
@@ -248,10 +341,10 @@ private fun removePrivateDeclarationsForDeclarationContainer(
|
||||
treatInternalAsPrivate: Boolean,
|
||||
) {
|
||||
container.functions.removeIf {
|
||||
pruneClass || it.visibility.shouldRemove(treatInternalAsPrivate) || (copyFunShouldBeDeleted && it.name == "copy")
|
||||
pruneClass || isPrivateVisibility(it.visibility, treatInternalAsPrivate) || (copyFunShouldBeDeleted && it.name == "copy")
|
||||
}
|
||||
container.properties.removeIf {
|
||||
pruneClass || it.visibility.shouldRemove(treatInternalAsPrivate)
|
||||
pruneClass || isPrivateVisibility(it.visibility, treatInternalAsPrivate)
|
||||
}
|
||||
|
||||
if (!preserveDeclarationOrder) {
|
||||
@@ -4,7 +4,12 @@ package org.jetbrains.bazel.jvm.kotlin
|
||||
import java.util.*
|
||||
|
||||
class ArgMap<T : Enum<T>> internal constructor(private val map: EnumMap<T, MutableList<String>>) {
|
||||
fun mandatorySingle(key: T): String = requireNotNull(optionalSingle(key)) { "$key is not optional" }
|
||||
fun mandatorySingle(key: T): String {
|
||||
val value = optionalSingle(key)
|
||||
requireNotNull(value) { "$key is not optional" }
|
||||
require(value.isNotBlank()) { "--$key should not be blank" }
|
||||
return value
|
||||
}
|
||||
|
||||
fun optionalSingle(key: T): String? {
|
||||
return map[key]?.let {
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package org.jetbrains.bazel.jvm.kotlin
|
||||
|
||||
import org.jetbrains.intellij.build.io.W_OVERWRITE
|
||||
import org.jetbrains.intellij.build.io.ZipArchiveOutputStream
|
||||
import org.jetbrains.intellij.build.io.ZipIndexWriter
|
||||
import org.jetbrains.intellij.build.io.writeZipUsingTempFile
|
||||
import org.jetbrains.kotlin.backend.common.output.OutputFileCollection
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.util.jar.Attributes
|
||||
import java.util.jar.JarFile
|
||||
import java.util.jar.Manifest
|
||||
import java.util.zip.ZipEntry
|
||||
import org.jetbrains.kotlin.backend.common.output.OutputFileCollection
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import java.nio.channels.FileChannel
|
||||
import java.nio.file.Files
|
||||
|
||||
data class JarOwner(
|
||||
@JvmField val jar: Path,
|
||||
@@ -22,8 +19,7 @@ data class JarOwner(
|
||||
@JvmField val aspect: String? = null,
|
||||
) {
|
||||
companion object {
|
||||
// These attributes are used by JavaBuilder, Turbine, and ijar.
|
||||
// They must all be kept in sync.
|
||||
// These attributes are used by JavaBuilder, Turbine, and `ijar`. They must all be kept in sync.
|
||||
@JvmField
|
||||
val TARGET_LABEL = Attributes.Name("Target-Label")
|
||||
|
||||
@@ -40,17 +36,7 @@ private fun writeManifest(manifest: Manifest, out: ZipArchiveOutputStream) {
|
||||
|
||||
val manifestOut = ByteArrayOutputStream()
|
||||
manifest.write(manifestOut)
|
||||
|
||||
val data = manifestOut.toByteArray()
|
||||
val size = data.size
|
||||
out.writeDataRawEntry(
|
||||
data = ByteBuffer.wrap(data),
|
||||
name = MANIFEST_NAME_BYTES,
|
||||
size = size,
|
||||
compressedSize = size,
|
||||
method = ZipEntry.STORED,
|
||||
crc = 0,
|
||||
)
|
||||
out.writeDataRawEntryWithoutCrc(data = ByteBuffer.wrap(manifestOut.toByteArray()), name = MANIFEST_NAME_BYTES)
|
||||
}
|
||||
|
||||
fun createJar(
|
||||
@@ -63,11 +49,7 @@ fun createJar(
|
||||
outFile.parent?.let {
|
||||
Files.createDirectories(it)
|
||||
}
|
||||
ZipArchiveOutputStream(
|
||||
channel = FileChannel.open(outFile, W_OVERWRITE),
|
||||
zipIndexWriter = ZipIndexWriter(indexWriter = null),
|
||||
).use { out ->
|
||||
|
||||
writeZipUsingTempFile(outFile, indexWriter = null) { out ->
|
||||
val manifest = Manifest()
|
||||
val attributes = manifest.mainAttributes
|
||||
attributes.put(Attributes.Name.MANIFEST_VERSION, "1.0")
|
||||
@@ -83,14 +65,7 @@ fun createJar(
|
||||
|
||||
for (outputFile in outputFiles.asList()) {
|
||||
val data = outputFile.asByteArray()
|
||||
out.writeDataRawEntry(
|
||||
data = ByteBuffer.wrap(data),
|
||||
name = outputFile.relativePath.toByteArray(),
|
||||
size = data.size,
|
||||
compressedSize = data.size,
|
||||
method = ZipEntry.STORED,
|
||||
crc = 0,
|
||||
)
|
||||
out.writeDataRawEntryWithoutCrc(data = ByteBuffer.wrap(data), name = outputFile.relativePath.toByteArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
load("@rules_java//java:defs.bzl", "java_binary")
|
||||
load("@rules_jvm//:jvm.bzl", "jvm_import")
|
||||
load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
|
||||
load("//:src/jvm-args.bzl", "get_jvm_flags")
|
||||
|
||||
kt_jvm_library(
|
||||
name = "worker-lib",
|
||||
@@ -49,20 +50,12 @@ java_binary(
|
||||
"@kotlin-serialization-compiler-plugin//file",
|
||||
],
|
||||
main_class = "org.jetbrains.bazel.jvm.jps.JpsBuildWorker",
|
||||
jvm_flags = [
|
||||
"--add-opens=java.base/java.util.concurrent=ALL-UNNAMED",
|
||||
"--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED",
|
||||
"--add-opens=java.base/java.util.concurrent.locks=ALL-UNNAMED",
|
||||
"--add-opens=java.base/java.nio=ALL-UNNAMED",
|
||||
"-Xms1024m",
|
||||
"-Xmx6144m",
|
||||
"-Djava.awt.headless=true",
|
||||
"-Dapple.awt.UIElement=true",
|
||||
jvm_flags = get_jvm_flags([
|
||||
"-Dkotlin.environment.keepalive=true",
|
||||
"-Djps.use.experimental.storage=true",
|
||||
"-Djps.kotlin.home=$(rlocationpath @kotlinc//:kotlinc_dist)",
|
||||
"-Dorg.jetbrains.kotlin.kotlin-serialization-compiler-plugin.path=$(rlocationpath @kotlin-serialization-compiler-plugin//file)",
|
||||
],
|
||||
]),
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
@@ -74,18 +67,10 @@ java_binary(
|
||||
"@kotlin-serialization-compiler-plugin//file",
|
||||
],
|
||||
main_class = "org.jetbrains.bazel.jvm.jps.TestJpsBuildWorker",
|
||||
jvm_flags = [
|
||||
"--add-opens=java.base/java.util.concurrent=ALL-UNNAMED",
|
||||
"--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED",
|
||||
"--add-opens=java.base/java.util.concurrent.locks=ALL-UNNAMED",
|
||||
"--add-opens=java.base/java.nio=ALL-UNNAMED",
|
||||
"-Xms1024m",
|
||||
"-Xmx6144m",
|
||||
"-Djava.awt.headless=true",
|
||||
"-Dapple.awt.UIElement=true",
|
||||
jvm_flags = get_jvm_flags([
|
||||
"-Dkotlin.environment.keepalive=true",
|
||||
"-Djps.use.experimental.storage=true",
|
||||
"-Djps.kotlin.home=$(rlocationpath @kotlinc//:kotlinc_dist)",
|
||||
"-Dorg.jetbrains.kotlin.kotlin-serialization-compiler-plugin.path=$(rlocationpath @kotlin-serialization-compiler-plugin//file)",
|
||||
],
|
||||
]),
|
||||
)
|
||||
|
||||
@@ -47,7 +47,6 @@ internal fun loadJpsModel(
|
||||
classPathRootDir: Path,
|
||||
classOutDir: Path,
|
||||
dependencyFileToDigest: Map<Path, ByteArray>,
|
||||
messageHandler: ConsoleMessageHandler,
|
||||
): Pair<JpsModel, TargetConfigurationDigestContainer> {
|
||||
val model = jpsElementFactory.createModel()
|
||||
|
||||
@@ -61,7 +60,7 @@ internal fun loadJpsModel(
|
||||
// extension.loadModuleOptions not needed for us (not implemented for java)
|
||||
val module = JpsModuleImpl(
|
||||
JpsJavaModuleType.INSTANCE,
|
||||
args.mandatorySingle(JvmBuilderFlags.TARGET_LABEL),
|
||||
args.mandatorySingle(JvmBuilderFlags.KOTLIN_MODULE_NAME),
|
||||
jpsElementFactory.createDummyElement(),
|
||||
)
|
||||
val jpsJavaModuleExtension = JpsJavaExtensionService.getInstance().getOrCreateModuleExtension(module)
|
||||
@@ -79,10 +78,6 @@ internal fun loadJpsModel(
|
||||
module.addSourceRoot(JpsModuleSourceRootImpl(source.toUri().toString(), JavaSourceRootType.SOURCE, properties))
|
||||
}
|
||||
|
||||
if (messageHandler.isDebugEnabled) {
|
||||
messageHandler.info("sources:\n ${sources.joinToString(separator = "\n ") { it.invariantSeparatorsPathString }}\n")
|
||||
}
|
||||
|
||||
configureKotlinCompiler(module = module, args = args, classPathRootDir = classPathRootDir, configHash = configHash)
|
||||
|
||||
val dependencyList = module.dependenciesList
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
package org.jetbrains.bazel.jvm.jps
|
||||
|
||||
import org.jetbrains.bazel.jvm.jps.impl.BazelKotlinBuilder
|
||||
import org.jetbrains.jps.backwardRefs.JavaBackwardReferenceIndexBuilder
|
||||
import org.jetbrains.jps.builders.AdditionalRootsProviderService
|
||||
import org.jetbrains.jps.builders.PreloadedDataExtension
|
||||
import org.jetbrains.jps.builders.impl.java.JavacCompilerTool
|
||||
@@ -13,11 +11,9 @@ import org.jetbrains.jps.builders.java.JavaCompilingTool
|
||||
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType
|
||||
import org.jetbrains.jps.incremental.BuilderService
|
||||
import org.jetbrains.jps.incremental.ModuleLevelBuilder
|
||||
import org.jetbrains.jps.incremental.java.JavaBuilder
|
||||
import org.jetbrains.jps.model.*
|
||||
import org.jetbrains.jps.service.JpsServiceManager
|
||||
import org.jetbrains.jps.service.SharedThreadPool
|
||||
import org.jetbrains.kotlin.jps.incremental.KotlinCompilerReferenceIndexBuilder
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
@@ -117,14 +113,8 @@ private object BazelJavaBuilderService : BuilderService() {
|
||||
// remove ResourcesTargetType.ALL_TYPES and ProjectDependenciesResolver.ProjectDependenciesResolvingTargetType.INSTANCE
|
||||
override fun getTargetTypes() = listOf(JavaModuleBuildTargetType.PRODUCTION)
|
||||
|
||||
// remove RmiStubsGenerator and DependencyResolvingBuilder
|
||||
// remove RmiStubsGenerator and DependencyResolvingBuilder
|
||||
override fun createModuleLevelBuilders(): List<ModuleLevelBuilder> {
|
||||
return listOf(
|
||||
JavaBuilder(SharedThreadPool.getInstance()),
|
||||
//NotNullInstrumentingBuilder(),
|
||||
JavaBackwardReferenceIndexBuilder(),
|
||||
BazelKotlinBuilder(),
|
||||
KotlinCompilerReferenceIndexBuilder(),
|
||||
)
|
||||
throw IllegalStateException("must not be called")
|
||||
}
|
||||
}
|
||||
149
build/jvm-rules/src/jps-builder/BuildStateStorage.kt
Normal file
149
build/jvm-rules/src/jps-builder/BuildStateStorage.kt
Normal file
@@ -0,0 +1,149 @@
|
||||
@file:Suppress("UnstableApiUsage")
|
||||
|
||||
package org.jetbrains.bazel.jvm.jps
|
||||
|
||||
import com.google.protobuf.CodedInputStream
|
||||
import com.google.protobuf.CodedOutputStream
|
||||
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream
|
||||
import org.jetbrains.intellij.build.io.unmapBuffer
|
||||
import org.jetbrains.intellij.build.io.writeFileUsingTempFile
|
||||
import org.jetbrains.jps.incremental.storage.PathTypeAwareRelativizer
|
||||
import org.jetbrains.jps.incremental.storage.RelativePathType
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.enumSetOf
|
||||
import java.io.IOException
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.MappedByteBuffer
|
||||
import java.nio.channels.FileChannel
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.NoSuchFileException
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.StandardOpenOption
|
||||
import java.util.zip.CRC32
|
||||
|
||||
private const val STATE_FILE_FORMAT_VERSION = 1
|
||||
|
||||
private val WRITE_FILE_OPTION = enumSetOf(StandardOpenOption.WRITE, StandardOpenOption.CREATE)
|
||||
private val READ_FILE_OPTION = enumSetOf(StandardOpenOption.READ)
|
||||
|
||||
internal fun loadBuildState(
|
||||
buildStateFile: Path,
|
||||
relativizer: PathTypeAwareRelativizer,
|
||||
log: RequestLog,
|
||||
): HashMap<Path, SourceDescriptor>? {
|
||||
var map: MappedByteBuffer? = null
|
||||
try {
|
||||
map = FileChannel.open(buildStateFile, READ_FILE_OPTION).use {
|
||||
it.map(FileChannel.MapMode.READ_ONLY, 0, it.size())
|
||||
}
|
||||
return doLoad(map, relativizer)
|
||||
}
|
||||
catch (_: NoSuchFileException) {
|
||||
return null
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
log.error("cannot load $buildStateFile", e)
|
||||
// will be deleted by caller
|
||||
return null
|
||||
}
|
||||
finally {
|
||||
map?.let { unmapBuffer(it) }
|
||||
}
|
||||
}
|
||||
|
||||
internal fun saveBuildState(buildStateFile: Path, list: Array<SourceDescriptor>, relativizer: PathTypeAwareRelativizer) {
|
||||
val byteArrayOutputStream = BufferExposingByteArrayOutputStream()
|
||||
val output = CodedOutputStream.newInstance(byteArrayOutputStream)
|
||||
output.writeFixed32NoTag(STATE_FILE_FORMAT_VERSION)
|
||||
// allocate for checksum
|
||||
output.writeFixed64NoTag(0L)
|
||||
|
||||
output.writeUInt32NoTag(list.size)
|
||||
for (descriptor in list) {
|
||||
output.writeStringNoTag(relativizer.toRelative(descriptor.sourceFile, RelativePathType.SOURCE))
|
||||
output.writeByteArrayNoTag(descriptor.digest)
|
||||
val outputs = descriptor.outputs
|
||||
if (outputs == null) {
|
||||
output.writeUInt32NoTag(0)
|
||||
}
|
||||
else {
|
||||
output.writeUInt32NoTag(outputs.size)
|
||||
for (outputPath in outputs) {
|
||||
output.writeStringNoTag(outputPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// allocate for checksum
|
||||
output.writeFixed64NoTag(0L)
|
||||
output.flush()
|
||||
|
||||
val data = byteArrayOutputStream.internalBuffer
|
||||
val dataSize = byteArrayOutputStream.size()
|
||||
|
||||
val crc32 = CRC32()
|
||||
val dataOffset = Int.SIZE_BYTES + Long.SIZE_BYTES
|
||||
crc32.update(data, dataOffset, dataSize - dataOffset)
|
||||
val checksum = crc32.value
|
||||
|
||||
CodedOutputStream.newInstance(data, Int.SIZE_BYTES, dataOffset).writeFixed64NoTag(checksum)
|
||||
CodedOutputStream.newInstance(data, dataSize - Long.SIZE_BYTES, dataOffset).writeFixed64NoTag(checksum)
|
||||
|
||||
val parent = buildStateFile.parent
|
||||
Files.createDirectories(parent)
|
||||
writeFileUsingTempFile(buildStateFile) { tempFile ->
|
||||
FileChannel.open(tempFile, WRITE_FILE_OPTION).use {
|
||||
it.write(ByteBuffer.wrap(data, 0, dataSize), 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun doLoad(byteBuffer: MappedByteBuffer, relativizer: PathTypeAwareRelativizer): HashMap<Path, SourceDescriptor> {
|
||||
val fileSize = byteBuffer.limit()
|
||||
|
||||
val crc32 = CRC32()
|
||||
byteBuffer.mark()
|
||||
byteBuffer.position(Int.SIZE_BYTES + Long.SIZE_BYTES).limit(fileSize - Long.SIZE_BYTES)
|
||||
crc32.update(byteBuffer)
|
||||
val expectedChecksum = crc32.value
|
||||
byteBuffer.position(0).limit(fileSize)
|
||||
|
||||
val input = CodedInputStream.newInstance(byteBuffer)
|
||||
|
||||
val formatVersion = input.readRawLittleEndian32()
|
||||
if (formatVersion != STATE_FILE_FORMAT_VERSION) {
|
||||
throw IOException("format version mismatch: expected $STATE_FILE_FORMAT_VERSION, actual $formatVersion")
|
||||
}
|
||||
|
||||
val storedChecksum = input.readRawLittleEndian64()
|
||||
if (storedChecksum != expectedChecksum) {
|
||||
throw IOException("checksum mismatch: expected $expectedChecksum, actual $storedChecksum (file start)")
|
||||
}
|
||||
|
||||
val size = input.readRawVarint32()
|
||||
val map = HashMap<Path, SourceDescriptor>(size)
|
||||
repeat(size) {
|
||||
val source = input.readStringRequireUtf8()
|
||||
val digest = input.readByteArray()
|
||||
val inputSize = input.readRawVarint32()
|
||||
val outputs = if (inputSize == 0) {
|
||||
null
|
||||
}
|
||||
else {
|
||||
Array(inputSize) { input.readStringRequireUtf8() }.asList()
|
||||
}
|
||||
|
||||
val sourceFile = relativizer.toAbsoluteFile(source, RelativePathType.SOURCE)
|
||||
map.put(sourceFile, SourceDescriptor(
|
||||
sourceFile = sourceFile,
|
||||
digest = digest,
|
||||
outputs = outputs,
|
||||
))
|
||||
}
|
||||
|
||||
val storedChecksumEnd = input.readRawLittleEndian64()
|
||||
if (storedChecksumEnd != expectedChecksum) {
|
||||
throw IOException("checksum mismatch: expected $expectedChecksum, actual $storedChecksumEnd (file end)")
|
||||
}
|
||||
|
||||
return map
|
||||
}
|
||||
@@ -5,10 +5,8 @@ package org.jetbrains.bazel.jvm.jps
|
||||
|
||||
import com.intellij.openapi.diagnostic.IdeaLogRecordFormatter
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import kotlinx.coroutines.CoroutineName
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import com.intellij.openapi.util.io.FileUtilRt
|
||||
import kotlinx.coroutines.*
|
||||
import org.jetbrains.bazel.jvm.WorkRequest
|
||||
import org.jetbrains.bazel.jvm.WorkRequestExecutor
|
||||
import org.jetbrains.bazel.jvm.jps.impl.*
|
||||
@@ -21,13 +19,18 @@ import org.jetbrains.bazel.jvm.logging.LogWriter
|
||||
import org.jetbrains.bazel.jvm.processRequests
|
||||
import org.jetbrains.jps.api.CanceledStatus
|
||||
import org.jetbrains.jps.api.GlobalOptions
|
||||
import org.jetbrains.jps.backwardRefs.JavaBackwardReferenceIndexBuilder
|
||||
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType
|
||||
import org.jetbrains.jps.incremental.*
|
||||
import org.jetbrains.jps.incremental.CompileContextImpl
|
||||
import org.jetbrains.jps.incremental.CompileScopeImpl
|
||||
import org.jetbrains.jps.incremental.ModuleBuildTarget
|
||||
import org.jetbrains.jps.incremental.RebuildRequestedException
|
||||
import org.jetbrains.jps.incremental.java.JavaBuilder
|
||||
import org.jetbrains.jps.incremental.relativizer.PathRelativizerService
|
||||
import org.jetbrains.jps.incremental.storage.ExperimentalSourceToOutputMapping
|
||||
import org.jetbrains.jps.incremental.storage.StorageManager
|
||||
import org.jetbrains.jps.model.JpsModel
|
||||
import org.jetbrains.kotlin.config.IncrementalCompilation
|
||||
import org.jetbrains.kotlin.jps.incremental.KotlinCompilerReferenceIndexBuilder
|
||||
import java.io.Writer
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
@@ -66,10 +69,13 @@ object JpsBuildWorker : WorkRequestExecutor {
|
||||
|
||||
override suspend fun execute(request: WorkRequest, writer: Writer, baseDir: Path): Int {
|
||||
val dependencyFileToDigest = HashMap<Path, ByteArray>()
|
||||
val sourceFileToDigest = HashMap<Path, ByteArray>(request.inputs.size)
|
||||
val sources = ArrayList<Path>()
|
||||
for (input in request.inputs) {
|
||||
if (input.path.endsWith(".kt") || input.path.endsWith(".java")) {
|
||||
sources.add(baseDir.resolve(input.path).normalize())
|
||||
val file = baseDir.resolve(input.path).normalize()
|
||||
sources.add(file)
|
||||
sourceFileToDigest.put(file, input.digest)
|
||||
}
|
||||
else if (input.path.endsWith(".jar")) {
|
||||
dependencyFileToDigest.put(baseDir.resolve(input.path).normalize(), input.digest)
|
||||
@@ -83,6 +89,7 @@ object JpsBuildWorker : WorkRequestExecutor {
|
||||
sources = sources,
|
||||
dependencyFileToDigest = dependencyFileToDigest,
|
||||
isDebugEnabled = request.verbosity > 0,
|
||||
sourceFileToDigest = sourceFileToDigest,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -93,9 +100,10 @@ internal suspend fun buildUsingJps(
|
||||
out: Writer,
|
||||
sources: List<Path>,
|
||||
dependencyFileToDigest: Map<Path, ByteArray>,
|
||||
sourceFileToDigest: Map<Path, ByteArray>,
|
||||
isDebugEnabled: Boolean,
|
||||
): Int {
|
||||
val messageHandler = ConsoleMessageHandler(out = out, isDebugEnabled = isDebugEnabled)
|
||||
val log = RequestLog(out = out, isDebugEnabled = isDebugEnabled)
|
||||
|
||||
val abiJar = args.optionalSingle(JvmBuilderFlags.ABI_OUT)?.let { baseDir.resolve(it).normalize() }
|
||||
val outJar = baseDir.resolve(args.mandatorySingle(JvmBuilderFlags.OUT)).normalize()
|
||||
@@ -111,8 +119,7 @@ internal suspend fun buildUsingJps(
|
||||
args = args,
|
||||
classPathRootDir = baseDir,
|
||||
classOutDir = classOutDir,
|
||||
dependencyFileToDigest = dependencyFileToDigest,
|
||||
messageHandler = messageHandler
|
||||
dependencyFileToDigest = dependencyFileToDigest
|
||||
)
|
||||
val moduleTarget = BazelModuleBuildTarget(
|
||||
outDir = classOutDir,
|
||||
@@ -123,9 +130,28 @@ internal suspend fun buildUsingJps(
|
||||
val relativizer = createPathRelativizer(baseDir = baseDir, classOutDir = classOutDir)
|
||||
|
||||
// if class output dir doesn't exist, make sure that we do not to use existing cache - pass `isRebuild` as true in this case
|
||||
val ok = initAndBuild(
|
||||
isRebuild = Files.notExists(classOutDir),
|
||||
messageHandler = messageHandler,
|
||||
var isRebuild = Files.notExists(classOutDir)
|
||||
|
||||
val buildStateFile = dataDir.resolve("$prefix-state-v1.db")
|
||||
val typeAwareRelativizer = relativizer.typeAwareRelativizer!!
|
||||
val buildState = loadBuildState(buildStateFile, typeAwareRelativizer, log)
|
||||
if (buildState == null) {
|
||||
FileUtilRt.deleteRecursively(dataDir)
|
||||
FileUtilRt.deleteRecursively(classOutDir)
|
||||
|
||||
isRebuild = true
|
||||
}
|
||||
|
||||
val buildDataProvider = BazelBuildDataProvider(
|
||||
relativizer = typeAwareRelativizer,
|
||||
actualDigestMap = sourceFileToDigest,
|
||||
sourceToDescriptor = buildState ?: HashMap(sourceFileToDigest.size),
|
||||
storeFile = buildStateFile,
|
||||
)
|
||||
|
||||
var exitCode = initAndBuild(
|
||||
isRebuild = isRebuild,
|
||||
messageHandler = log,
|
||||
dataDir = dataDir,
|
||||
classOutDir = classOutDir,
|
||||
targetDigests = targetDigests,
|
||||
@@ -134,11 +160,13 @@ internal suspend fun buildUsingJps(
|
||||
abiJar = abiJar,
|
||||
relativizer = relativizer,
|
||||
jpsModel = jpsModel,
|
||||
buildDataProvider = buildDataProvider,
|
||||
)
|
||||
if (!ok) {
|
||||
initAndBuild(
|
||||
if (exitCode == -1) {
|
||||
log.resetState()
|
||||
exitCode = initAndBuild(
|
||||
isRebuild = true,
|
||||
messageHandler = messageHandler,
|
||||
messageHandler = log,
|
||||
dataDir = dataDir,
|
||||
classOutDir = classOutDir,
|
||||
targetDigests = targetDigests,
|
||||
@@ -147,15 +175,16 @@ internal suspend fun buildUsingJps(
|
||||
abiJar = abiJar,
|
||||
relativizer = relativizer,
|
||||
jpsModel = jpsModel,
|
||||
buildDataProvider = buildDataProvider,
|
||||
)
|
||||
}
|
||||
|
||||
return if (messageHandler.hasErrors()) 1 else 0
|
||||
return exitCode
|
||||
}
|
||||
|
||||
private suspend fun initAndBuild(
|
||||
isRebuild: Boolean,
|
||||
messageHandler: ConsoleMessageHandler,
|
||||
messageHandler: RequestLog,
|
||||
dataDir: Path,
|
||||
classOutDir: Path,
|
||||
targetDigests: TargetConfigurationDigestContainer,
|
||||
@@ -164,9 +193,8 @@ private suspend fun initAndBuild(
|
||||
abiJar: Path?,
|
||||
relativizer: PathRelativizerService,
|
||||
jpsModel: JpsModel,
|
||||
): Boolean {
|
||||
messageHandler.resetState()
|
||||
|
||||
buildDataProvider: BazelBuildDataProvider,
|
||||
): Int {
|
||||
if (messageHandler.isDebugEnabled) {
|
||||
messageHandler.info("build (isRebuild=$isRebuild)")
|
||||
}
|
||||
@@ -180,7 +208,13 @@ private suspend fun initAndBuild(
|
||||
}
|
||||
|
||||
try {
|
||||
val projectDescriptor = storageInitializer.createProjectDescriptor(messageHandler, jpsModel, moduleTarget, relativizer)
|
||||
val projectDescriptor = storageInitializer.createProjectDescriptor(
|
||||
messageHandler = messageHandler,
|
||||
jpsModel = jpsModel,
|
||||
moduleTarget = moduleTarget,
|
||||
relativizer = relativizer,
|
||||
buildDataProvider = buildDataProvider,
|
||||
)
|
||||
try {
|
||||
val compileScope = CompileScopeImpl(
|
||||
/* types = */ java.util.Set.of(JavaModuleBuildTargetType.PRODUCTION),
|
||||
@@ -199,27 +233,48 @@ private suspend fun initAndBuild(
|
||||
override fun isCanceled(): Boolean = !coroutineContext.isActive
|
||||
},
|
||||
)
|
||||
JpsProjectBuilder(
|
||||
builderRegistry = BuilderRegistry.getInstance(),
|
||||
messageHandler = messageHandler,
|
||||
|
||||
val builders = arrayOf(
|
||||
JavaBuilder(BazelSharedThreadPool),
|
||||
//NotNullInstrumentingBuilder(),
|
||||
JavaBackwardReferenceIndexBuilder(),
|
||||
BazelKotlinBuilder(isKotlinBuilderInDumbMode = false, log = messageHandler),
|
||||
KotlinCompilerReferenceIndexBuilder(),
|
||||
)
|
||||
builders.sortBy { it.category.ordinal }
|
||||
val exitCode = JpsProjectBuilder(
|
||||
log = messageHandler,
|
||||
isCleanBuild = storageInitializer.isCleanBuild,
|
||||
).build(context, moduleTarget)
|
||||
if (!messageHandler.hasErrors()) {
|
||||
postBuild(
|
||||
messageHandler = messageHandler,
|
||||
moduleTarget = moduleTarget,
|
||||
outJar = outJar,
|
||||
abiJar = abiJar,
|
||||
classOutDir = classOutDir,
|
||||
context = context,
|
||||
targetDigests = targetDigests,
|
||||
storageManager = storageManager,
|
||||
)
|
||||
dataManager = buildDataProvider,
|
||||
).build(context = context, moduleTarget = moduleTarget, builders = builders)
|
||||
if (exitCode == 0) {
|
||||
try {
|
||||
postBuild(
|
||||
messageHandler = messageHandler,
|
||||
moduleTarget = moduleTarget,
|
||||
outJar = outJar,
|
||||
abiJar = abiJar,
|
||||
classOutDir = classOutDir,
|
||||
context = context,
|
||||
targetDigests = targetDigests,
|
||||
storageManager = storageManager,
|
||||
buildDataProvider = buildDataProvider,
|
||||
)
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
// in case of any error during packaging - clear build
|
||||
storageManager.forceClose()
|
||||
projectDescriptor.release()
|
||||
|
||||
storageInitializer.clearStorage()
|
||||
|
||||
throw e
|
||||
}
|
||||
}
|
||||
return true
|
||||
return exitCode
|
||||
}
|
||||
catch (_: RebuildRequestedException) {
|
||||
return false
|
||||
return -1
|
||||
}
|
||||
finally {
|
||||
projectDescriptor.release()
|
||||
@@ -231,7 +286,7 @@ private suspend fun initAndBuild(
|
||||
}
|
||||
|
||||
private suspend fun postBuild(
|
||||
messageHandler: ConsoleMessageHandler,
|
||||
messageHandler: RequestLog,
|
||||
moduleTarget: ModuleBuildTarget,
|
||||
outJar: Path,
|
||||
abiJar: Path?,
|
||||
@@ -239,9 +294,11 @@ private suspend fun postBuild(
|
||||
context: CompileContextImpl,
|
||||
targetDigests: TargetConfigurationDigestContainer,
|
||||
storageManager: StorageManager,
|
||||
buildDataProvider: BazelBuildDataProvider,
|
||||
) {
|
||||
coroutineScope {
|
||||
val dataManager = context.projectDescriptor.dataManager
|
||||
val sourceDescriptors = buildDataProvider.getFinalList()
|
||||
launch(CoroutineName("save caches")) {
|
||||
// save config state only in the end
|
||||
saveTargetState(
|
||||
@@ -251,18 +308,21 @@ private suspend fun postBuild(
|
||||
)
|
||||
|
||||
dataManager.flush(/* memoryCachesOnly = */ false)
|
||||
|
||||
ensureActive()
|
||||
|
||||
saveBuildState(buildDataProvider.storeFile, sourceDescriptors, relativizer = buildDataProvider.relativizer)
|
||||
}
|
||||
|
||||
launch(CoroutineName("create output JAR and ABI JAR")) {
|
||||
// pack to jar
|
||||
messageHandler.measureTime("pack and abi") {
|
||||
val sourceToOutputMap = dataManager.getSourceToOutputMap(moduleTarget) as ExperimentalSourceToOutputMapping
|
||||
packageToJar(
|
||||
outJar = outJar,
|
||||
abiJar = abiJar,
|
||||
sourceToOutputMap = sourceToOutputMap,
|
||||
sourceDescriptors = sourceDescriptors,
|
||||
classOutDir = classOutDir,
|
||||
messageHandler = messageHandler,
|
||||
log = messageHandler,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ package org.jetbrains.bazel.jvm.jps
|
||||
import com.intellij.openapi.util.io.FileUtilRt
|
||||
import kotlinx.coroutines.ensureActive
|
||||
import org.h2.mvstore.MVStore
|
||||
import org.jetbrains.bazel.jvm.jps.impl.BazelBuildDataProvider
|
||||
import org.jetbrains.bazel.jvm.jps.impl.BazelModuleBuildTarget
|
||||
import org.jetbrains.bazel.jvm.jps.impl.loadJpsProject
|
||||
import org.jetbrains.bazel.jvm.jps.state.TargetConfigurationDigestContainer
|
||||
@@ -33,7 +34,7 @@ internal class StorageInitializer(private val dataDir: Path, private val classOu
|
||||
var isCleanBuild: Boolean = false
|
||||
private set
|
||||
|
||||
fun clearAndInit(messageHandler: ConsoleMessageHandler): StorageManager {
|
||||
fun clearAndInit(messageHandler: RequestLog): StorageManager {
|
||||
isCheckRebuildRequired = false
|
||||
wasCleared = true
|
||||
isCleanBuild = true
|
||||
@@ -47,7 +48,7 @@ internal class StorageInitializer(private val dataDir: Path, private val classOu
|
||||
.also { storageManager = it }
|
||||
}
|
||||
|
||||
suspend fun init(messageHandler: ConsoleMessageHandler, targetDigests: TargetConfigurationDigestContainer): StorageManager {
|
||||
suspend fun init(messageHandler: RequestLog, targetDigests: TargetConfigurationDigestContainer): StorageManager {
|
||||
val logger = createLogger(messageHandler)
|
||||
coroutineContext.ensureActive()
|
||||
|
||||
@@ -100,7 +101,7 @@ internal class StorageInitializer(private val dataDir: Path, private val classOu
|
||||
return tryOpenMvStore(file = cacheDbFile, readOnly = false, autoCommitDelay = 0, logger = logger)
|
||||
}
|
||||
|
||||
private fun createLogger(messageHandler: ConsoleMessageHandler): StoreLogger {
|
||||
private fun createLogger(messageHandler: RequestLog): StoreLogger {
|
||||
return { m: String, e: Throwable, isWarn: Boolean ->
|
||||
val message = "$m: ${e.stackTraceToString()}"
|
||||
if (isWarn) {
|
||||
@@ -113,10 +114,11 @@ internal class StorageInitializer(private val dataDir: Path, private val classOu
|
||||
}
|
||||
|
||||
fun createProjectDescriptor(
|
||||
messageHandler: ConsoleMessageHandler,
|
||||
messageHandler: RequestLog,
|
||||
jpsModel: JpsModel,
|
||||
moduleTarget: BazelModuleBuildTarget,
|
||||
relativizer: PathRelativizerService,
|
||||
buildDataProvider: BazelBuildDataProvider,
|
||||
): ProjectDescriptor {
|
||||
try {
|
||||
return loadJpsProject(
|
||||
@@ -128,6 +130,7 @@ internal class StorageInitializer(private val dataDir: Path, private val classOu
|
||||
moduleTarget = moduleTarget,
|
||||
relativizer = relativizer,
|
||||
storageManager = storageManager!!,
|
||||
buildDataProvider = buildDataProvider,
|
||||
)
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
@@ -144,10 +147,11 @@ internal class StorageInitializer(private val dataDir: Path, private val classOu
|
||||
jpsModel = jpsModel,
|
||||
moduleTarget = moduleTarget,
|
||||
relativizer = relativizer,
|
||||
buildDataProvider = buildDataProvider,
|
||||
)
|
||||
}
|
||||
|
||||
private fun clearStorage() {
|
||||
fun clearStorage() {
|
||||
isCleanBuild = true
|
||||
wasCleared = true
|
||||
isCheckRebuildRequired = false
|
||||
|
||||
@@ -1,333 +1,57 @@
|
||||
// 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.bazel.jvm.jps
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.jetbrains.bazel.jvm.TestModules
|
||||
import org.jetbrains.bazel.jvm.collectSources
|
||||
import org.jetbrains.bazel.jvm.getTestWorkerPaths
|
||||
import org.jetbrains.bazel.jvm.kotlin.JvmBuilderFlags
|
||||
import org.jetbrains.bazel.jvm.kotlin.parseArgs
|
||||
import org.jetbrains.bazel.jvm.logging.LogWriter
|
||||
import org.jetbrains.bazel.jvm.performTestInvocation
|
||||
import java.io.PrintStream
|
||||
import java.io.StringWriter
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.security.MessageDigest
|
||||
import kotlin.io.path.ExperimentalPathApi
|
||||
import kotlin.io.path.invariantSeparatorsPathString
|
||||
import kotlin.io.path.walk
|
||||
|
||||
//private val dateTimeFormatter = DateTimeFormatter.ofPattern("yy-MM-dd_T-HH-mm-ss")
|
||||
|
||||
object TestJpsBuildWorker {
|
||||
internal object TestJpsBuildWorker {
|
||||
@OptIn(ExperimentalPathApi::class)
|
||||
@JvmStatic
|
||||
fun main(startupArgs: Array<String>) {
|
||||
val userHomeDir = Path.of(System.getProperty("user.home"))
|
||||
val out = StringWriter()
|
||||
try {
|
||||
@Suppress("SpellCheckingInspection")
|
||||
val baseDir = Path.of("/private/var/tmp/_bazel_develar/c002af20f6ada3e2667e9e2ceaf2ceca/execroot/_main")
|
||||
val testPaths = getTestWorkerPaths()
|
||||
val baseDir = testPaths.baseDir
|
||||
//val sources = collectSources(sourceDirPath = "platform/platform-impl/src", paths = testPaths)
|
||||
|
||||
//val sources = Files.newDirectoryStream(userHomeDir.resolve("projects/idea/community/platform/util/xmlDom/src")).use { it.toList() }
|
||||
val ideaProjectDirName = if (Runtime.getRuntime().availableProcessors() >= 20) "idea-push" else "idea-second"
|
||||
val communityDir = userHomeDir.resolve("projects/$ideaProjectDirName/community")
|
||||
val sources = communityDir.resolve("platform/platform-impl/src")
|
||||
.walk()
|
||||
.filter {
|
||||
val p = it.toString()
|
||||
p.endsWith(".kt") || p.endsWith(".java")
|
||||
}
|
||||
.map { "../community+/" + communityDir.relativize(it).invariantSeparatorsPathString }
|
||||
.sorted()
|
||||
.map { baseDir.resolve(it).normalize() }
|
||||
.toList()
|
||||
val testModule = TestModules.PLATFORM_BOOTSTRAP
|
||||
val sources = collectSources(sourceDirPath = testModule.sourcePath, paths = testPaths)
|
||||
val testParams = testModule.getParams(baseDir)
|
||||
|
||||
require(sources.isNotEmpty())
|
||||
performTestInvocation { out, coroutineScope ->
|
||||
// IDEA console is bad and outdated, write to file and use modern tooling to view logs
|
||||
// ${dateTimeFormatter.format(LocalDateTime.now())}
|
||||
val logFile = testPaths.userHomeDir.resolve("kotlin-worker/log.ndjson")
|
||||
configureGlobalJps(LogWriter(coroutineScope, PrintStream(Files.newOutputStream(logFile)), closeWriterOnShutdown = true))
|
||||
|
||||
runBlocking(Dispatchers.Default) {
|
||||
// IDEA console is bad and outdated, write to file and use modern tooling to view logs
|
||||
// ${dateTimeFormatter.format(LocalDateTime.now())}
|
||||
val logFile = userHomeDir.resolve("kotlin-worker/log.ndjson")
|
||||
configureGlobalJps(LogWriter(this, PrintStream(Files.newOutputStream(logFile)), closeWriterOnShutdown = true))
|
||||
|
||||
val args = parseArgs(testParams.trimStart().lines().toTypedArray())
|
||||
val messageDigest = MessageDigest.getInstance("SHA-256")
|
||||
buildUsingJps(
|
||||
baseDir = baseDir,
|
||||
args = args,
|
||||
out = out,
|
||||
sources = sources,
|
||||
dependencyFileToDigest = args.optionalList(JvmBuilderFlags.CLASSPATH).associate {
|
||||
val file = baseDir.resolve(it).normalize()
|
||||
val digest = messageDigest.digest(Files.readAllBytes(file))
|
||||
messageDigest.reset()
|
||||
file to digest
|
||||
},
|
||||
isDebugEnabled = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
finally {
|
||||
System.out.append(out.toString())
|
||||
val args = parseArgs(testParams.lines().toTypedArray())
|
||||
val messageDigest = MessageDigest.getInstance("SHA-256")
|
||||
buildUsingJps(
|
||||
baseDir = baseDir,
|
||||
args = args,
|
||||
out = out,
|
||||
sources = sources,
|
||||
dependencyFileToDigest = args.optionalList(JvmBuilderFlags.CLASSPATH).associate {
|
||||
val file = baseDir.resolve(it).normalize()
|
||||
val digest = messageDigest.digest(Files.readAllBytes(file))
|
||||
messageDigest.reset()
|
||||
file to digest
|
||||
},
|
||||
sourceFileToDigest = sources.associate {
|
||||
val file = baseDir.resolve(it).normalize()
|
||||
val digest = messageDigest.digest(Files.readAllBytes(file))
|
||||
messageDigest.reset()
|
||||
file to digest
|
||||
},
|
||||
isDebugEnabled = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
private const val testParams = """
|
||||
--target_label
|
||||
@community//platform/platform-impl:ide-impl
|
||||
--rule_kind
|
||||
kt_jvm_library
|
||||
--kotlin_module_name
|
||||
intellij.platform.ide.impl
|
||||
--deps_artifacts
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/jps/model-impl/model-impl.jdeps
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/observable/ide-observable-kt.jdeps
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/rd-platform-community/rd-community-kt.jdeps
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util-class-loader/util-classLoader.jdeps
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util/zip/zip.jdeps
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util/xmlDom/xmlDom-kt.jdeps
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util/jdom/jdom.jdeps
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util/text-matching/text-matching.jdeps
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/platform-impl/rpc/ide-rpc-kt.jdeps
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/diagnostic/startUpPerformanceReporter/startUpPerformanceReporter-kt.jdeps
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/backend/observation/observation-kt.jdeps
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/ml-api/ml-kt.jdeps
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util/storages/io-storages.jdeps
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/core-nio-fs/libcore-nio-fs.jdeps
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/project/shared/project-kt.jdeps
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/jbr/jbr.jdeps
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/fleet/util/core/fleet-util-core-kt.jdeps
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/buildData/buildData-kt.jdeps
|
||||
--warn
|
||||
off
|
||||
--jvm-default
|
||||
all
|
||||
--jvm-target
|
||||
17
|
||||
--opt-in
|
||||
com.intellij.openapi.util.IntellijInternalApi
|
||||
org.jetbrains.kotlin.utils.addToStdlib.UnsafeCastFunction
|
||||
--classpath
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/eawtstub/lib+/eawtstub-ijar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/platform-api/ide.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util/util.abi.jar
|
||||
../lib++_repo_rules+annotations-24_0_0_http/file/annotations-24.0.0.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util-rt/util-rt-hjar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util/base/base.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/core-api/core.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/extensions/extensions.abi.jar
|
||||
../lib++_repo_rules+kotlinx-coroutines-core-jvm-1_8_0-intellij-11_http/file/kotlinx-coroutines-core-jvm-1.8.0-intellij-11.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/forms_rt/java-guiForms-rt-hjar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/projectModel-api/projectModel.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/jps/model-api/model-hjar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/editor-ui-api/editor.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/credential-store/credentialStore.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/remote-core/remote-core.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/ide-core/ide-core.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/progress/shared/ide-progress.abi.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/oro_matcher/lib++_repo_rules+oro-2_0_8_http/file/oro-2.0.8-ijar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/lang-api/lang.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/lang-core/lang-core.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/lvcs-api/lvcs.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/indexing-api/indexing.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/analysis-api/analysis.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/code-style-api/codeStyle.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/execution/execution.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/refactoring/refactoring.abi.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/jna-platform-5_14_0_http_import/lib++_repo_rules+jna-platform-5_14_0_http/file/jna-platform-5.14.0-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/jna-5_14_0_http_import/lib++_repo_rules+jna-5_14_0_http/file/jna-5.14.0-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/winp/lib++_repo_rules+winp-1_30_1_http/file/winp-1.30.1-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/swingx/lib++_repo_rules+swingx-core-1_6_2-2_http/file/swingx-core-1.6.2-2-ijar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/core-impl/core-impl.abi.jar
|
||||
../lib++_repo_rules+kotlin-stdlib-2_1_0_http/file/kotlin-stdlib-2.1.0.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/miglayout-swing-11_4_http_import/lib++_repo_rules+miglayout-swing-11_4_http/file/miglayout-swing-11.4-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/miglayout-core-11_4_http_import/lib++_repo_rules+miglayout-core-11_4_http/file/miglayout-core-11.4-ijar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/projectModel-impl/projectModel-impl.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/jps/model-serialization/model-serialization-hjar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util-ex/util-ex.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util/concurrency/concurrency.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/workspace/storage/storage.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/workspace/jps/jps.abi.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/commons-imaging/lib++_repo_rules+commons-imaging-1_0-RC-1_http/file/commons-imaging-1.0-RC-1-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/guava-33_3_1-jre_http_import/lib++_repo_rules+guava-33_3_1-jre_http/file/guava-33.3.1-jre-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/failureaccess-1_0_2_http_import/lib++_repo_rules+failureaccess-1_0_2_http/file/failureaccess-1.0.2-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/j2objc-annotations-3_0_0_http_import/lib++_repo_rules+j2objc-annotations-3_0_0_http/file/j2objc-annotations-3.0.0-ijar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/jps/model-impl/model-impl-hjar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/analysis-impl/analysis-impl.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/editor-ui-ex/editor-ex.abi.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/gson/lib++_repo_rules+gson-2_11_0_http/file/gson-2.11.0-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/httpmime-4_5_14_http_import/lib++_repo_rules+httpmime-4_5_14_http/file/httpmime-4.5.14-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/httpclient-4_5_14_http_import/lib++_repo_rules+httpclient-4_5_14_http/file/httpclient-4.5.14-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/httpcore-4_4_16_http_import/lib++_repo_rules+httpcore-4_4_16_http/file/httpcore-4.4.16-ijar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/diff-api/diff.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util/diff/diff.abi.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/imgscalr/lib++_repo_rules+imgscalr-lib-4_2_http/file/imgscalr-lib-4.2-ijar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/built-in-server-api/builtInServer.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/observable/ide-observable.abi.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/stream_ex/lib++_repo_rules+streamex-0_8_2_http/file/streamex-0.8.2-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/netty-codec-http2-4_2_0_RC1_http_import/lib++_repo_rules+netty-codec-http2-4_2_0_RC1_http/file/netty-codec-http2-4.2.0.RC1-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/netty-transport-4_2_0_RC1_http_import/lib++_repo_rules+netty-transport-4_2_0_RC1_http/file/netty-transport-4.2.0.RC1-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/netty-resolver-4_2_0_RC1_http_import/lib++_repo_rules+netty-resolver-4_2_0_RC1_http/file/netty-resolver-4.2.0.RC1-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/netty-codec-4_2_0_RC1_http_import/lib++_repo_rules+netty-codec-4_2_0_RC1_http/file/netty-codec-4.2.0.RC1-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/netty-codec-base-4_2_0_RC1_http_import/lib++_repo_rules+netty-codec-base-4_2_0_RC1_http/file/netty-codec-base-4.2.0.RC1-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/netty-handler-4_2_0_RC1_http_import/lib++_repo_rules+netty-handler-4_2_0_RC1_http/file/netty-handler-4.2.0.RC1-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/netty-transport-native-unix-common-4_2_0_RC1_http_import/lib++_repo_rules+netty-transport-native-unix-common-4_2_0_RC1_http/file/netty-transport-native-unix-common-4.2.0.RC1-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/netty-codec-http-4_2_0_RC1_http_import/lib++_repo_rules+netty-codec-http-4_2_0_RC1_http/file/netty-codec-http-4.2.0.RC1-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/jackson/lib++_repo_rules+jackson-core-2_17_0_http/file/jackson-core-2.17.0-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/java_compatibility/lib++_repo_rules+java-compatibility-1_0_1_http/file/java-compatibility-1.0.1-ijar.jar
|
||||
../lib++_repo_rules+kotlin-reflect-2_1_0_http/file/kotlin-reflect-2.1.0.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/jackson-databind-2_17_2_http_import/lib++_repo_rules+jackson-databind-2_17_2_http/file/jackson-databind-2.17.2-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/jackson-annotations-2_17_2_http_import/lib++_repo_rules+jackson-annotations-2_17_2_http/file/jackson-annotations-2.17.2-ijar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util/util-ui.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/platform-util-io-impl/ide-util-io-impl.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/platform-util-io/ide-util-io.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/instanceContainer/instanceContainer.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/service-container/serviceContainer.abi.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/jcef/lib++_repo_rules+jcef-122_1_9-gd14e051-chromium-122_0_6261_94-api-1_17-251-b2_http/file/jcef-122.1.9-gd14e051-chromium-122.0.6261.94-api-1.17-251-b2-ijar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/statistics/statistics.abi.jar
|
||||
../lib++_repo_rules+ap-validation-76_http/file/ap-validation-76.jar
|
||||
../lib++_repo_rules+model-76_http/file/model-76.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/asm/lib++_repo_rules+asm-all-9_6_1_http/file/asm-all-9.6.1-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/jsoup/lib++_repo_rules+jsoup-1_18_1_http/file/jsoup-1.18.1-ijar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/rd-platform-community/rd-community.abi.jar
|
||||
../lib++_repo_rules+rd-core-2024_3_1_http/file/rd-core-2024.3.1.jar
|
||||
../lib++_repo_rules+rd-framework-2024_3_1_http/file/rd-framework-2024.3.1.jar
|
||||
../lib++_repo_rules+rd-swing-2024_3_1_http/file/rd-swing-2024.3.1.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/fastutil-min/lib++_repo_rules+intellij-deps-fastutil-8_5_14-jb1_http/file/intellij-deps-fastutil-8.5.14-jb1-ijar.jar
|
||||
../lib++_repo_rules+blockmap-1_0_7_http/file/blockmap-1.0.7.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util-class-loader/util-classLoader-hjar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/netty-buffer-4_2_0_RC1_http_import/lib++_repo_rules+netty-buffer-4_2_0_RC1_http/file/netty-buffer-4.2.0.RC1-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/netty-common-4_2_0_RC1_http_import/lib++_repo_rules+netty-common-4_2_0_RC1_http/file/netty-common-4.2.0.RC1-ijar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util/progress/progress.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/core-ui/core-ui.abi.jar
|
||||
../lib++_repo_rules+marketplace-zip-signer-0_1_24_http/file/marketplace-zip-signer-0.1.24.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/caffeine/lib++_repo_rules+caffeine-3_1_8_http/file/caffeine-3.1.8-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/classgraph/lib++_repo_rules+classgraph-4_8_174_http/file/classgraph-4.8.174-ijar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util/zip/zip-hjar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/icu4j/lib++_repo_rules+icu4j-73_2_http/file/icu4j-73.2-ijar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util/xmlDom/xmlDom.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/ide-core-impl/ide-core-impl.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/ide-core/plugins/ide-core-plugins.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/platform-util-netty/ide-util-netty.abi.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/aalto-xml-1_3_3_http_import/lib++_repo_rules+aalto-xml-1_3_3_http/file/aalto-xml-1.3.3-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/stax2-api-4_2_2_http_import/lib++_repo_rules+stax2-api-4_2_2_http/file/stax2-api-4.2.2-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/jbr-api/lib++_repo_rules+jbr-api-1_0_0_http/file/jbr-api-1.0.0-ijar.jar
|
||||
../lib++_repo_rules+kotlinx-serialization-json-jvm-1_7_3_http/file/kotlinx-serialization-json-jvm-1.7.3.jar
|
||||
../lib++_repo_rules+kotlinx-serialization-core-jvm-1_7_3_http/file/kotlinx-serialization-core-jvm-1.7.3.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util/jdom/jdom-hjar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/jvm-native-trusted-roots/lib++_repo_rules+jvm-native-trusted-roots-1_0_21_http/file/jvm-native-trusted-roots-1.0.21-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/opentelemetry-sdk-1_45_0_http_import/lib++_repo_rules+opentelemetry-sdk-1_45_0_http/file/opentelemetry-sdk-1.45.0-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/opentelemetry-api-1_45_0_http_import/lib++_repo_rules+opentelemetry-api-1_45_0_http/file/opentelemetry-api-1.45.0-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/opentelemetry-context-1_45_0_http_import/lib++_repo_rules+opentelemetry-context-1_45_0_http/file/opentelemetry-context-1.45.0-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/opentelemetry-sdk-common-1_45_0_http_import/lib++_repo_rules+opentelemetry-sdk-common-1_45_0_http/file/opentelemetry-sdk-common-1.45.0-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/opentelemetry-sdk-trace-1_45_0_http_import/lib++_repo_rules+opentelemetry-sdk-trace-1_45_0_http/file/opentelemetry-sdk-trace-1.45.0-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/opentelemetry-api-incubator-1_45_0-alpha_http_import/lib++_repo_rules+opentelemetry-api-incubator-1_45_0-alpha_http/file/opentelemetry-api-incubator-1.45.0-alpha-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/opentelemetry-sdk-metrics-1_45_0_http_import/lib++_repo_rules+opentelemetry-sdk-metrics-1_45_0_http/file/opentelemetry-sdk-metrics-1.45.0-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/opentelemetry-sdk-logs-1_45_0_http_import/lib++_repo_rules+opentelemetry-sdk-logs-1_45_0_http/file/opentelemetry-sdk-logs-1.45.0-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/opentelemetry-semconv/lib++_repo_rules+opentelemetry-semconv-1_28_0-alpha_http/file/opentelemetry-semconv-1.28.0-alpha-ijar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/diagnostic/telemetry/telemetry.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/diagnostic/diagnostic.abi.jar
|
||||
../lib++_repo_rules+opentelemetry-extension-kotlin-1_45_0_http/file/opentelemetry-extension-kotlin-1.45.0.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/hdr_histogram/lib++_repo_rules+HdrHistogram-2_2_2_http/file/HdrHistogram-2.2.2-ijar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/code-style-impl/codeStyle-impl.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util/text-matching/text-matching-hjar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/platform-impl/rpc/ide-rpc.abi.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/hash4j/lib++_repo_rules+hash4j-0_19_0_http/file/hash4j-0.19.0-ijar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/backend/workspace/workspace.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/diagnostic/startUpPerformanceReporter/startUpPerformanceReporter.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/diagnostic/telemetry-impl/telemetry-impl.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/diagnostic/telemetry.exporters/telemetry-exporters.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/diagnostic/telemetry/rt/diagnostic-telemetry-rt-hjar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/ijent/ijent.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/eel/eel.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/backend/observation/observation.abi.jar
|
||||
../lib++_repo_rules+pty4j-0_13_1_http/file/pty4j-0.13.1.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/settings/settings.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util/coroutines/coroutines.abi.jar
|
||||
../lib++_repo_rules+rwmutex-idea-0_0_7_http/file/rwmutex-idea-0.0.7.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/lz4-java/lib++_repo_rules+lz4-java-1_8_0_http/file/lz4-java-1.8.0-ijar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/ml-api/ml.abi.jar
|
||||
../lib++_repo_rules+ml-feature-api-58_http/file/ml-feature-api-58.jar
|
||||
../lib++_repo_rules+kotlinx-collections-immutable-jvm-0_3_8_http/file/kotlinx-collections-immutable-jvm-0.3.8.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util/storages/io-storages-hjar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/core-nio-fs/libcore-nio-fs-hjar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/ijent/impl/community-impl.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/ijent/buildConstants/community-buildConstants.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/kernel/shared/kernel.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/kernel/rpc/rpc.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/fleet/rpc/rpc.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/fleet/kernel/kernel.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/fleet/rhizomedb/rhizomedb.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/fleet/util/core/fleet-util-core.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/fleet/util/logging/api/fleet-util-logging-api.abi.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/slf4j-api/lib++_repo_rules+slf4j-api-2_0_13_http/file/slf4j-api-2.0.13-ijar.jar
|
||||
../lib++_repo_rules+kotlinx-coroutines-slf4j-1_8_0-intellij-11_http/file/kotlinx-coroutines-slf4j-1.8.0-intellij-11.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/project/shared/project.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/jbr/jbr-hjar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/ui.jcef/ui-jcef.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/eel-provider/eel-provider.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/platform-impl/ui/ide-ui.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/buildData/buildData.abi.jar
|
||||
../lib++_repo_rules+annotations-java5-24_0_0_http/file/annotations-java5-24.0.0.jar
|
||||
../lib++_repo_rules+kotlinx-coroutines-debug-1_8_0-intellij-11_http/file/kotlinx-coroutines-debug-1.8.0-intellij-11.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/jaxen/lib++_repo_rules+jaxen-1_2_0_http/file/jaxen-1.2.0-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/log4_j/lib++_repo_rules+log4j-over-slf4j-1_7_36_http/file/log4j-over-slf4j-1.7.36-ijar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util/rt-java8/rt-java8-hjar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/commons-compress/lib++_repo_rules+commons-compress-1_26_1_http/file/commons-compress-1.26.1-ijar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util/troveCompileOnly/troveCompileOnly-hjar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/kryo5/lib++_repo_rules+kryo5-5_6_0_http/file/kryo5-5.6.0-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/jcip/lib++_repo_rules+jcip-annotations-1_0_http/file/jcip-annotations-1.0-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/mvstore/lib++_repo_rules+h2-mvstore-2_3_232_http/file/h2-mvstore-2.3.232-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/jsvg/lib++_repo_rules+jsvg-1_3_0-jb_8_http/file/jsvg-1.3.0-jb.8-ijar.jar
|
||||
../lib++_repo_rules+kotlinx-serialization-protobuf-jvm-1_7_3_http/file/kotlinx-serialization-protobuf-jvm-1.7.3.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/automaton/lib++_repo_rules+automaton-1_12-4_http/file/automaton-1.12-4-ijar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/fleet/reporting/api/fleet-reporting-api.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/fleet/preferences/preferences.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/fleet/util/os/fleet-util-os-hjar.jar
|
||||
../lib++_repo_rules+expects-compiler-plugin-2_1_0-0_3_http/file/expects-compiler-plugin-2.1.0-0.3.jar
|
||||
../lib++_repo_rules+rpc-compiler-plugin-2_1_0-0_4_http/file/rpc-compiler-plugin-2.1.0-0.4.jar
|
||||
../lib++_repo_rules+kotlinx-datetime-jvm-0_6_1_http/file/kotlinx-datetime-jvm-0.6.1.jar
|
||||
../lib++_repo_rules+rhizomedb-compiler-plugin-2_1_0-0_2_http/file/rhizomedb-compiler-plugin-2.1.0-0.2.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/usageView/usageView.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/statistics/uploader/uploader.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/statistics/config/config.abi.jar
|
||||
../lib++_repo_rules+jackson-module-kotlin-2_17_2_http/file/jackson-module-kotlin-2.17.2.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/runtime/product/product.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/runtime/repository/repository-hjar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/indexing-impl/indexing-impl.abi.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util/nanoxml/nanoxml-hjar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/proxy-vole-1_1_6_http_import/lib++_repo_rules+proxy-vole-1_1_6_http/file/proxy-vole-1.1.6-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/delight-rhino-sandbox-0_0_17_http_import/lib++_repo_rules+delight-rhino-sandbox-0_0_17_http/file/delight-rhino-sandbox-0.0.17-ijar.jar
|
||||
../lib++_repo_rules+rd-text-2024_3_1_http/file/rd-text-2024.3.1.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/opentelemetry-exporter-otlp-common-1_45_0_http_import/lib++_repo_rules+opentelemetry-exporter-otlp-common-1_45_0_http/file/opentelemetry-exporter-otlp-common-1.45.0-ijar.jar
|
||||
bazel-out/lib+/darwin_arm64-fastbuild/bin/_ijar/opentelemetry-exporter-common-1_45_0_http_import/lib++_repo_rules+opentelemetry-exporter-common-1_45_0_http/file/opentelemetry-exporter-common-1.45.0-ijar.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/util/http/http.abi.jar
|
||||
../lib++_repo_rules+ktor-client-core-jvm-2_3_13_http/file/ktor-client-core-jvm-2.3.13.jar
|
||||
../lib++_repo_rules+ktor-http-jvm-2_3_13_http/file/ktor-http-jvm-2.3.13.jar
|
||||
../lib++_repo_rules+ktor-utils-jvm-2_3_13_http/file/ktor-utils-jvm-2.3.13.jar
|
||||
../lib++_repo_rules+ktor-io-jvm-2_3_13_http/file/ktor-io-jvm-2.3.13.jar
|
||||
../lib++_repo_rules+ktor-events-jvm-2_3_13_http/file/ktor-events-jvm-2.3.13.jar
|
||||
../lib++_repo_rules+ktor-websocket-serialization-jvm-2_3_13_http/file/ktor-websocket-serialization-jvm-2.3.13.jar
|
||||
../lib++_repo_rules+ktor-serialization-jvm-2_3_13_http/file/ktor-serialization-jvm-2.3.13.jar
|
||||
../lib++_repo_rules+ktor-websockets-jvm-2_3_13_http/file/ktor-websockets-jvm-2.3.13.jar
|
||||
../lib++_repo_rules+ktor-client-java-jvm-2_3_13_http/file/ktor-client-java-jvm-2.3.13.jar
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/eel-impl/eel-impl.abi.jar
|
||||
--plugin-id
|
||||
org.jetbrains.kotlin.kotlin-serialization-compiler-plugin
|
||||
--plugin-classpath
|
||||
|
||||
--out
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/platform-impl/ide-impl.jar
|
||||
--abi-out
|
||||
bazel-out/community+/darwin_arm64-fastbuild/bin/platform/platform-impl/ide-impl.abi.jar
|
||||
--add-export
|
||||
java.desktop/sun.awt=ALL-UNNAMED
|
||||
java.desktop/sun.font=ALL-UNNAMED
|
||||
java.desktop/java.awt.peer=ALL-UNNAMED
|
||||
jdk.attach/sun.tools.attach=ALL-UNNAMED
|
||||
java.desktop/sun.awt.image=ALL-UNNAMED
|
||||
java.desktop/sun.awt.datatransfer=ALL-UNNAMED
|
||||
java.desktop/sun.swing=ALL-UNNAMED
|
||||
java.base/sun.nio.fs=ALL-UNNAMED
|
||||
"""
|
||||
}
|
||||
219
build/jvm-rules/src/jps-builder/impl/BazelBuildDataProvider.kt
Normal file
219
build/jvm-rules/src/jps-builder/impl/BazelBuildDataProvider.kt
Normal file
@@ -0,0 +1,219 @@
|
||||
@file:Suppress("UnstableApiUsage", "ReplaceGetOrSet", "ReplaceJavaStaticMethodWithKotlinAnalog")
|
||||
|
||||
package org.jetbrains.bazel.jvm.jps.impl
|
||||
|
||||
import org.jetbrains.bazel.jvm.jps.SourceDescriptor
|
||||
import org.jetbrains.jps.builders.BuildTarget
|
||||
import org.jetbrains.jps.builders.storage.SourceToOutputMapping
|
||||
import org.jetbrains.jps.incremental.storage.*
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.attribute.BasicFileAttributes
|
||||
|
||||
internal class BazelBuildDataProvider(
|
||||
@JvmField val relativizer: PathTypeAwareRelativizer,
|
||||
actualDigestMap: Map<Path, ByteArray>,
|
||||
private val sourceToDescriptor: HashMap<Path, SourceDescriptor>,
|
||||
@JvmField val storeFile: Path,
|
||||
) : BuildDataProvider {
|
||||
private val stamp = BazelStampStorage(actualDigestMap = actualDigestMap, map = sourceToDescriptor)
|
||||
|
||||
@JvmField val sourceToOutputMapping = BazelSourceToOutputMapping(map = sourceToDescriptor, relativizer = relativizer)
|
||||
|
||||
private val sourceToForm = object : OneToManyPathMapping {
|
||||
override fun getOutputs(path: String): Collection<String>? = sourceToOutputMapping.getOutputs(path)
|
||||
|
||||
override fun getOutputs(file: Path): Collection<Path>? = sourceToOutputMapping.getOutputs(file)
|
||||
|
||||
override fun setOutputs(path: Path, outPaths: List<Path>) {
|
||||
sourceToOutputMapping.setOutputs(path, outPaths)
|
||||
}
|
||||
|
||||
override fun remove(key: Path) {
|
||||
sourceToOutputMapping.remove(key)
|
||||
}
|
||||
}
|
||||
|
||||
fun getFinalList(): Array<SourceDescriptor> {
|
||||
val list = synchronized(sourceToDescriptor) {
|
||||
sourceToDescriptor.values.toTypedArray()
|
||||
}
|
||||
list.sortBy { it.sourceFile }
|
||||
return list
|
||||
}
|
||||
|
||||
override fun clearCache() {
|
||||
}
|
||||
|
||||
override fun removeStaleTarget(targetId: String, targetTypeId: String) {
|
||||
}
|
||||
|
||||
override fun getFileStampStorage(target: BuildTarget<*>): BazelStampStorage = stamp
|
||||
|
||||
override fun getSourceToOutputMapping(target: BuildTarget<*>): BazelSourceToOutputMapping = sourceToOutputMapping
|
||||
|
||||
override fun getOutputToTargetMapping(): OutputToTargetMapping = throw UnsupportedOperationException("Must not be used")
|
||||
|
||||
override fun getSourceToForm(target: BuildTarget<*>): OneToManyPathMapping = sourceToForm
|
||||
|
||||
override fun closeTargetMaps(target: BuildTarget<*>) {
|
||||
}
|
||||
|
||||
override fun removeAllMaps() {
|
||||
}
|
||||
|
||||
override fun commit() {
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
}
|
||||
}
|
||||
|
||||
internal class BazelStampStorage(
|
||||
private val actualDigestMap: Map<Path, ByteArray>,
|
||||
private val map: HashMap<Path, SourceDescriptor>,
|
||||
) : StampsStorage<ByteArray> {
|
||||
override fun updateStamp(sourceFile: Path, buildTarget: BuildTarget<*>?, currentFileTimestamp: Long) {
|
||||
val actualDigest = requireNotNull(actualDigestMap.get(sourceFile)) {
|
||||
"No digest is provided for $sourceFile"
|
||||
}
|
||||
|
||||
synchronized(map) {
|
||||
map.computeIfAbsent(sourceFile) { SourceDescriptor(sourceFile = it) }.digest = actualDigest
|
||||
}
|
||||
}
|
||||
|
||||
override fun removeStamp(sourceFile: Path, buildTarget: BuildTarget<*>?) {
|
||||
//synchronized(map) {
|
||||
// map.get(sourceFile)?.digest = null
|
||||
//}
|
||||
throw UnsupportedOperationException("Must not be used")
|
||||
}
|
||||
|
||||
override fun getCurrentStampIfUpToDate(file: Path, buildTarget: BuildTarget<*>?, attrs: BasicFileAttributes?): ByteArray? {
|
||||
//val key = createKey(file)
|
||||
//val storedDigest = synchronized(map) { map.get(key)?.digest } ?: return null
|
||||
//val actualDigest = actualDigestMap.get(file) ?: return null
|
||||
//return actualDigest.takeIf { storedDigest.contentEquals(actualDigest) }
|
||||
throw UnsupportedOperationException("Must not be used")
|
||||
}
|
||||
|
||||
fun isDirty(sourceFile: Path): Boolean {
|
||||
val storedDigest = synchronized(map) { map.get(sourceFile)?.digest } ?: return true
|
||||
val actualDigest = actualDigestMap.get(sourceFile) ?: return true
|
||||
return !storedDigest.contentEquals(actualDigest)
|
||||
}
|
||||
}
|
||||
|
||||
internal class BazelSourceToOutputMapping(
|
||||
private val map: HashMap<Path, SourceDescriptor>,
|
||||
private val relativizer: PathTypeAwareRelativizer,
|
||||
) : SourceToOutputMapping {
|
||||
override fun setOutputs(sourceFile: Path, outputPaths: List<Path>) {
|
||||
val relativeOutputPaths = if (outputPaths.isEmpty()) null else outputPaths.map { relativizer.toRelative(it, RelativePathType.OUTPUT) }
|
||||
synchronized(map) {
|
||||
val value = if (relativeOutputPaths == null) {
|
||||
map.get(sourceFile) ?: return
|
||||
}
|
||||
else {
|
||||
map.computeIfAbsent(sourceFile) { SourceDescriptor(sourceFile = it) }
|
||||
}
|
||||
|
||||
value.outputs = relativeOutputPaths
|
||||
}
|
||||
}
|
||||
|
||||
override fun appendOutput(sourcePath: String, outputPath: String) {
|
||||
val sourceFile = Path.of(sourcePath)
|
||||
val relativeOutputPath = relativizer.toRelative(outputPath, RelativePathType.OUTPUT)
|
||||
synchronized(map) {
|
||||
val sourceInfo = map.computeIfAbsent(sourceFile) { SourceDescriptor(sourceFile = it) }
|
||||
val existingOutputs = sourceInfo.outputs
|
||||
if (existingOutputs == null) {
|
||||
sourceInfo.outputs = java.util.List.of(relativeOutputPath)
|
||||
}
|
||||
else if (!existingOutputs.contains(relativeOutputPath)) {
|
||||
sourceInfo.outputs = existingOutputs + relativeOutputPath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun remove(sourceFile: Path) {
|
||||
synchronized(map) {
|
||||
map.get(sourceFile)?.outputs = null
|
||||
}
|
||||
}
|
||||
|
||||
override fun removeOutput(sourcePath: String, outputPath: String) {
|
||||
val sourceFile = Path.of(sourcePath)
|
||||
val relativeOutputPath = relativizer.toRelative(outputPath, RelativePathType.OUTPUT)
|
||||
synchronized(map) {
|
||||
val sourceInfo = map.get(sourceFile) ?: return
|
||||
val existingOutputs = sourceInfo.outputs ?: return
|
||||
if (existingOutputs.contains(relativeOutputPath)) {
|
||||
if (existingOutputs.size == 1) {
|
||||
sourceInfo.outputs = null
|
||||
}
|
||||
else {
|
||||
sourceInfo.outputs = existingOutputs - relativeOutputPath
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getOutputs(sourcePath: String): Collection<String>? {
|
||||
val sourceFile = Path.of(sourcePath)
|
||||
return synchronized(map) { map.get(sourceFile)?.outputs }?.map { relativizer.toAbsolute(it, RelativePathType.OUTPUT) }
|
||||
}
|
||||
|
||||
override fun getOutputs(sourceFile: Path): Collection<Path>? {
|
||||
return synchronized(map) { map.get(sourceFile)?.outputs }?.map { relativizer.toAbsoluteFile(it, RelativePathType.OUTPUT) }
|
||||
}
|
||||
|
||||
fun getDescriptor(sourceFile: Path): SourceDescriptor? {
|
||||
return synchronized(map) { map.get(sourceFile) }
|
||||
}
|
||||
|
||||
fun findAffectedSources(affectedSources: List<List<String>>): List<Path> {
|
||||
val result = ArrayList<Path>(affectedSources.size)
|
||||
synchronized(map) {
|
||||
for (descriptor in map.values) {
|
||||
val outputs = descriptor.outputs ?: continue
|
||||
for (output in outputs) {
|
||||
if (affectedSources.any { it.contains(output) }) {
|
||||
result.add(descriptor.sourceFile)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun findDeletedAndUnsetDigest(known: Map<Path, *>): List<Path> {
|
||||
synchronized(map) {
|
||||
return map.values.asSequence()
|
||||
.filter { !known.containsKey(it.sourceFile) }
|
||||
.onEach { it.digest = null }
|
||||
.map { it.sourceFile }
|
||||
.toList()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSourceFileIterator(): Iterator<Path> {
|
||||
throw UnsupportedOperationException("Must not be used")
|
||||
//return synchronized(map) { map.keys.toTypedArray() }.asSequence()
|
||||
// .map { relativizer.toAbsoluteFile(it, RelativePathType.SOURCE) }
|
||||
// .iterator()
|
||||
}
|
||||
|
||||
override fun getSourcesIterator(): Iterator<String> {
|
||||
throw UnsupportedOperationException("Must not be used")
|
||||
//return synchronized(map) { map.keys.toTypedArray() }.asSequence()
|
||||
// .map { relativizer.toAbsolute(it, RelativePathType.SOURCE) }
|
||||
// .iterator()
|
||||
}
|
||||
|
||||
override fun cursor(): SourceToOutputMappingCursor {
|
||||
throw UnsupportedOperationException("Must not be used")
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
@file:Suppress("HardCodedStringLiteral", "INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "DialogTitleCapitalization", "UnstableApiUsage", "ReplaceGetOrSet")
|
||||
package org.jetbrains.bazel.jvm.jps.impl
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import org.jetbrains.bazel.jvm.jps.RequestLog
|
||||
import org.jetbrains.jps.ModuleChunk
|
||||
import org.jetbrains.jps.builders.DirtyFilesHolder
|
||||
import org.jetbrains.jps.builders.FileProcessor
|
||||
@@ -13,24 +13,18 @@ import org.jetbrains.jps.incremental.ModuleLevelBuilder.ExitCode.*
|
||||
import org.jetbrains.jps.model.JpsProject
|
||||
import org.jetbrains.kotlin.build.GeneratedFile
|
||||
import org.jetbrains.kotlin.build.GeneratedJvmClass
|
||||
import org.jetbrains.kotlin.build.report.ICReporter
|
||||
import org.jetbrains.kotlin.build.report.ICReporter.ReportSeverity
|
||||
import org.jetbrains.kotlin.build.report.ICReporterBase
|
||||
import org.jetbrains.kotlin.build.report.debug
|
||||
import org.jetbrains.kotlin.build.report.metrics.JpsBuildTime
|
||||
import org.jetbrains.kotlin.build.report.statistics.StatTag
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||
import org.jetbrains.kotlin.compilerRunner.*
|
||||
import org.jetbrains.kotlin.config.Services
|
||||
import org.jetbrains.kotlin.incremental.*
|
||||
import org.jetbrains.kotlin.incremental.components.*
|
||||
import org.jetbrains.kotlin.jps.KotlinJpsBundle
|
||||
import org.jetbrains.kotlin.jps.build.*
|
||||
import org.jetbrains.kotlin.jps.incremental.JpsIncrementalCache
|
||||
import org.jetbrains.kotlin.jps.incremental.JpsLookupStorageManager
|
||||
import org.jetbrains.kotlin.jps.statistic.JpsBuilderMetricReporter
|
||||
import org.jetbrains.kotlin.jps.statistic.JpsStatisticsReportService
|
||||
import org.jetbrains.kotlin.jps.targets.KotlinModuleBuildTarget
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.kotlin.metadata.deserialization.MetadataVersion
|
||||
@@ -38,44 +32,44 @@ import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.preloading.ClassCondition
|
||||
import org.jetbrains.kotlin.utils.KotlinPaths
|
||||
import org.jetbrains.kotlin.utils.KotlinPathsFromHomeDir
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import java.io.File
|
||||
import kotlin.system.measureTimeMillis
|
||||
|
||||
private val LOG = Logger.getInstance("#org.jetbrains.kotlin.jps.build.KotlinBuilder")
|
||||
|
||||
private val classesToLoadByParent: ClassCondition = ClassCondition { className ->
|
||||
val prefixes = listOf(
|
||||
private val classesToLoadByParent = ClassCondition { className ->
|
||||
for (it in arrayOf(
|
||||
"org.apache.log4j.", // For logging from compiler
|
||||
"org.jetbrains.kotlin.incremental.components.",
|
||||
"org.jetbrains.kotlin.incremental.js",
|
||||
"org.jetbrains.kotlin.load.kotlin.incremental.components."
|
||||
)
|
||||
|
||||
val classes = listOf(
|
||||
)) {
|
||||
if (className.startsWith(it)) {
|
||||
return@ClassCondition true
|
||||
}
|
||||
}
|
||||
for (it in arrayOf(
|
||||
"org.jetbrains.kotlin.config.Services",
|
||||
"org.jetbrains.kotlin.progress.CompilationCanceledStatus",
|
||||
"org.jetbrains.kotlin.progress.CompilationCanceledException",
|
||||
"org.jetbrains.kotlin.modules.TargetId",
|
||||
"org.jetbrains.kotlin.cli.common.ExitCode"
|
||||
)
|
||||
|
||||
prefixes.forEach { if (className.startsWith(it)) return@ClassCondition true }
|
||||
classes.forEach { if (className == it) return@ClassCondition true }
|
||||
)) {
|
||||
if (className == it) {
|
||||
return@ClassCondition true
|
||||
}
|
||||
}
|
||||
|
||||
return@ClassCondition false
|
||||
}
|
||||
|
||||
internal class BazelKotlinBuilder(
|
||||
private val isKotlinBuilderInDumbMode: Boolean = false,
|
||||
private val isKotlinBuilderInDumbMode: Boolean,
|
||||
private val enableLookupStorageFillingInDumbMode: Boolean = false,
|
||||
private val log: RequestLog,
|
||||
) : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
|
||||
companion object {
|
||||
const val JPS_KOTLIN_HOME_PROPERTY = "jps.kotlin.home"
|
||||
}
|
||||
|
||||
private val statisticsLogger = TeamcityStatisticsLogger()
|
||||
|
||||
override fun getPresentableName() = "Kotlin Builder"
|
||||
|
||||
override fun getCompilableFileExtensions() = arrayListOf("kt")
|
||||
@@ -115,7 +109,7 @@ internal class BazelKotlinBuilder(
|
||||
kotlinContext.reportUnsupportedTargets()
|
||||
}
|
||||
|
||||
LOG.info("Total Kotlin global compile context initialization time: $time ms")
|
||||
log.info("Total Kotlin global compile context initialization time: $time ms")
|
||||
|
||||
return kotlinContext
|
||||
}
|
||||
@@ -131,8 +125,6 @@ internal class BazelKotlinBuilder(
|
||||
if (kotlinCompileContext != null) {
|
||||
kotlinCompileContext.dispose()
|
||||
context.putUserData(kotlinCompileContextKey, null)
|
||||
|
||||
statisticsLogger.reportTotal()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -141,12 +133,6 @@ internal class BazelKotlinBuilder(
|
||||
override fun chunkBuildStarted(context: CompileContext, chunk: ModuleChunk) {
|
||||
super.chunkBuildStarted(context, chunk)
|
||||
|
||||
if (chunk.isDummy(context)) {
|
||||
return
|
||||
}
|
||||
|
||||
val kotlinContext = ensureKotlinContextInitialized(context)
|
||||
|
||||
val buildLogger = context.testingContext?.buildLogger
|
||||
buildLogger?.chunkBuildStarted(context, chunk)
|
||||
|
||||
@@ -155,6 +141,7 @@ internal class BazelKotlinBuilder(
|
||||
}
|
||||
|
||||
val targets = chunk.targets
|
||||
val kotlinContext = ensureKotlinContextInitialized(context)
|
||||
if (targets.none { kotlinContext.hasKotlinMarker[it] == true }) {
|
||||
return
|
||||
}
|
||||
@@ -191,7 +178,7 @@ internal class BazelKotlinBuilder(
|
||||
}
|
||||
}
|
||||
)
|
||||
val fsOperations = FSOperationsHelper(context, chunk, dirtyFilesHolder, LOG)
|
||||
val fsOperations = BazelKotlinFsOperationsHelper(context, chunk, dirtyFilesHolder, log)
|
||||
|
||||
val representativeTarget = kotlinContext.targetsBinding[chunk.representativeTarget()] ?: return
|
||||
|
||||
@@ -229,10 +216,17 @@ internal class BazelKotlinBuilder(
|
||||
}
|
||||
|
||||
val changesCollector = ChangesCollector()
|
||||
removedClasses.forEach { changesCollector.collectSignature(FqName(it), areSubclassesAffected = true) }
|
||||
val affectedByRemovedClasses = changesCollector.getDirtyFiles(incrementalCaches.values, kotlinContext.lookupStorageManager)
|
||||
for (it in removedClasses) {
|
||||
changesCollector.collectSignature(FqName(it), areSubclassesAffected = true)
|
||||
}
|
||||
val affectedByRemovedClasses = getDirtyFiles(
|
||||
changeCollector = changesCollector,
|
||||
caches = incrementalCaches.values,
|
||||
lookupStorageManager = kotlinContext.lookupStorageManager,
|
||||
reporter = BazelJpsICReporter(log),
|
||||
)
|
||||
|
||||
fsOperations.markFilesForCurrentRound(affectedByRemovedClasses.dirtyFiles + affectedByRemovedClasses.forceRecompileTogether)
|
||||
fsOperations.markFilesForCurrentRound(affectedByRemovedClasses.dirtyFiles.asSequence() + affectedByRemovedClasses.forceRecompileTogether)
|
||||
}
|
||||
|
||||
override fun build(
|
||||
@@ -241,48 +235,28 @@ internal class BazelKotlinBuilder(
|
||||
dirtyFilesHolder: DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget>,
|
||||
outputConsumer: OutputConsumer
|
||||
): ExitCode {
|
||||
val reportService = JpsStatisticsReportService.getFromContext(context)
|
||||
reportService.moduleBuildStarted(chunk)
|
||||
return doBuild(context = context, chunk = chunk, dirtyFilesHolder = dirtyFilesHolder, outputConsumer = outputConsumer).also { result ->
|
||||
reportService.moduleBuildFinished(chunk, context, result)
|
||||
}
|
||||
}
|
||||
|
||||
private fun doBuild(
|
||||
context: CompileContext,
|
||||
chunk: ModuleChunk,
|
||||
dirtyFilesHolder: DirtyFilesHolder<JavaSourceRootDescriptor, ModuleBuildTarget>,
|
||||
outputConsumer: OutputConsumer
|
||||
): ExitCode {
|
||||
if (chunk.isDummy(context)) {
|
||||
return NOTHING_DONE
|
||||
}
|
||||
|
||||
val kotlinTarget = context.kotlin.targetsBinding.get(chunk.representativeTarget()) ?: return OK
|
||||
val messageCollector = MessageCollectorAdapter(context, kotlinTarget)
|
||||
|
||||
val kotlinDirtyFilesHolder = KotlinDirtySourceFilesHolder(chunk, context, dirtyFilesHolder)
|
||||
val fsOperations = FSOperationsHelper(context, chunk, kotlinDirtyFilesHolder, LOG)
|
||||
val reportService = JpsStatisticsReportService.getFromContext(context)
|
||||
reportService.reportDirtyFiles(kotlinDirtyFilesHolder)
|
||||
return reportService.reportMetrics(chunk, JpsBuildTime.JPS_ITERATION) {
|
||||
val proposedExitCode = doBuild(
|
||||
chunk = chunk,
|
||||
representativeTarget = kotlinTarget,
|
||||
context = context,
|
||||
kotlinDirtyFilesHolder = kotlinDirtyFilesHolder,
|
||||
messageCollector = messageCollector,
|
||||
outputConsumer = outputConsumer,
|
||||
fsOperations = fsOperations
|
||||
)
|
||||
val fsOperations = BazelKotlinFsOperationsHelper(
|
||||
context = context,
|
||||
chunk = chunk,
|
||||
dirtyFilesHolder = kotlinDirtyFilesHolder,
|
||||
log = log,
|
||||
)
|
||||
val proposedExitCode = doBuild(
|
||||
chunk = chunk,
|
||||
representativeTarget = kotlinTarget,
|
||||
context = context,
|
||||
kotlinDirtyFilesHolder = kotlinDirtyFilesHolder,
|
||||
messageCollector = MessageCollectorAdapter(context, kotlinTarget),
|
||||
outputConsumer = outputConsumer,
|
||||
fsOperations = fsOperations
|
||||
)
|
||||
|
||||
val actualExitCode = if (proposedExitCode == OK && fsOperations.hasMarkedDirty) ADDITIONAL_PASS_REQUIRED else proposedExitCode
|
||||
|
||||
LOG.debug("Build result: $actualExitCode")
|
||||
|
||||
context.testingContext?.buildLogger?.buildFinished(actualExitCode)
|
||||
actualExitCode
|
||||
}
|
||||
val actualExitCode = if (proposedExitCode == OK && fsOperations.hasMarkedDirty) ADDITIONAL_PASS_REQUIRED else proposedExitCode
|
||||
log.debug("build result: $actualExitCode")
|
||||
context.testingContext?.buildLogger?.buildFinished(actualExitCode)
|
||||
return actualExitCode
|
||||
}
|
||||
|
||||
private fun doBuild(
|
||||
@@ -292,27 +266,18 @@ internal class BazelKotlinBuilder(
|
||||
kotlinDirtyFilesHolder: KotlinDirtySourceFilesHolder,
|
||||
messageCollector: MessageCollectorAdapter,
|
||||
outputConsumer: OutputConsumer,
|
||||
fsOperations: FSOperationsHelper,
|
||||
fsOperations: BazelKotlinFsOperationsHelper,
|
||||
): ExitCode {
|
||||
val kotlinContext = context.kotlin
|
||||
val kotlinChunk = chunk.toKotlinChunk(context)!!
|
||||
|
||||
val kotlinChunk = context.kotlin.getChunk(chunk)!!
|
||||
if (!kotlinChunk.haveSameCompiler) {
|
||||
messageCollector.report(
|
||||
CompilerMessageSeverity.ERROR,
|
||||
KotlinJpsBundle.message(
|
||||
"error.text.cyclically.dependent.modules.0.should.have.same.compiler",
|
||||
kotlinChunk.presentableModulesToCompilersList
|
||||
)
|
||||
)
|
||||
return ABORT
|
||||
throw RuntimeException("Cyclically dependent modules ${kotlinChunk.presentableModulesToCompilersList} should have same compiler.")
|
||||
}
|
||||
|
||||
if (!kotlinChunk.isEnabled) {
|
||||
return NOTHING_DONE
|
||||
}
|
||||
|
||||
val projectDescriptor = context.projectDescriptor
|
||||
val targets = chunk.targets
|
||||
|
||||
val isChunkRebuilding = JavaBuilderUtil.isForcedRecompilationAllJavaModules(context) ||
|
||||
@@ -320,8 +285,8 @@ internal class BazelKotlinBuilder(
|
||||
|
||||
if (!kotlinDirtyFilesHolder.hasDirtyOrRemovedFiles) {
|
||||
if (isChunkRebuilding) {
|
||||
targets.forEach {
|
||||
kotlinContext.hasKotlinMarker[it] = false
|
||||
for (target in targets) {
|
||||
kotlinContext.hasKotlinMarker[target] = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,14 +306,10 @@ internal class BazelKotlinBuilder(
|
||||
|
||||
val targetsWithoutOutputDir = targets.filter { it.outputDir == null }
|
||||
if (targetsWithoutOutputDir.isNotEmpty()) {
|
||||
messageCollector.report(
|
||||
CompilerMessageSeverity.ERROR,
|
||||
KotlinJpsBundle.message("error.text.output.directory.not.specified.for.0", targetsWithoutOutputDir.joinToString())
|
||||
)
|
||||
return ABORT
|
||||
throw RuntimeException("Output directory not specified for ${targetsWithoutOutputDir.joinToString()}")
|
||||
}
|
||||
|
||||
val project = projectDescriptor.project
|
||||
val project = context.projectDescriptor.project
|
||||
val lookupTracker = getLookupTracker(project, representativeTarget)
|
||||
val exceptActualTracker = ExpectActualTrackerImpl()
|
||||
val incrementalCaches = kotlinChunk.loadCaches()
|
||||
@@ -374,9 +335,6 @@ internal class BazelKotlinBuilder(
|
||||
kotlinDirtyFilesHolder.allRemovedFilesFiles
|
||||
)
|
||||
|
||||
val reportService = JpsStatisticsReportService.getFromContext(context)
|
||||
reportService.reportCompilerArguments(chunk, kotlinChunk)
|
||||
val start = System.nanoTime()
|
||||
val outputItemCollector = doCompileModuleChunk(
|
||||
kotlinChunk = kotlinChunk,
|
||||
representativeTarget = representativeTarget,
|
||||
@@ -386,16 +344,13 @@ internal class BazelKotlinBuilder(
|
||||
fsOperations = fsOperations,
|
||||
environment = environment,
|
||||
incrementalCaches = incrementalCaches,
|
||||
buildMetricReporter = reportService.getMetricReporter(chunk)
|
||||
)
|
||||
|
||||
statisticsLogger.registerStatistic(chunk, System.nanoTime() - start)
|
||||
|
||||
if (outputItemCollector == null) {
|
||||
return NOTHING_DONE
|
||||
}
|
||||
|
||||
val compilationErrors = Utils.ERRORS_DETECTED_KEY[context, false]
|
||||
val compilationErrors = Utils.ERRORS_DETECTED_KEY.get(context, false)
|
||||
if (compilationErrors) {
|
||||
JavaBuilderUtil.registerFilesWithErrors(context, messageCollector.filesWithErrors.map(::File))
|
||||
return ABORT
|
||||
@@ -417,22 +372,22 @@ internal class BazelKotlinBuilder(
|
||||
|
||||
val kotlinTargets = kotlinContext.targetsBinding
|
||||
for ((target, outputItems) in generatedFiles) {
|
||||
val kotlinTarget = kotlinTargets[target] ?: error("Could not find Kotlin target for JPS target $target")
|
||||
val kotlinTarget = kotlinTargets.get(target) ?: error("Could not find Kotlin target for JPS target $target")
|
||||
kotlinTarget.registerOutputItems(outputConsumer, outputItems)
|
||||
}
|
||||
kotlinChunk.saveVersions()
|
||||
|
||||
if (targets.any { kotlinContext.hasKotlinMarker[it] == null }) {
|
||||
fsOperations.markChunk(recursively = false, kotlinOnly = true, excludeFiles = kotlinDirtyFilesHolder.allDirtyFiles)
|
||||
if (targets.any { kotlinContext.hasKotlinMarker.get(it) == null }) {
|
||||
fsOperations.markChunk(excludeFiles = kotlinDirtyFilesHolder.allDirtyFiles)
|
||||
}
|
||||
|
||||
for (target in targets) {
|
||||
kotlinContext.hasKotlinMarker[target] = true
|
||||
kotlinContext.hasKotlinMarker.set(target, true)
|
||||
kotlinContext.rebuildAfterCacheVersionChanged.clean(target)
|
||||
}
|
||||
|
||||
kotlinChunk.targets.forEach {
|
||||
it.doAfterBuild()
|
||||
for (target in kotlinChunk.targets) {
|
||||
target.doAfterBuild()
|
||||
}
|
||||
|
||||
representativeTarget.updateChunkMappings(
|
||||
@@ -459,10 +414,10 @@ internal class BazelKotlinBuilder(
|
||||
val kotlinModuleBuilderTarget = kotlinContext.targetsBinding[target]!!
|
||||
kotlinModuleBuilderTarget.updateCaches(
|
||||
dirtyFilesHolder = kotlinDirtyFilesHolder,
|
||||
jpsIncrementalCache = incrementalCaches[kotlinModuleBuilderTarget]!!,
|
||||
jpsIncrementalCache = incrementalCaches.get(kotlinModuleBuilderTarget)!!,
|
||||
files = files,
|
||||
changesCollector = changesCollector,
|
||||
environment = environment
|
||||
environment = environment,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -476,7 +431,8 @@ internal class BazelKotlinBuilder(
|
||||
compiledFiles = kotlinDirtyFilesHolder.allDirtyFiles,
|
||||
lookupStorageManager = kotlinContext.lookupStorageManager,
|
||||
fsOperations = fsOperations,
|
||||
caches = incrementalCaches.values
|
||||
caches = incrementalCaches.values,
|
||||
reporter = BazelJpsICReporter(log),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -492,17 +448,15 @@ internal class BazelKotlinBuilder(
|
||||
commonArguments: CommonCompilerArguments,
|
||||
context: CompileContext,
|
||||
dirtyFilesHolder: KotlinDirtySourceFilesHolder,
|
||||
fsOperations: FSOperationsHelper,
|
||||
fsOperations: BazelKotlinFsOperationsHelper,
|
||||
environment: JpsCompilerEnvironment,
|
||||
incrementalCaches: Map<KotlinModuleBuildTarget<*>, JpsIncrementalCache>,
|
||||
buildMetricReporter: JpsBuilderMetricReporter?,
|
||||
): OutputItemsCollector? {
|
||||
kotlinChunk.targets.forEach {
|
||||
it.nextRound(context)
|
||||
}
|
||||
|
||||
if (representativeTarget.isIncrementalCompilationEnabled) {
|
||||
buildMetricReporter?.addTag(StatTag.INCREMENTAL)
|
||||
for (target in kotlinChunk.targets) {
|
||||
val cache = incrementalCaches[target]
|
||||
val jpsTarget = target.jpsModuleBuildTarget
|
||||
@@ -519,8 +473,7 @@ internal class BazelKotlinBuilder(
|
||||
}
|
||||
|
||||
registerFilesToCompile(dirtyFilesHolder, context)
|
||||
val isDoneSomething = representativeTarget.compileModuleChunk(commonArguments, dirtyFilesHolder, environment, buildMetricReporter)
|
||||
|
||||
val isDoneSomething = representativeTarget.compileModuleChunk(commonArguments, dirtyFilesHolder, environment, null)
|
||||
return if (isDoneSomething) environment.outputItemsCollector else null
|
||||
}
|
||||
|
||||
@@ -529,8 +482,8 @@ internal class BazelKotlinBuilder(
|
||||
context: CompileContext,
|
||||
) {
|
||||
val allDirtyFiles = dirtyFilesHolder.allDirtyFiles
|
||||
if (LOG.isDebugEnabled) {
|
||||
LOG.debug("Compiling files: $allDirtyFiles")
|
||||
if (log.isDebugEnabled) {
|
||||
log.debug("compiling files: $allDirtyFiles")
|
||||
}
|
||||
JavaBuilderUtil.registerFilesToCompile(context, allDirtyFiles)
|
||||
}
|
||||
@@ -561,7 +514,7 @@ internal class BazelKotlinBuilder(
|
||||
}
|
||||
|
||||
return JpsCompilerEnvironment(
|
||||
kotlinPaths = computeKotlinPathsForJpsPlugin(messageCollector) ?: return null,
|
||||
kotlinPaths = computeKotlinPathsForJpsPlugin() ?: return null,
|
||||
services = compilerServices,
|
||||
classesToLoadByParent = classesToLoadByParent,
|
||||
messageCollector = messageCollector,
|
||||
@@ -570,25 +523,14 @@ internal class BazelKotlinBuilder(
|
||||
)
|
||||
}
|
||||
|
||||
// When JPS is run on TeamCity, it can not rely on Kotlin plugin layout,
|
||||
// so the path to Kotlin is specified in a system property
|
||||
private fun computeKotlinPathsForJpsPlugin(messageCollector: MessageCollectorAdapter): KotlinPaths? {
|
||||
private fun computeKotlinPathsForJpsPlugin(): KotlinPaths? {
|
||||
val jpsKotlinHome = System.getProperty(JPS_KOTLIN_HOME_PROPERTY)?.let { File(it) }
|
||||
if (System.getProperty("kotlin.jps.tests").equals("true", ignoreCase = true) && jpsKotlinHome == null) {
|
||||
return PathUtil.kotlinPathsForDistDirectory
|
||||
?: throw RuntimeException("Make sure that '$JPS_KOTLIN_HOME_PROPERTY' system property is set in JPS process")
|
||||
if (jpsKotlinHome.exists()) {
|
||||
return KotlinPathsFromHomeDir(jpsKotlinHome)
|
||||
}
|
||||
|
||||
return when {
|
||||
jpsKotlinHome == null -> {
|
||||
messageCollector.report(CompilerMessageSeverity.ERROR, "Make sure that '$JPS_KOTLIN_HOME_PROPERTY' system property is set in JPS process")
|
||||
null
|
||||
}
|
||||
|
||||
jpsKotlinHome.exists() -> KotlinPathsFromHomeDir(jpsKotlinHome)
|
||||
else -> {
|
||||
messageCollector.report(CompilerMessageSeverity.ERROR, "Cannot find kotlinc home at $jpsKotlinHome")
|
||||
null
|
||||
}
|
||||
else {
|
||||
throw RuntimeException("Cannot find kotlinc home at $jpsKotlinHome")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -641,7 +583,7 @@ internal class BazelKotlinBuilder(
|
||||
generatedFiles: Map<ModuleBuildTarget, List<GeneratedFile>>,
|
||||
kotlinContext: KotlinCompileContext,
|
||||
incrementalCaches: Map<KotlinModuleBuildTarget<*>, JpsIncrementalCache>,
|
||||
fsOperations: FSOperationsHelper
|
||||
fsOperations: BazelKotlinFsOperationsHelper,
|
||||
) {
|
||||
for ((target, files) in generatedFiles) {
|
||||
val kotlinModuleBuilderTarget = kotlinContext.targetsBinding[target] ?: continue
|
||||
@@ -653,21 +595,21 @@ internal class BazelKotlinBuilder(
|
||||
val actualParts = generated.filter { it.outputClass.classHeader.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS_PART }
|
||||
.map { it.outputClass.className.toString() }
|
||||
if (!actualParts.containsAll(expectedAllParts)) {
|
||||
fsOperations.markFiles(expectedAllParts.flatMap { cache.sourcesByInternalName(it) }
|
||||
+ multifileClasses.flatMap { it.sourceFiles })
|
||||
fsOperations.markFiles(expectedAllParts.asSequence().flatMap { cache.sourcesByInternalName(it) }
|
||||
+ multifileClasses.asSequence().flatMap { it.sourceFiles })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class JpsICReporter : ICReporterBase() {
|
||||
private class BazelJpsICReporter(private val log: RequestLog) : ICReporterBase() {
|
||||
override fun reportCompileIteration(incremental: Boolean, sourceFiles: Collection<File>, exitCode: ExitCode) {
|
||||
}
|
||||
|
||||
override fun report(message: () -> String, severity: ReportSeverity) {
|
||||
// Currently, all severity levels are mapped to debug
|
||||
if (KotlinBuilder.LOG.isDebugEnabled) {
|
||||
KotlinBuilder.LOG.debug(message())
|
||||
if (log.isDebugEnabled) {
|
||||
log.debug(message())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -676,16 +618,19 @@ private fun processChangesUsingLookups(
|
||||
collector: ChangesCollector,
|
||||
compiledFiles: Set<File>,
|
||||
lookupStorageManager: JpsLookupStorageManager,
|
||||
fsOperations: FSOperationsHelper,
|
||||
caches: Iterable<JpsIncrementalCache>
|
||||
fsOperations: BazelKotlinFsOperationsHelper,
|
||||
caches: Iterable<JpsIncrementalCache>,
|
||||
reporter: ICReporter,
|
||||
) {
|
||||
val allCaches = caches.flatMap { it.thisWithDependentCaches }
|
||||
val reporter = JpsICReporter()
|
||||
|
||||
reporter.debug { "Start processing changes" }
|
||||
|
||||
val dirtyFiles = collector.getDirtyFiles(allCaches, lookupStorageManager)
|
||||
// if list of inheritors of sealed class has changed it should be recompiled with all the inheritors
|
||||
val dirtyFiles = getDirtyFiles(
|
||||
changeCollector = collector,
|
||||
caches = allCaches,
|
||||
lookupStorageManager = lookupStorageManager,
|
||||
reporter = reporter,
|
||||
)
|
||||
// if a list of inheritors of sealed class has changed it should be recompiled with all the inheritors
|
||||
// Here we have a small optimization. Do not recompile the bunch if ALL these files were recompiled during the previous round.
|
||||
val excludeFiles = if (compiledFiles.containsAll(dirtyFiles.forceRecompileTogether)) {
|
||||
compiledFiles
|
||||
@@ -694,27 +639,26 @@ private fun processChangesUsingLookups(
|
||||
compiledFiles.minus(dirtyFiles.forceRecompileTogether)
|
||||
}
|
||||
fsOperations.markInChunkOrDependents(
|
||||
(dirtyFiles.dirtyFiles + dirtyFiles.forceRecompileTogether).asIterable(),
|
||||
excludeFiles = excludeFiles
|
||||
files = (dirtyFiles.dirtyFiles.asSequence() + dirtyFiles.forceRecompileTogether),
|
||||
excludeFiles = excludeFiles,
|
||||
)
|
||||
|
||||
reporter.debug { "End of processing changes" }
|
||||
}
|
||||
|
||||
private data class FilesToRecompile(@JvmField val dirtyFiles: Set<File>, @JvmField val forceRecompileTogether: Set<File>)
|
||||
|
||||
private fun ChangesCollector.getDirtyFiles(
|
||||
private fun getDirtyFiles(
|
||||
changeCollector: ChangesCollector,
|
||||
caches: Iterable<IncrementalCacheCommon>,
|
||||
lookupStorageManager: JpsLookupStorageManager
|
||||
lookupStorageManager: JpsLookupStorageManager,
|
||||
reporter: ICReporter,
|
||||
): FilesToRecompile {
|
||||
val reporter = JpsICReporter()
|
||||
val (dirtyLookupSymbols, dirtyClassFqNames, forceRecompile) = getChangedAndImpactedSymbols(caches, reporter)
|
||||
val (dirtyLookupSymbols, dirtyClassFqNames, forceRecompile) = changeCollector.changes().getChangedAndImpactedSymbols(caches, reporter)
|
||||
val dirtyFilesFromLookups = lookupStorageManager.withLookupStorage {
|
||||
mapLookupSymbolsToFiles(lookupStorage = it, lookupSymbols = dirtyLookupSymbols, reporter = reporter)
|
||||
}
|
||||
return FilesToRecompile(
|
||||
dirtyFilesFromLookups + mapClassesFqNamesToFiles(caches, dirtyClassFqNames, reporter),
|
||||
mapClassesFqNamesToFiles(caches, forceRecompile, reporter)
|
||||
dirtyFiles = dirtyFilesFromLookups + mapClassesFqNamesToFiles(caches, dirtyClassFqNames, reporter),
|
||||
forceRecompileTogether = mapClassesFqNamesToFiles(caches, forceRecompile, reporter)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
@file:Suppress("HardCodedStringLiteral", "INVISIBLE_REFERENCE", "INVISIBLE_MEMBER", "DialogTitleCapitalization", "UnstableApiUsage", "ReplaceGetOrSet")
|
||||
package org.jetbrains.bazel.jvm.jps.impl
|
||||
|
||||
import com.intellij.openapi.util.io.FileUtilRt
|
||||
import org.jetbrains.bazel.jvm.jps.RequestLog
|
||||
import org.jetbrains.jps.ModuleChunk
|
||||
import org.jetbrains.jps.builders.BuildRootDescriptor
|
||||
import org.jetbrains.jps.builders.FileProcessor
|
||||
import org.jetbrains.jps.builders.impl.DirtyFilesHolderBase
|
||||
import org.jetbrains.jps.builders.java.JavaBuilderUtil
|
||||
import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor
|
||||
import org.jetbrains.jps.incremental.BuildOperations
|
||||
import org.jetbrains.jps.incremental.CompileContext
|
||||
import org.jetbrains.jps.incremental.FSOperations
|
||||
import org.jetbrains.jps.incremental.FSOperations.addCompletelyMarkedDirtyTarget
|
||||
import org.jetbrains.jps.incremental.ModuleBuildTarget
|
||||
import org.jetbrains.jps.incremental.fs.CompilationRound
|
||||
import org.jetbrains.kotlin.jps.build.KotlinDirtySourceFilesHolder
|
||||
import java.io.File
|
||||
import java.nio.file.Path
|
||||
|
||||
internal class BazelKotlinFsOperationsHelper(
|
||||
private val context: CompileContext,
|
||||
private val chunk: ModuleChunk,
|
||||
private val dirtyFilesHolder: KotlinDirtySourceFilesHolder,
|
||||
private val log: RequestLog,
|
||||
) {
|
||||
internal var hasMarkedDirty = false
|
||||
private set
|
||||
|
||||
fun markChunk(excludeFiles: Set<File>) {
|
||||
val target = chunk.targets.single()
|
||||
val filter = { file: Path ->
|
||||
val filePath = file.toString()
|
||||
when {
|
||||
!(FileUtilRt.extensionEquals(filePath, "kt") || FileUtilRt.extensionEquals(filePath, "kts")) -> {
|
||||
false
|
||||
}
|
||||
excludeFiles.contains(file.toFile()) -> {
|
||||
false
|
||||
}
|
||||
else -> {
|
||||
hasMarkedDirty = true
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var completelyMarkedDirty = true
|
||||
val stampStorage = context.projectDescriptor.dataManager.getFileStampStorage(target)
|
||||
for (rootDescriptor in (context.projectDescriptor.buildRootIndex as BazelBuildRootIndex).descriptors) {
|
||||
val file = rootDescriptor.rootFile
|
||||
if (!filter(file)) {
|
||||
completelyMarkedDirty = false
|
||||
continue
|
||||
}
|
||||
|
||||
// if it is a full project rebuild, all storages are already completely cleared;
|
||||
// so passing null because there is no need to access the storage to clear non-existing data
|
||||
val marker = if (JavaBuilderUtil.isForcedRecompilationAllJavaModules(context)) null else stampStorage
|
||||
context.projectDescriptor.fsState.markDirty(context, CompilationRound.NEXT, file, rootDescriptor, marker, false)
|
||||
}
|
||||
|
||||
if (completelyMarkedDirty) {
|
||||
addCompletelyMarkedDirtyTarget(context, target)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun markFilesForCurrentRound(files: Sequence<File>) {
|
||||
val buildRootIndex = context.projectDescriptor.buildRootIndex as BazelBuildRootIndex
|
||||
for (file in files) {
|
||||
val root = buildRootIndex.fileToDescriptors.get(file.toPath())
|
||||
if (root != null) {
|
||||
dirtyFilesHolder.byTarget[root.target]?._markDirty(file, root)
|
||||
}
|
||||
}
|
||||
|
||||
markFilesImpl(files, currentRound = true) { it.exists() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks given [files] as dirty for current round and given [target] of [chunk].
|
||||
*/
|
||||
fun markFilesForCurrentRound(target: ModuleBuildTarget, files: Collection<File>) {
|
||||
require(target in chunk.targets)
|
||||
|
||||
val targetDirtyFiles = dirtyFilesHolder.byTarget.getValue(target)
|
||||
val dirtyFileToRoot = HashMap<File, JavaSourceRootDescriptor>()
|
||||
for (file in files) {
|
||||
val root = context.projectDescriptor.buildRootIndex
|
||||
.findAllParentDescriptors<BuildRootDescriptor>(file, context)
|
||||
.single { sourceRoot -> sourceRoot.target == target }
|
||||
|
||||
targetDirtyFiles._markDirty(file, root as JavaSourceRootDescriptor)
|
||||
dirtyFileToRoot[file] = root
|
||||
}
|
||||
|
||||
markFilesImpl(files.asSequence(), currentRound = true) { it.exists() }
|
||||
cleanOutputsForNewDirtyFilesInCurrentRound(target, dirtyFileToRoot)
|
||||
}
|
||||
|
||||
private fun cleanOutputsForNewDirtyFilesInCurrentRound(target: ModuleBuildTarget, dirtyFiles: Map<File, JavaSourceRootDescriptor>) {
|
||||
val dirtyFilesHolder = object : DirtyFilesHolderBase<JavaSourceRootDescriptor, ModuleBuildTarget>(context) {
|
||||
override fun processDirtyFiles(processor: FileProcessor<JavaSourceRootDescriptor, ModuleBuildTarget>) {
|
||||
for ((file, root) in dirtyFiles) {
|
||||
processor.apply(target, file, root)
|
||||
}
|
||||
}
|
||||
|
||||
override fun hasDirtyFiles(): Boolean = dirtyFiles.isNotEmpty()
|
||||
}
|
||||
BuildOperations.cleanOutputsCorrespondingToChangedFiles(context, dirtyFilesHolder)
|
||||
}
|
||||
|
||||
fun markFiles(files: Sequence<File>) {
|
||||
markFilesImpl(files, currentRound = false) { it.exists() }
|
||||
}
|
||||
|
||||
fun markInChunkOrDependents(files: Sequence<File>, excludeFiles: Set<File>) {
|
||||
markFilesImpl(files, currentRound = false) {
|
||||
!excludeFiles.contains(it) && it.exists()
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun markFilesImpl(
|
||||
files: Sequence<File>,
|
||||
currentRound: Boolean,
|
||||
shouldMark: (File) -> Boolean
|
||||
) {
|
||||
val filesToMark = files.filterTo(HashSet(), shouldMark)
|
||||
if (filesToMark.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
val compilationRound = if (currentRound) {
|
||||
CompilationRound.CURRENT
|
||||
}
|
||||
else {
|
||||
hasMarkedDirty = true
|
||||
CompilationRound.NEXT
|
||||
}
|
||||
|
||||
for (fileToMark in filesToMark) {
|
||||
FSOperations.markDirty(context, compilationRound, fileToMark)
|
||||
}
|
||||
log.debug("Mark dirty: $filesToMark ($compilationRound)")
|
||||
}
|
||||
}
|
||||
@@ -4,22 +4,18 @@
|
||||
package org.jetbrains.bazel.jvm.jps.impl
|
||||
|
||||
import com.intellij.tracing.Tracer
|
||||
import com.intellij.util.containers.FileHashStrategy
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMaps
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap
|
||||
import org.jetbrains.bazel.jvm.jps.ConsoleMessageHandler
|
||||
import org.jetbrains.bazel.jvm.jps.RequestLog
|
||||
import org.jetbrains.jps.ModuleChunk
|
||||
import org.jetbrains.jps.builders.BuildTarget
|
||||
import org.jetbrains.jps.builders.FileProcessor
|
||||
import org.jetbrains.jps.builders.impl.BuildOutputConsumerImpl
|
||||
import org.jetbrains.jps.builders.impl.BuildTargetChunk
|
||||
import org.jetbrains.jps.builders.impl.DirtyFilesHolderBase
|
||||
import org.jetbrains.jps.builders.java.JavaBuilderUtil
|
||||
import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor
|
||||
import org.jetbrains.jps.builders.storage.BuildDataCorruptedException
|
||||
import org.jetbrains.jps.builders.storage.SourceToOutputMapping
|
||||
import org.jetbrains.jps.incremental.*
|
||||
import org.jetbrains.jps.incremental.ModuleLevelBuilder.OutputConsumer
|
||||
import org.jetbrains.jps.incremental.fs.BuildFSState
|
||||
import org.jetbrains.jps.incremental.fs.CompilationRound
|
||||
import org.jetbrains.jps.incremental.messages.*
|
||||
import org.jetbrains.jps.incremental.storage.BuildTargetConfiguration
|
||||
@@ -34,7 +30,6 @@ import java.util.concurrent.ConcurrentHashMap
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.concurrent.atomic.AtomicLong
|
||||
import java.util.function.Function
|
||||
import java.util.function.Predicate
|
||||
import kotlin.concurrent.Volatile
|
||||
|
||||
private val TARGET_WITH_CLEARED_OUTPUT = GlobalContextKey.create<MutableSet<BuildTarget<*>>>("_targets_with_cleared_output_")
|
||||
@@ -47,34 +42,34 @@ private const val CLASSPATH_INDEX_FILE_NAME = "classpath.index"
|
||||
private const val UNMODIFIED_MARK_FILE_NAME = ".unmodified"
|
||||
|
||||
internal class JpsProjectBuilder(
|
||||
private val builderRegistry: BuilderRegistry,
|
||||
private val messageHandler: ConsoleMessageHandler,
|
||||
private val log: RequestLog,
|
||||
private val isCleanBuild: Boolean,
|
||||
private val dataManager: BazelBuildDataProvider,
|
||||
) {
|
||||
private val totalModuleLevelBuilderCount = builderRegistry.moduleLevelBuilderCount
|
||||
private val elapsedTimeNanosByBuilder = ConcurrentHashMap<Builder, AtomicLong>()
|
||||
private val numberOfSourcesProcessedByBuilder = ConcurrentHashMap<Builder, AtomicInteger>()
|
||||
|
||||
fun build(context: CompileContextImpl, moduleTarget: BazelModuleBuildTarget) {
|
||||
fun build(context: CompileContextImpl, moduleTarget: BazelModuleBuildTarget, builders: Array<ModuleLevelBuilder>): Int {
|
||||
try {
|
||||
val buildSpan = Tracer.start("IncProjectBuilder.runBuild")
|
||||
runBuild(context, moduleTarget = moduleTarget)
|
||||
runBuild(context, moduleTarget = moduleTarget, builders = builders)
|
||||
buildSpan.complete()
|
||||
}
|
||||
catch (e: StopBuildException) {
|
||||
// some builder decided to stop the build - report optional progress message if any
|
||||
e.message?.takeIf { it.isNotEmpty() }?.let {
|
||||
messageHandler.processMessage(ProgressMessage(it))
|
||||
log.processMessage(ProgressMessage(it))
|
||||
}
|
||||
return if (log.hasErrors()) 1 else 0
|
||||
}
|
||||
catch (e: BuildDataCorruptedException) {
|
||||
messageHandler.warn("Internal caches are corrupted or have outdated format, forcing project rebuild: $e")
|
||||
log.warn("Internal caches are corrupted or have outdated format, forcing project rebuild: $e")
|
||||
throw RebuildRequestedException(e)
|
||||
}
|
||||
catch (e: ProjectBuildException) {
|
||||
val cause = e.cause
|
||||
if (cause is IOException || cause is BuildDataCorruptedException || (cause is RuntimeException && cause.cause is IOException)) {
|
||||
messageHandler.warn("Internal caches are corrupted or have outdated format, forcing project rebuild: $e")
|
||||
log.warn("Internal caches are corrupted or have outdated format, forcing project rebuild: $e")
|
||||
throw RebuildRequestedException(cause)
|
||||
}
|
||||
else {
|
||||
@@ -82,9 +77,10 @@ internal class JpsProjectBuilder(
|
||||
throw e
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
private fun runBuild(context: CompileContextImpl, moduleTarget: BazelModuleBuildTarget) {
|
||||
private fun runBuild(context: CompileContextImpl, moduleTarget: BazelModuleBuildTarget, builders: Array<ModuleLevelBuilder>) {
|
||||
context.setDone(0.0f)
|
||||
|
||||
context.addBuildListener(ChainedTargetsBuildListener(context))
|
||||
@@ -118,26 +114,13 @@ internal class JpsProjectBuilder(
|
||||
}
|
||||
}
|
||||
})
|
||||
require(builderRegistry.targetBuilders.isEmpty())
|
||||
val allModuleLevelBuildersBuildStartedSpan = Tracer.start("All ModuleLevelBuilder.buildStarted")
|
||||
for (builder in builderRegistry.moduleLevelBuilders) {
|
||||
for (builder in builders) {
|
||||
builder.buildStarted(context)
|
||||
}
|
||||
allModuleLevelBuildersBuildStartedSpan.complete()
|
||||
|
||||
val projectDescriptor = context.projectDescriptor
|
||||
var buildProgress: BuildProgress? = null
|
||||
try {
|
||||
val sortedTargetChunks = projectDescriptor.buildTargetIndex.getSortedTargetChunks(context)
|
||||
buildProgress = BuildProgress(
|
||||
projectDescriptor.dataManager,
|
||||
projectDescriptor.buildTargetIndex,
|
||||
sortedTargetChunks,
|
||||
Predicate { context.scope.isAffected(moduleTarget) }
|
||||
)
|
||||
|
||||
require(builderRegistry.beforeTasks.isEmpty())
|
||||
|
||||
val checkingSourcesSpan = Tracer.start("Building targets")
|
||||
// We don't call closeSourceToOutputStorages as we only built a single target and close the database after the build.
|
||||
// (In any case, for the new storage, it only involves removing the cached map with no actual IO close operation or using MVStore API)
|
||||
@@ -145,22 +128,14 @@ internal class JpsProjectBuilder(
|
||||
val affected = context.scope.isAffected(moduleTarget)
|
||||
isAffectedSpan.complete()
|
||||
if (affected) {
|
||||
buildTargetChunk(context = context, buildProgress = buildProgress, moduleTarget = moduleTarget)
|
||||
buildTargetChunk(context = context, target = moduleTarget, builders = builders)
|
||||
}
|
||||
checkingSourcesSpan.complete()
|
||||
|
||||
require(builderRegistry.afterTasks.isEmpty())
|
||||
sendElapsedTimeMessages(context)
|
||||
}
|
||||
finally {
|
||||
if (buildProgress != null) {
|
||||
buildProgress.updateExpectedAverageTime()
|
||||
if (isCleanBuild && !Utils.errorsDetected(context) && !context.cancelStatus.isCanceled) {
|
||||
projectDescriptor.dataManager.targetStateManager.setLastSuccessfulRebuildDuration(buildProgress.absoluteBuildTime)
|
||||
}
|
||||
}
|
||||
|
||||
for (builder in builderRegistry.moduleLevelBuilders) {
|
||||
for (builder in builders) {
|
||||
builder.buildFinished(context)
|
||||
}
|
||||
}
|
||||
@@ -178,77 +153,71 @@ internal class JpsProjectBuilder(
|
||||
.forEach { context.processMessage(it) }
|
||||
}
|
||||
|
||||
private fun deleteAndCollectDeleted(file: Path, deletedPaths: MutableList<Path>, parentDirs: MutableSet<Path>): Boolean {
|
||||
val deleted = Files.deleteIfExists(file)
|
||||
if (deleted) {
|
||||
deletedPaths.add(file)
|
||||
file.parent?.let {
|
||||
parentDirs.add(it)
|
||||
}
|
||||
}
|
||||
return deleted
|
||||
}
|
||||
|
||||
private fun processDeletedPaths(context: CompileContext, target: ModuleBuildTarget): Boolean {
|
||||
var doneSomething = false
|
||||
// cleanup outputs
|
||||
val targetToRemovedSources = HashMap<BuildTarget<*>, MutableCollection<String>>()
|
||||
|
||||
val dirsToDelete = HashSet<Path>()
|
||||
for (target in arrayOf(target)) {
|
||||
val deletedPaths = context.projectDescriptor.fsState.getAndClearDeletedPaths(target)
|
||||
if (deletedPaths.isEmpty()) {
|
||||
continue
|
||||
}
|
||||
val deletedPaths = context.projectDescriptor.fsState.getAndClearDeletedPaths(target).asSequence().map { Path.of(it) }.sorted().toList()
|
||||
if (deletedPaths.isEmpty()) {
|
||||
return false
|
||||
}
|
||||
|
||||
targetToRemovedSources.put(target, deletedPaths)
|
||||
if (isTargetOutputCleared(context, target)) {
|
||||
continue
|
||||
}
|
||||
if (isTargetOutputCleared(context, target)) {
|
||||
return false
|
||||
}
|
||||
|
||||
val dataManager = context.projectDescriptor.dataManager
|
||||
val buildTargetId = dataManager.targetStateManager.getBuildTargetId(target)
|
||||
val sourceToOutputStorage = dataManager.getSourceToOutputMap(target)
|
||||
val logger = context.loggingManager.projectBuilderLogger
|
||||
// actually delete outputs associated with removed paths
|
||||
for (deletedSource in deletedPaths.sorted()) {
|
||||
// deleting outputs corresponding to a non-existing source
|
||||
val outputs = sourceToOutputStorage.getOutputs(deletedSource)
|
||||
if (outputs != null && !outputs.isEmpty()) {
|
||||
val deletedOutputPaths = ArrayList<String>()
|
||||
val outputToSourceRegistry = dataManager.outputToTargetMapping
|
||||
for (output in outputToSourceRegistry.removeTargetAndGetSafeToDeleteOutputs(outputs, buildTargetId, sourceToOutputStorage)) {
|
||||
val deleted = BuildOperations.deleteRecursivelyAndCollectDeleted(Path.of(output), deletedOutputPaths, dirsToDelete)
|
||||
if (deleted) {
|
||||
doneSomething = true
|
||||
}
|
||||
}
|
||||
if (!deletedOutputPaths.isEmpty()) {
|
||||
if (logger.isEnabled) {
|
||||
logger.logDeletedFiles(deletedOutputPaths)
|
||||
}
|
||||
context.processMessage(FileDeletedEvent(deletedOutputPaths))
|
||||
var doneSomething = false
|
||||
val dataManager = context.projectDescriptor.dataManager
|
||||
val sourceToOutputStorage = dataManager.getSourceToOutputMap(target)
|
||||
// actually delete outputs associated with removed paths
|
||||
for (deletedFile in deletedPaths) {
|
||||
// deleting outputs corresponding to a non-existing source
|
||||
val outputs = sourceToOutputStorage.getOutputs(deletedFile)
|
||||
if (outputs != null && !outputs.isEmpty()) {
|
||||
val deletedOutputFiles = ArrayList<Path>()
|
||||
for (output in outputs) {
|
||||
val deleted = deleteAndCollectDeleted(output, deletedOutputFiles, dirsToDelete)
|
||||
if (deleted) {
|
||||
doneSomething = true
|
||||
}
|
||||
}
|
||||
|
||||
// check if the deleted source was associated with a form
|
||||
val sourceToFormMap = dataManager.getSourceToFormMap(target)
|
||||
val boundForms = sourceToFormMap.getOutputs(deletedSource)
|
||||
if (boundForms != null) {
|
||||
for (formPath in boundForms) {
|
||||
val formFile = Path.of(formPath)
|
||||
if (Files.exists(formFile)) {
|
||||
FSOperations.markDirty(context, CompilationRound.CURRENT, formFile.toFile())
|
||||
}
|
||||
}
|
||||
sourceToFormMap.remove(deletedSource)
|
||||
if (!deletedOutputFiles.isEmpty()) {
|
||||
log.info("Deleted files: $deletedOutputFiles")
|
||||
context.processMessage(FileDeletedEvent(deletedOutputFiles.map { it.toString() }))
|
||||
}
|
||||
}
|
||||
|
||||
// check if the deleted source was associated with a form
|
||||
val sourceToFormMap = dataManager.getSourceToFormMap(target)
|
||||
val boundForms = sourceToFormMap.getOutputs(deletedFile)
|
||||
if (boundForms != null) {
|
||||
for (formFile in boundForms) {
|
||||
if (Files.exists(formFile)) {
|
||||
FSOperations.markDirty(context, CompilationRound.CURRENT, formFile.toFile())
|
||||
}
|
||||
}
|
||||
sourceToFormMap.remove(deletedFile)
|
||||
}
|
||||
}
|
||||
|
||||
if (!targetToRemovedSources.isEmpty()) {
|
||||
val existing = Utils.REMOVED_SOURCES_KEY.get(context)
|
||||
if (existing != null) {
|
||||
for (entry in existing.entries) {
|
||||
val paths = targetToRemovedSources.get(entry.key)
|
||||
if (paths == null) {
|
||||
targetToRemovedSources.put(entry.key, entry.value)
|
||||
}
|
||||
else {
|
||||
paths.addAll(entry.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
Utils.REMOVED_SOURCES_KEY.set(context, targetToRemovedSources)
|
||||
val existing = Utils.REMOVED_SOURCES_KEY.get(context).get(target)
|
||||
if (existing == null) {
|
||||
Utils.REMOVED_SOURCES_KEY.set(context, java.util.Map.of(target, deletedPaths as Collection<Path>))
|
||||
}
|
||||
else {
|
||||
val set = LinkedHashSet<Path>()
|
||||
set.addAll(existing)
|
||||
set.addAll(deletedPaths)
|
||||
Utils.REMOVED_SOURCES_KEY.set(context, java.util.Map.of(target, set as Collection<Path>))
|
||||
}
|
||||
|
||||
FSOperations.pruneEmptyDirs(context, dirsToDelete)
|
||||
@@ -256,19 +225,21 @@ internal class JpsProjectBuilder(
|
||||
}
|
||||
|
||||
// return true if changed something, false otherwise
|
||||
private fun runModuleLevelBuilders(context: CompileContext, moduleTarget: BazelModuleBuildTarget, buildProgress: BuildProgress): Boolean {
|
||||
val chunk = ModuleChunk(setOf(moduleTarget))
|
||||
for (category in BuilderCategory.entries) {
|
||||
for (builder in builderRegistry.getBuilders(category)) {
|
||||
builder.chunkBuildStarted(context, chunk)
|
||||
}
|
||||
private fun runModuleLevelBuilders(
|
||||
context: CompileContext,
|
||||
moduleTarget: BazelModuleBuildTarget,
|
||||
builders: Array<ModuleLevelBuilder>,
|
||||
): Boolean {
|
||||
val chunk = ModuleChunk(java.util.Set.of<ModuleBuildTarget>(moduleTarget))
|
||||
for (builder in builders) {
|
||||
builder.chunkBuildStarted(context, chunk)
|
||||
}
|
||||
|
||||
completeRecompiledSourcesSet(context, moduleTarget)
|
||||
if (!isCleanBuild) {
|
||||
completeRecompiledSourcesSet(context, moduleTarget)
|
||||
}
|
||||
|
||||
var doneSomething = false
|
||||
var rebuildFromScratchRequested = false
|
||||
var nextPassRequired: Boolean
|
||||
val outputConsumer = ChunkBuildOutputConsumerImpl(context)
|
||||
try {
|
||||
val fsState = context.projectDescriptor.fsState
|
||||
@@ -280,11 +251,13 @@ internal class JpsProjectBuilder(
|
||||
}
|
||||
}
|
||||
|
||||
var rebuildFromScratchRequested = false
|
||||
var nextPassRequired: Boolean
|
||||
do {
|
||||
nextPassRequired = false
|
||||
fsState.beforeNextRoundStart(context, chunk)
|
||||
|
||||
if (!JavaBuilderUtil.isForcedRecompilationAllJavaModules(context.scope)) {
|
||||
if (!isCleanBuild) {
|
||||
val cleanedSources = BuildOperations.cleanOutputsCorrespondingToChangedFiles(context, dirtyFilesHolder)
|
||||
for (entry in cleanedSources.entries) {
|
||||
val files = entry.value.keys
|
||||
@@ -293,11 +266,11 @@ internal class JpsProjectBuilder(
|
||||
}
|
||||
|
||||
val mapping = context.projectDescriptor.dataManager.getSourceToOutputMap(entry.key)
|
||||
for (srcFile in files) {
|
||||
val outputs = entry.value.get(srcFile)!!
|
||||
mapping.setOutputs(srcFile.path, outputs)
|
||||
for (sourceFile in files) {
|
||||
val outputs = entry.value.get(sourceFile)!!
|
||||
mapping.setOutputs(sourceFile, outputs)
|
||||
if (!outputs.isEmpty()) {
|
||||
messageHandler.info("Some outputs were not removed for ${srcFile.path} source file: $outputs")
|
||||
log.info("Some outputs were not removed for $sourceFile source file: $outputs")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -305,73 +278,58 @@ internal class JpsProjectBuilder(
|
||||
|
||||
try {
|
||||
var buildersPassed = 0
|
||||
BUILDER_CATEGORY_LOOP@ for (category in BuilderCategory.entries) {
|
||||
val builders = builderRegistry.getBuilders(category)
|
||||
if (category == BuilderCategory.CLASS_POST_PROCESSOR) {
|
||||
var instrumentedClassesSaved = false
|
||||
for (builder in builders) {
|
||||
if (builder.category == BuilderCategory.CLASS_POST_PROCESSOR && !instrumentedClassesSaved) {
|
||||
instrumentedClassesSaved = true
|
||||
// ensure changes from instruments are visible to class post-processors
|
||||
saveInstrumentedClasses(outputConsumer)
|
||||
}
|
||||
if (builders.isEmpty()) {
|
||||
continue
|
||||
|
||||
outputConsumer.setCurrentBuilderName(builder.presentableName)
|
||||
processDeletedPaths(context, moduleTarget)
|
||||
val start = System.nanoTime()
|
||||
val processedSourcesBefore = outputConsumer.getNumberOfProcessedSources()
|
||||
val buildResult = builder.build(context, chunk, dirtyFilesHolder, outputConsumer)
|
||||
storeBuilderStatistics(
|
||||
builder = builder,
|
||||
elapsedTime = System.nanoTime() - start,
|
||||
processedFiles = outputConsumer.getNumberOfProcessedSources() - processedSourcesBefore,
|
||||
)
|
||||
|
||||
doneSomething = doneSomething or (buildResult != ModuleLevelBuilder.ExitCode.NOTHING_DONE)
|
||||
|
||||
if (buildResult == ModuleLevelBuilder.ExitCode.ABORT) {
|
||||
throw StopBuildException("Builder ${builder.presentableName} requested build stop")
|
||||
}
|
||||
|
||||
try {
|
||||
for (builder in builders) {
|
||||
outputConsumer.setCurrentBuilderName(builder.presentableName)
|
||||
processDeletedPaths(context, moduleTarget)
|
||||
val start = System.nanoTime()
|
||||
val processedSourcesBefore = outputConsumer.getNumberOfProcessedSources()
|
||||
val buildResult = builder.build(context, chunk, dirtyFilesHolder, outputConsumer)
|
||||
storeBuilderStatistics(
|
||||
builder = builder,
|
||||
elapsedTime = System.nanoTime() - start,
|
||||
processedFiles = outputConsumer.getNumberOfProcessedSources() - processedSourcesBefore,
|
||||
)
|
||||
|
||||
doneSomething = doneSomething or (buildResult != ModuleLevelBuilder.ExitCode.NOTHING_DONE)
|
||||
|
||||
if (buildResult == ModuleLevelBuilder.ExitCode.ABORT) {
|
||||
throw StopBuildException("Builder ${builder.presentableName} requested build stop")
|
||||
}
|
||||
context.checkCanceled()
|
||||
if (buildResult == ModuleLevelBuilder.ExitCode.ADDITIONAL_PASS_REQUIRED) {
|
||||
nextPassRequired = true
|
||||
}
|
||||
else if (buildResult == ModuleLevelBuilder.ExitCode.CHUNK_REBUILD_REQUIRED) {
|
||||
if (!rebuildFromScratchRequested && !JavaBuilderUtil.isForcedRecompilationAllJavaModules(context.scope)) {
|
||||
notifyChunkRebuildRequested(context, chunk, builder)
|
||||
// allow rebuild from scratch only once per chunk
|
||||
rebuildFromScratchRequested = true
|
||||
try {
|
||||
// forcibly mark all files in the chunk dirty
|
||||
fsState.clearContextRoundData(context)
|
||||
FSOperations.markDirty(context, CompilationRound.NEXT, chunk, null)
|
||||
// reverting to the beginning
|
||||
nextPassRequired = true
|
||||
outputConsumer.clear()
|
||||
break@BUILDER_CATEGORY_LOOP
|
||||
}
|
||||
catch (e: Exception) {
|
||||
throw ProjectBuildException(e)
|
||||
}
|
||||
}
|
||||
else {
|
||||
messageHandler.debug("Builder ${builder.presentableName} requested second chunk rebuild")
|
||||
}
|
||||
}
|
||||
|
||||
buildersPassed++
|
||||
for (target in chunk.targets) {
|
||||
buildProgress.updateProgress(target, (buildersPassed.toDouble()) / totalModuleLevelBuilderCount, context)
|
||||
}
|
||||
context.checkCanceled()
|
||||
if (buildResult == ModuleLevelBuilder.ExitCode.ADDITIONAL_PASS_REQUIRED) {
|
||||
nextPassRequired = true
|
||||
}
|
||||
else if (buildResult == ModuleLevelBuilder.ExitCode.CHUNK_REBUILD_REQUIRED) {
|
||||
if (!rebuildFromScratchRequested && !isCleanBuild) {
|
||||
notifyChunkRebuildRequested(context, chunk, builder)
|
||||
// allow rebuild from scratch only once per chunk
|
||||
rebuildFromScratchRequested = true
|
||||
// forcibly mark all files in the chunk dirty
|
||||
fsState.clearContextRoundData(context)
|
||||
FSOperations.markDirty(context, CompilationRound.NEXT, chunk, null)
|
||||
// reverting to the beginning
|
||||
nextPassRequired = true
|
||||
outputConsumer.clear()
|
||||
break
|
||||
}
|
||||
else {
|
||||
log.debug("Builder ${builder.presentableName} requested second chunk rebuild")
|
||||
}
|
||||
}
|
||||
finally {
|
||||
outputConsumer.setCurrentBuilderName(null)
|
||||
}
|
||||
|
||||
buildersPassed++
|
||||
}
|
||||
}
|
||||
finally {
|
||||
outputConsumer.setCurrentBuilderName(null)
|
||||
val moreToCompile = JavaBuilderUtil.updateMappingsOnRoundCompletion(context, dirtyFilesHolder, chunk)
|
||||
if (moreToCompile) {
|
||||
nextPassRequired = true
|
||||
@@ -384,10 +342,8 @@ internal class JpsProjectBuilder(
|
||||
saveInstrumentedClasses(outputConsumer)
|
||||
outputConsumer.fireFileGeneratedEvents()
|
||||
outputConsumer.clear()
|
||||
for (category in BuilderCategory.entries) {
|
||||
for (builder in builderRegistry.getBuilders(category)) {
|
||||
builder.chunkBuildFinished(context, chunk)
|
||||
}
|
||||
for (builder in builders) {
|
||||
builder.chunkBuildFinished(context, chunk)
|
||||
}
|
||||
if (Utils.errorsDetected(context)) {
|
||||
context.processMessage(CompilerMessage("", BuildMessage.Kind.JPS_INFO, "Errors occurred while compiling module ${chunk.presentableShortName}"))
|
||||
@@ -397,59 +353,59 @@ internal class JpsProjectBuilder(
|
||||
return doneSomething
|
||||
}
|
||||
|
||||
private fun ensureFsStateInitialized(context: CompileContext, target: BuildTarget<*>) {
|
||||
private fun initFsStateForCleanBuild(context: CompileContext, target: BuildTarget<*>) {
|
||||
val fsState = context.projectDescriptor.fsState
|
||||
if (isCleanBuild) {
|
||||
val targetRoots = (context.projectDescriptor.buildRootIndex as BazelBuildRootIndex).descriptors
|
||||
fsState.getDelta(target).clearRecompile(targetRoots)
|
||||
for (rootDescriptor in targetRoots) {
|
||||
// if it is a full project rebuild, all storages are already completely cleared;
|
||||
// so passing null as stampStorage because there is no need to access the storage to clear non-existing data
|
||||
fsState.markDirty(
|
||||
/* context = */ context,
|
||||
/* round = */ CompilationRound.CURRENT,
|
||||
/* file = */ rootDescriptor.file,
|
||||
/* buildRootDescriptor = */ rootDescriptor,
|
||||
/* stampStorage = */ null,
|
||||
/* saveEventStamp = */ false,
|
||||
)
|
||||
}
|
||||
FSOperations.addCompletelyMarkedDirtyTarget(context, target)
|
||||
fsState.markInitialScanPerformed(target)
|
||||
}
|
||||
else {
|
||||
require(!fsState.isInitialScanPerformed(target))
|
||||
initTargetFsStateForNonInitialBuild(context, target, messageHandler)
|
||||
val targetRoots = (context.projectDescriptor.buildRootIndex as BazelBuildRootIndex).descriptors
|
||||
fsState.getDelta(target).clearRecompile(targetRoots)
|
||||
for (rootDescriptor in targetRoots) {
|
||||
// if it is a full project rebuild, all storages are already completely cleared;
|
||||
// so passing null as stampStorage because there is no need to access the storage to clear non-existing data
|
||||
fsState.markDirty(
|
||||
/* context = */ context,
|
||||
/* round = */ CompilationRound.CURRENT,
|
||||
/* file = */ rootDescriptor.file,
|
||||
/* buildRootDescriptor = */ rootDescriptor,
|
||||
/* stampStorage = */ null,
|
||||
/* saveEventStamp = */ false,
|
||||
)
|
||||
}
|
||||
FSOperations.addCompletelyMarkedDirtyTarget(context, target)
|
||||
fsState.markInitialScanPerformed(target)
|
||||
}
|
||||
|
||||
private fun buildTargetChunk(context: CompileContext, buildProgress: BuildProgress, moduleTarget: BazelModuleBuildTarget) {
|
||||
val buildSpan = Tracer.start { "Building ${moduleTarget.presentableName}" }
|
||||
private fun buildTargetChunk(context: CompileContext, target: BazelModuleBuildTarget, builders: Array<ModuleLevelBuilder>) {
|
||||
val buildSpan = Tracer.start { "Building ${target.presentableName}" }
|
||||
val fsState = context.projectDescriptor.fsState
|
||||
var doneSomething: Boolean
|
||||
val targets = java.util.Set.of<BuildTarget<*>>(moduleTarget)
|
||||
val targets = java.util.Set.of<BuildTarget<*>>(target)
|
||||
try {
|
||||
context.setCompilationStartStamp(targets, System.currentTimeMillis())
|
||||
|
||||
sendBuildingTargetMessages(targets, BuildingTargetProgressMessage.Event.STARTED)
|
||||
Utils.ERRORS_DETECTED_KEY.set(context, false)
|
||||
|
||||
ensureFsStateInitialized(context = context, target = moduleTarget)
|
||||
val fsState = context.projectDescriptor.fsState
|
||||
if (isCleanBuild) {
|
||||
initFsStateForCleanBuild(context = context, target = target)
|
||||
}
|
||||
else {
|
||||
require(!fsState.isInitialScanPerformed(target))
|
||||
initTargetFsStateForNonInitialBuild(context = context, target = target, log = log, dataManager = dataManager)
|
||||
}
|
||||
|
||||
doneSomething = processDeletedPaths(context, moduleTarget)
|
||||
doneSomething = processDeletedPaths(context, target)
|
||||
|
||||
val chunk = BuildTargetChunk(targets)
|
||||
fsState.beforeChunkBuildStart(context, targets)
|
||||
|
||||
val runBuildersSpan = Tracer.start { "runBuilders " + moduleTarget.presentableName }
|
||||
doneSomething = doneSomething or runModuleLevelBuilders(context, moduleTarget, buildProgress)
|
||||
val runBuildersSpan = Tracer.start { "runBuilders " + target.presentableName }
|
||||
doneSomething = doneSomething or runModuleLevelBuilders(context, target, builders)
|
||||
runBuildersSpan.complete()
|
||||
|
||||
fsState.clearContextRoundData(context)
|
||||
fsState.clearContextChunk(context)
|
||||
|
||||
if (doneSomething) {
|
||||
BuildOperations.markTargetsUpToDate(context, chunk)
|
||||
BuildOperations.markTargetsUpToDate(context, targets)
|
||||
}
|
||||
}
|
||||
catch (e: BuildDataCorruptedException) {
|
||||
@@ -460,21 +416,20 @@ internal class JpsProjectBuilder(
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
val message = StringBuilder()
|
||||
message.append(moduleTarget.presentableName).append(": ").append(e.javaClass.getName())
|
||||
message.append(target.presentableName).append(": ").append(e.javaClass.getName())
|
||||
e.message?.let {
|
||||
message.append(": ").append(it)
|
||||
}
|
||||
throw ProjectBuildException(message.toString(), e)
|
||||
}
|
||||
finally {
|
||||
buildProgress.onTargetChunkFinished(targets, context)
|
||||
try {
|
||||
// restore deleted paths that were not processed by 'integrate'
|
||||
val map = Utils.REMOVED_SOURCES_KEY.get(context)
|
||||
if (map != null) {
|
||||
for (entry in map.entries) {
|
||||
for (path in entry.value) {
|
||||
fsState.registerDeleted(context, entry.key, Path.of(path), null)
|
||||
for (file in entry.value) {
|
||||
fsState.registerDeleted(context, entry.key, file, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -488,7 +443,7 @@ internal class JpsProjectBuilder(
|
||||
}
|
||||
|
||||
private fun sendBuildingTargetMessages(targets: Set<BuildTarget<*>>, event: BuildingTargetProgressMessage.Event) {
|
||||
messageHandler.processMessage(BuildingTargetProgressMessage(targets, event))
|
||||
log.processMessage(BuildingTargetProgressMessage(targets, event))
|
||||
}
|
||||
|
||||
private fun storeBuilderStatistics(builder: Builder, elapsedTime: Long, processedFiles: Int) {
|
||||
@@ -501,7 +456,7 @@ private class ChunkBuildOutputConsumerImpl(private val context: CompileContext)
|
||||
private val targetToConsumer = HashMap<BuildTarget<*>, BuildOutputConsumerImpl>()
|
||||
private val classes = HashMap<String, CompiledClass>()
|
||||
private val targetToClassesMap = HashMap<BuildTarget<*>, MutableCollection<CompiledClass>>()
|
||||
private val outputToBuilderNameMap = Object2ObjectMaps.synchronize(Object2ObjectOpenCustomHashMap<File, String>(FileHashStrategy))
|
||||
private val outputToBuilderNameMap = Collections.synchronizedMap(HashMap<File, String>())
|
||||
|
||||
@Volatile
|
||||
private var currentBuilderName: String? = null
|
||||
@@ -634,66 +589,74 @@ private fun isTargetOutputCleared(context: CompileContext, target: BuildTarget<*
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* if an output file is generated from multiple sources, make sure all of them are added for recompilation
|
||||
*/
|
||||
@Suppress("SpellCheckingInspection")
|
||||
private fun completeRecompiledSourcesSet(context: CompileContext, moduleBuildTarget: BazelModuleBuildTarget) {
|
||||
|
||||
private inline fun processFilesToRecompile(
|
||||
context: CompileContext,
|
||||
target: BazelModuleBuildTarget,
|
||||
fsState: BuildFSState,
|
||||
processor: (Path, JavaSourceRootDescriptor) -> Boolean,
|
||||
): Boolean {
|
||||
val scope = context.scope
|
||||
if (scope.isBuildForced(moduleBuildTarget)) {
|
||||
// assuming build is either forced for all targets in a chunk or for none of them
|
||||
return
|
||||
}
|
||||
|
||||
val projectDescriptor = context.projectDescriptor
|
||||
val affectedOutputs = HashSet<String>()
|
||||
val affectedSources = HashSet<String>()
|
||||
|
||||
val mappings = ArrayList<SourceToOutputMapping>()
|
||||
projectDescriptor.fsState.processFilesToRecompile(context, moduleBuildTarget, object : FileProcessor<JavaSourceRootDescriptor, BazelModuleBuildTarget> {
|
||||
private var srcToOut: SourceToOutputMapping? = null
|
||||
|
||||
override fun apply(target: BazelModuleBuildTarget, file: File, root: JavaSourceRootDescriptor): Boolean {
|
||||
val src = file.invariantSeparatorsPath
|
||||
if (!affectedSources.add(src)) {
|
||||
return true
|
||||
}
|
||||
|
||||
// lazy init
|
||||
var srcToOut = this.srcToOut
|
||||
if (srcToOut == null) {
|
||||
srcToOut = projectDescriptor.dataManager.getSourceToOutputMap(target)
|
||||
mappings.add(srcToOut)
|
||||
this.srcToOut = srcToOut
|
||||
}
|
||||
|
||||
val outs = srcToOut.getOutputs(src) ?: return true
|
||||
// Temporary hack for KTIJ-197
|
||||
// Change of only one input of *.kotlin_module files didn't trigger recompilation of all inputs in old behavior.
|
||||
// Now it does. It isn't yet obvious whether it is right or wrong behavior. Let's leave old behavior for a
|
||||
// while for safety and keeping kotlin incremental JPS tests green
|
||||
outs.filterTo(affectedOutputs) { "kotlin_module" != it.substringAfterLast('.') }
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
if (affectedOutputs.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
for (srcToOut in mappings) {
|
||||
val cursor = srcToOut.cursor()
|
||||
while (cursor.hasNext()) {
|
||||
val src = cursor.next()
|
||||
if (!affectedSources.contains(src)) {
|
||||
for (out in cursor.outputPaths) {
|
||||
if (affectedOutputs.contains(out)) {
|
||||
FSOperations.markDirtyIfNotDeleted(context, CompilationRound.CURRENT, Path.of(src))
|
||||
break
|
||||
}
|
||||
val delta = fsState.getEffectiveFilesDelta(context, target)
|
||||
delta.lockData()
|
||||
try {
|
||||
for (entry in delta.sourceMapToRecompile.entries) {
|
||||
val root = entry.key as JavaSourceRootDescriptor
|
||||
for (file in entry.value) {
|
||||
if (!scope.isAffected(target, file)) {
|
||||
continue
|
||||
}
|
||||
if (!processor(file, root)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
finally {
|
||||
delta.unlockData()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* if an output file is generated from multiple sources, make sure all of them are added for recompilation
|
||||
*/
|
||||
private fun completeRecompiledSourcesSet(context: CompileContext, target: BazelModuleBuildTarget) {
|
||||
val projectDescriptor = context.projectDescriptor
|
||||
val affected = mutableListOf<List<String>>()
|
||||
val affectedSources = HashSet<Path>()
|
||||
|
||||
val sourceToOut = projectDescriptor.dataManager.getSourceToOutputMap(target) as BazelSourceToOutputMapping
|
||||
processFilesToRecompile(context = context, target = target, fsState = projectDescriptor.fsState) { file, root ->
|
||||
if (!affectedSources.add(file)) {
|
||||
sourceToOut.getDescriptor(file)?.outputs?.let {
|
||||
affected.add(it)
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
if (affected.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
// one output can be produced by different sources, so, we find intersection by outputs
|
||||
val affectedSourceFiles = sourceToOut.findAffectedSources(affected)
|
||||
if (affectedSourceFiles.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
val fileToDescriptors = (context.projectDescriptor.buildRootIndex as BazelBuildRootIndex).fileToDescriptors
|
||||
val stampStorage = projectDescriptor.dataManager.getFileStampStorage(target)
|
||||
for (file in affectedSourceFiles) {
|
||||
val rootDescriptor = fileToDescriptors.get(file) ?: continue
|
||||
context.projectDescriptor.fsState.markDirtyIfNotDeleted(
|
||||
context,
|
||||
CompilationRound.CURRENT,
|
||||
file,
|
||||
rootDescriptor,
|
||||
stampStorage
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,18 +2,21 @@
|
||||
|
||||
package org.jetbrains.bazel.jvm.jps.impl
|
||||
|
||||
import org.jetbrains.bazel.jvm.jps.ConsoleMessageHandler
|
||||
import org.jetbrains.bazel.jvm.jps.RequestLog
|
||||
import org.jetbrains.jps.builders.BuildTarget
|
||||
import org.jetbrains.jps.incremental.CompileContext
|
||||
import org.jetbrains.jps.incremental.FSOperations
|
||||
import org.jetbrains.jps.incremental.fs.BuildFSState
|
||||
import org.jetbrains.jps.incremental.fs.FilesDelta
|
||||
import org.jetbrains.jps.incremental.storage.RelativePathType
|
||||
import org.jetbrains.jps.incremental.storage.StampsStorage
|
||||
|
||||
internal fun initTargetFsStateForNonInitialBuild(context: CompileContext, target: BuildTarget<*>, messageHandler: ConsoleMessageHandler) {
|
||||
internal fun initTargetFsStateForNonInitialBuild(
|
||||
context: CompileContext,
|
||||
target: BuildTarget<*>,
|
||||
log: RequestLog,
|
||||
dataManager: BazelBuildDataProvider,
|
||||
) {
|
||||
val projectDescriptor = context.projectDescriptor
|
||||
val dataManager = projectDescriptor.dataManager
|
||||
val buildRootIndex = projectDescriptor.buildRootIndex as BazelBuildRootIndex
|
||||
val fsState = projectDescriptor.fsState
|
||||
|
||||
@@ -21,7 +24,7 @@ internal fun initTargetFsStateForNonInitialBuild(context: CompileContext, target
|
||||
val nextDelta = context.getUserData(BuildFSState.NEXT_ROUND_DELTA_KEY)
|
||||
val filesDelta = fsState.getDelta(target)
|
||||
|
||||
val stampStorage = dataManager.getFileStampStorage(target)!!
|
||||
val stampStorage = dataManager.getFileStampStorage(target)
|
||||
markDirtyFiles(
|
||||
context = context,
|
||||
target = target,
|
||||
@@ -29,19 +32,13 @@ internal fun initTargetFsStateForNonInitialBuild(context: CompileContext, target
|
||||
buildRootIndex = buildRootIndex,
|
||||
fsState = fsState,
|
||||
filesDelta = filesDelta,
|
||||
messageHandler = messageHandler,
|
||||
messageHandler = log,
|
||||
)
|
||||
|
||||
val fileToDescriptors = buildRootIndex.fileToDescriptors
|
||||
|
||||
// handle deleted paths
|
||||
val sourceToOutputMap = dataManager.getSourceToOutputMap(target)
|
||||
|
||||
for (file in sourceToOutputMap.sourceFileIterator) {
|
||||
if (fileToDescriptors.contains(file)) {
|
||||
continue
|
||||
}
|
||||
|
||||
for (file in dataManager.sourceToOutputMapping.findDeletedAndUnsetDigest(fileToDescriptors)) {
|
||||
currentDelta?.addDeleted(file)
|
||||
nextDelta?.addDeleted(file)
|
||||
filesDelta.addDeleted(file)
|
||||
@@ -53,18 +50,18 @@ internal fun initTargetFsStateForNonInitialBuild(context: CompileContext, target
|
||||
private fun markDirtyFiles(
|
||||
context: CompileContext,
|
||||
target: BuildTarget<*>,
|
||||
stampStorage: StampsStorage<*>,
|
||||
stampStorage: BazelStampStorage,
|
||||
buildRootIndex: BazelBuildRootIndex,
|
||||
fsState: BuildFSState,
|
||||
filesDelta: FilesDelta,
|
||||
messageHandler: ConsoleMessageHandler,
|
||||
messageHandler: RequestLog,
|
||||
) {
|
||||
var completelyMarkedDirty = true
|
||||
for (rootDescriptor in buildRootIndex.descriptors) {
|
||||
fsState.clearRecompile(rootDescriptor)
|
||||
|
||||
val file = rootDescriptor.file
|
||||
val markDirty = stampStorage.getCurrentStampIfUpToDate(file, rootDescriptor.target, null) == null
|
||||
val markDirty = stampStorage.isDirty(file)
|
||||
if (!markDirty) {
|
||||
completelyMarkedDirty = false
|
||||
continue
|
||||
|
||||
@@ -30,6 +30,7 @@ internal fun loadJpsProject(
|
||||
jpsModel: JpsModel,
|
||||
moduleTarget: BazelModuleBuildTarget,
|
||||
relativizer: PathRelativizerService,
|
||||
buildDataProvider: BazelBuildDataProvider,
|
||||
): ProjectDescriptor {
|
||||
val dataPaths = BuildDataPathsImpl(dataStorageRoot)
|
||||
val dataManager = BuildDataManager.createSingleDb(
|
||||
@@ -37,7 +38,7 @@ internal fun loadJpsProject(
|
||||
/* targetStateManager = */ BazelBuildTargetStateManager(loadTargetState(storageManager)),
|
||||
/* relativizer = */ relativizer,
|
||||
/* versionManager = */ NoopBuildDataVersionManager,
|
||||
/* storageManager = */ storageManager,
|
||||
/* buildDataProvider = */ buildDataProvider,
|
||||
)
|
||||
return ProjectDescriptor(
|
||||
/* model = */ jpsModel,
|
||||
|
||||
@@ -27,7 +27,7 @@ internal fun createPathRelativizer(baseDir: Path, classOutDir: Path): PathRelati
|
||||
return when {
|
||||
p.startsWith(baseDirPrefix) -> p.substring(baseDirPrefix.length)
|
||||
p.startsWith(parentOfBaseDirPrefix) -> "../" + p.substring(parentOfBaseDirPrefix.length)
|
||||
else -> error("Unexpected path: $p")
|
||||
else -> error("Unexpected path: $p (baseDirPrefix=$baseDirPrefix, parentOfBaseDirPrefix=$parentOfBaseDirPrefix)")
|
||||
}
|
||||
}
|
||||
RelativePathType.OUTPUT -> {
|
||||
|
||||
@@ -15,6 +15,7 @@ kt_jvm_library(
|
||||
"//zip:build-zip",
|
||||
"//src/jps-builder:jps-standalone",
|
||||
"//:kotlin-metadata",
|
||||
"//src/abi"
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
@@ -7,7 +7,7 @@ import org.jetbrains.jps.incremental.MessageHandler
|
||||
import org.jetbrains.jps.incremental.messages.BuildMessage
|
||||
import org.jetbrains.jps.incremental.messages.CompilerMessage
|
||||
|
||||
class ConsoleMessageHandler(
|
||||
class RequestLog(
|
||||
@PublishedApi @JvmField internal val out: Appendable,
|
||||
@JvmField val isDebugEnabled: Boolean,
|
||||
) : MessageHandler {
|
||||
@@ -26,6 +26,10 @@ class ConsoleMessageHandler(
|
||||
out.appendLine("ERROR: $message")
|
||||
}
|
||||
|
||||
fun error(message: String, error: Throwable) {
|
||||
out.appendLine("ERROR: $message\n${error.stackTraceToString().prependIndent(" ")}")
|
||||
}
|
||||
|
||||
fun info(message: String) {
|
||||
out.appendLine("INFO: $message")
|
||||
}
|
||||
@@ -6,33 +6,35 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.bazel.jvm.abi.writeAbi
|
||||
import org.jetbrains.intellij.build.io.*
|
||||
import org.jetbrains.jps.incremental.storage.ExperimentalSourceToOutputMapping
|
||||
import org.jetbrains.org.objectweb.asm.ClassReader
|
||||
import org.jetbrains.org.objectweb.asm.ClassWriter
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.channels.FileChannel
|
||||
import java.nio.file.*
|
||||
import java.nio.file.attribute.DosFileAttributeView
|
||||
import java.nio.file.attribute.PosixFileAttributeView
|
||||
import java.nio.file.attribute.PosixFilePermission
|
||||
import java.util.zip.ZipEntry
|
||||
import java.nio.file.NoSuchFileException
|
||||
import java.nio.file.Path
|
||||
|
||||
class SourceDescriptor(
|
||||
// absolute and normalized
|
||||
@JvmField var sourceFile: Path,
|
||||
@JvmField var digest: ByteArray? = null,
|
||||
@JvmField var outputs: List<String>? = null,
|
||||
) {
|
||||
//fun isEmpty(): Boolean = digest == null && outputs.isNullOrEmpty()
|
||||
}
|
||||
|
||||
suspend fun packageToJar(
|
||||
outJar: Path,
|
||||
abiJar: Path?,
|
||||
sourceToOutputMap: ExperimentalSourceToOutputMapping,
|
||||
sourceDescriptors: Array<SourceDescriptor>,
|
||||
classOutDir: Path,
|
||||
messageHandler: ConsoleMessageHandler
|
||||
log: RequestLog
|
||||
) {
|
||||
if (abiJar == null) {
|
||||
withContext(Dispatchers.IO) {
|
||||
createJar(
|
||||
outJar = outJar,
|
||||
sourceToOutputMap = sourceToOutputMap,
|
||||
sourceDescriptors = sourceDescriptors,
|
||||
classOutDir = classOutDir,
|
||||
abiChannel = null,
|
||||
messageHandler = messageHandler,
|
||||
messageHandler = log,
|
||||
)
|
||||
}
|
||||
return
|
||||
@@ -43,132 +45,59 @@ suspend fun packageToJar(
|
||||
launch {
|
||||
createJar(
|
||||
outJar = outJar,
|
||||
sourceToOutputMap = sourceToOutputMap,
|
||||
sourceDescriptors = sourceDescriptors,
|
||||
classOutDir = classOutDir,
|
||||
abiChannel = classChannel,
|
||||
messageHandler = messageHandler,
|
||||
messageHandler = log,
|
||||
)
|
||||
classChannel.close()
|
||||
}
|
||||
|
||||
writeZipUsingTempFile(abiJar, indexWriter = null) { stream ->
|
||||
val classesToBeDeleted = HashSet<String>()
|
||||
for ((name, classData) in classChannel) {
|
||||
val classWriter = ClassWriter(0)
|
||||
val abiClassVisitor = AbiClassVisitor(classVisitor = classWriter, classesToBeDeleted = classesToBeDeleted)
|
||||
ClassReader(classData).accept(abiClassVisitor, 0)
|
||||
if (!abiClassVisitor.isApiClass) {
|
||||
continue
|
||||
}
|
||||
|
||||
val abiData = classWriter.toByteArray()
|
||||
stream.writeDataRawEntry(ByteBuffer.wrap(abiData), name, abiData.size, abiData.size, ZipEntry.STORED, 0)
|
||||
}
|
||||
|
||||
if (classesToBeDeleted.isNotEmpty()) {
|
||||
messageHandler.debug("Non-abi classes to be deleted: ${classesToBeDeleted.size}")
|
||||
}
|
||||
}
|
||||
writeAbi(abiJar, classChannel)
|
||||
//if (classesToBeDeleted.isNotEmpty()) {
|
||||
// messageHandler.debug("Non-abi classes to be deleted: ${classesToBeDeleted.size}")
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun createJar(
|
||||
outJar: Path,
|
||||
sourceToOutputMap: ExperimentalSourceToOutputMapping,
|
||||
sourceDescriptors: Array<SourceDescriptor>,
|
||||
classOutDir: Path,
|
||||
abiChannel: Channel<Pair<ByteArray, ByteArray>>?,
|
||||
messageHandler: ConsoleMessageHandler,
|
||||
messageHandler: RequestLog,
|
||||
) {
|
||||
val packageIndexBuilder = PackageIndexBuilder()
|
||||
writeZipUsingTempFile(outJar, packageIndexBuilder.indexWriter) { stream ->
|
||||
// MVStore like a TreeMap, keys already sorted
|
||||
//val all = sourceToOutputMap.outputs().toList()
|
||||
//val unique = LinkedHashSet(all)
|
||||
//if (unique.size != all.size) {
|
||||
// messageHandler.out.appendLine("Duplicated outputs: ${all.groupingBy { it }
|
||||
// .eachCount()
|
||||
// .filter { it.value > 1 }
|
||||
// .keys
|
||||
// }")
|
||||
//}
|
||||
// output file maybe associated with more than one output file
|
||||
val uniqueGuard = HashSet<String>(sourceDescriptors.size + 10)
|
||||
|
||||
for (path in sourceToOutputMap.outputs().toList()) {
|
||||
// duplicated - ignore it
|
||||
if (path.endsWith(".kotlin_module")) {
|
||||
continue
|
||||
}
|
||||
for (sourceDescriptor in sourceDescriptors) {
|
||||
for (path in sourceDescriptor.outputs ?: continue) {
|
||||
// duplicated - ignore it
|
||||
if (!uniqueGuard.add(path)) {
|
||||
continue
|
||||
}
|
||||
|
||||
packageIndexBuilder.addFile(name = path, addClassDir = false)
|
||||
try {
|
||||
val file = classOutDir.resolve(path)
|
||||
if (abiChannel != null && path.endsWith(".class")) {
|
||||
val name = path.toByteArray()
|
||||
val classData = stream.fileAndGetData(name, file)
|
||||
abiChannel.send(name to classData)
|
||||
packageIndexBuilder.addFile(name = path, addClassDir = false)
|
||||
try {
|
||||
val file = classOutDir.resolve(path)
|
||||
if (abiChannel != null && path.endsWith(".class")) {
|
||||
val name = path.toByteArray()
|
||||
val classData = stream.fileAndGetData(name, file)
|
||||
abiChannel.send(name to classData)
|
||||
}
|
||||
else {
|
||||
stream.file(nameString = path, file = file)
|
||||
}
|
||||
}
|
||||
else {
|
||||
stream.file(nameString = path, file = file)
|
||||
catch (_: NoSuchFileException) {
|
||||
messageHandler.warn("output file exists in src-to-output mapping, but not found on disk: $path (classOutDir=$classOutDir)")
|
||||
}
|
||||
}
|
||||
catch (_: NoSuchFileException) {
|
||||
messageHandler.warn("output file exists in src-to-output mapping, but not found on disk: $path (classOutDir=$classOutDir)")
|
||||
}
|
||||
}
|
||||
packageIndexBuilder.writePackageIndex(stream = stream, addDirEntriesMode = AddDirEntriesMode.RESOURCE_ONLY)
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun writeZipUsingTempFile(file: Path, indexWriter: IkvIndexBuilder?, task: (ZipArchiveOutputStream) -> Unit) {
|
||||
val tempFile = Files.createTempFile(file.parent, file.fileName.toString(), ".tmp")
|
||||
var moved = false
|
||||
try {
|
||||
ZipArchiveOutputStream(
|
||||
channel = FileChannel.open(tempFile, WRITE),
|
||||
zipIndexWriter = ZipIndexWriter(indexWriter),
|
||||
).use {
|
||||
task(it)
|
||||
}
|
||||
|
||||
try {
|
||||
moveAtomic(tempFile, file)
|
||||
}
|
||||
catch (e: AccessDeniedException) {
|
||||
makeFileWritable(file, e)
|
||||
moveAtomic(tempFile, file)
|
||||
}
|
||||
moved = true
|
||||
}
|
||||
finally {
|
||||
if (!moved) {
|
||||
Files.deleteIfExists(tempFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun moveAtomic(from: Path, to: Path) {
|
||||
try {
|
||||
Files.move(from, to, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE)
|
||||
}
|
||||
catch (_: AtomicMoveNotSupportedException) {
|
||||
Files.move(from, to, StandardCopyOption.REPLACE_EXISTING)
|
||||
}
|
||||
}
|
||||
|
||||
private fun makeFileWritable(file: Path, cause: Throwable) {
|
||||
val posixView = Files.getFileAttributeView<PosixFileAttributeView?>(file, PosixFileAttributeView::class.java)
|
||||
if (posixView != null) {
|
||||
val permissions = posixView.readAttributes().permissions()
|
||||
permissions.add(PosixFilePermission.OWNER_WRITE)
|
||||
posixView.setPermissions(permissions)
|
||||
}
|
||||
|
||||
val dosView = Files.getFileAttributeView<DosFileAttributeView?>(file, DosFileAttributeView::class.java)
|
||||
@Suppress("IfThenToSafeAccess")
|
||||
if (dosView != null) {
|
||||
dosView.setReadOnly(false)
|
||||
}
|
||||
|
||||
throw UnsupportedOperationException("Unable to modify file attributes. Unsupported platform.", cause)
|
||||
}
|
||||
|
||||
|
||||
|
||||
16
build/jvm-rules/src/jvm-args.bzl
Normal file
16
build/jvm-rules/src/jvm-args.bzl
Normal file
@@ -0,0 +1,16 @@
|
||||
def get_jvm_flags(flags):
|
||||
return [
|
||||
# "-XX:+UseZGC",
|
||||
# "-XX:+ZGenerational",
|
||||
"-Xms2g",
|
||||
"-Xmx8g",
|
||||
"-XX:ReservedCodeCacheSize=512m",
|
||||
"-Djava.awt.headless=true",
|
||||
"-Dapple.awt.UIElement=true",
|
||||
"-Didea.io.use.nio2=true",
|
||||
"--add-opens=java.base/java.util.concurrent=ALL-UNNAMED",
|
||||
"--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED",
|
||||
"--add-opens=java.base/java.util.concurrent.locks=ALL-UNNAMED",
|
||||
"--add-opens=java.base/java.nio=ALL-UNNAMED",
|
||||
"-Dkotlin.environment.keepalive=true",
|
||||
] + flags
|
||||
@@ -1,6 +1,7 @@
|
||||
load("@rules_java//java:defs.bzl", "java_binary")
|
||||
load("@rules_jvm//:jvm.bzl", "jvm_import")
|
||||
load("@rules_kotlin//kotlin:jvm.bzl", "kt_jvm_library")
|
||||
load("//:src/jvm-args.bzl", "get_jvm_flags")
|
||||
|
||||
kt_jvm_library(
|
||||
name = "worker-lib",
|
||||
@@ -24,19 +25,19 @@ kt_jvm_library(
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
|
||||
|
||||
java_binary(
|
||||
name = "worker-jvm",
|
||||
runtime_deps = [":worker-lib"],
|
||||
main_class = "org.jetbrains.bazel.jvm.kotlin.KotlinBuildWorker",
|
||||
jvm_flags = [
|
||||
"-Xms1000m",
|
||||
"-Xmx6000m",
|
||||
"-Djava.awt.headless=true",
|
||||
"-Dapple.awt.UIElement=true",
|
||||
"-Dkotlin.environment.keepalive=true",
|
||||
# Kotlin Compiler sets it
|
||||
"-Didea.io.use.nio2=true",
|
||||
"-Dzip.handler.uses.crc.instead.of.timestamp=true",
|
||||
],
|
||||
jvm_flags = get_jvm_flags([]),
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
java_binary(
|
||||
name = "test-worker",
|
||||
runtime_deps = [":worker-lib"],
|
||||
main_class = "org.jetbrains.bazel.jvm.kotlin.TestKotlinBuildWorker",
|
||||
jvm_flags = get_jvm_flags([]),
|
||||
)
|
||||
|
||||
@@ -30,7 +30,6 @@ import java.util.*
|
||||
import java.util.jar.Attributes
|
||||
import java.util.jar.JarFile
|
||||
import java.util.jar.Manifest
|
||||
import java.util.zip.ZipEntry
|
||||
|
||||
private val MANIFEST_NAME_BYTES = JarFile.MANIFEST_NAME.toByteArray()
|
||||
|
||||
@@ -121,15 +120,7 @@ class JarCreator(
|
||||
|
||||
val content = manifestContentImpl(existingFile = manifestFile)
|
||||
|
||||
val size = content.size
|
||||
out.writeDataRawEntry(
|
||||
data = ByteBuffer.wrap(content),
|
||||
name = MANIFEST_NAME_BYTES,
|
||||
size = size,
|
||||
compressedSize = size,
|
||||
method = ZipEntry.STORED,
|
||||
crc = 0,
|
||||
)
|
||||
out.writeDataRawEntryWithoutCrc(data = ByteBuffer.wrap(content), name = MANIFEST_NAME_BYTES)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
|
||||
@@ -25,7 +25,7 @@ object KotlinBuildWorker : WorkRequestExecutor {
|
||||
|
||||
// Important issues:
|
||||
// https://youtrack.jetbrains.com/issue/KT-71680/Report-a-warning-when-Serializable-public-class-has-private-serializer
|
||||
private suspend fun buildKotlin(
|
||||
internal suspend fun buildKotlin(
|
||||
workingDir: Path,
|
||||
out: Writer,
|
||||
args: ArgMap<JvmBuilderFlags>,
|
||||
@@ -42,7 +42,7 @@ private suspend fun buildKotlin(
|
||||
Platform.JVM -> {
|
||||
compileContext.execute("compile classes") {
|
||||
val code = compileContext.execute("kotlinc") {
|
||||
compileKotlinForJvm(args = args, context = compileContext, sources = sources, out = out, workingDir = workingDir, info = info)
|
||||
compileKotlinForJvm(args = args, context = compileContext, sources = sources, out = out, baseDir = workingDir, info = info)
|
||||
}
|
||||
if (code != 0) {
|
||||
return code
|
||||
@@ -56,23 +56,21 @@ private suspend fun buildKotlin(
|
||||
return 0
|
||||
}
|
||||
|
||||
private fun createBuildInfo(argMap: ArgMap<JvmBuilderFlags>): CompilationTaskInfo {
|
||||
val ruleKind = argMap.mandatorySingle(JvmBuilderFlags.RULE_KIND).split('_')
|
||||
private fun createBuildInfo(args: ArgMap<JvmBuilderFlags>): CompilationTaskInfo {
|
||||
val ruleKind = args.mandatorySingle(JvmBuilderFlags.RULE_KIND).split('_')
|
||||
check(ruleKind.size == 3 && ruleKind[0] == "kt") {
|
||||
"invalid rule kind $ruleKind"
|
||||
}
|
||||
|
||||
return CompilationTaskInfo(
|
||||
label = argMap.mandatorySingle(JvmBuilderFlags.TARGET_LABEL),
|
||||
label = args.mandatorySingle(JvmBuilderFlags.TARGET_LABEL),
|
||||
ruleKind = checkNotNull(RuleKind.valueOf(ruleKind[2].uppercase())) {
|
||||
"unrecognized rule kind ${ruleKind[2]}"
|
||||
},
|
||||
platform = checkNotNull(Platform.valueOf(ruleKind[1].uppercase())) {
|
||||
"unrecognized platform ${ruleKind[1]}"
|
||||
},
|
||||
moduleName = argMap.mandatorySingle(JvmBuilderFlags.KOTLIN_MODULE_NAME).also {
|
||||
check(it.isNotBlank()) { "--kotlin_module_name should not be blank" }
|
||||
},
|
||||
moduleName = args.mandatorySingle(JvmBuilderFlags.KOTLIN_MODULE_NAME),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -4,18 +4,27 @@ package org.jetbrains.bazel.jvm.kotlin
|
||||
import com.google.devtools.build.lib.view.proto.Deps
|
||||
import com.google.devtools.build.lib.view.proto.Deps.Dependencies
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.psi.PsiJavaModule.MODULE_INFO_FILE
|
||||
import kotlinx.coroutines.ensureActive
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
|
||||
import org.jetbrains.kotlin.cli.common.messages.*
|
||||
import org.jetbrains.kotlin.cli.common.modules.ModuleBuilder
|
||||
import org.jetbrains.kotlin.cli.common.setupCommonArguments
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.configurePlugins
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.k2jvm
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.loadPlugins
|
||||
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
|
||||
import org.jetbrains.kotlin.cli.jvm.config.JvmModulePathRoot
|
||||
import org.jetbrains.kotlin.cli.jvm.config.addJavaSourceRoot
|
||||
import org.jetbrains.kotlin.cli.jvm.setupJvmSpecificArguments
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.messageCollector
|
||||
import org.jetbrains.kotlin.metadata.deserialization.MetadataVersion
|
||||
import org.jetbrains.kotlin.modules.JavaRootPath
|
||||
import java.io.BufferedInputStream
|
||||
import java.io.File
|
||||
import java.io.Writer
|
||||
@@ -28,18 +37,21 @@ internal suspend fun compileKotlinForJvm(
|
||||
context: TraceHelper,
|
||||
sources: List<Path>,
|
||||
out: Writer,
|
||||
workingDir: Path,
|
||||
baseDir: Path,
|
||||
info: CompilationTaskInfo,
|
||||
): Int {
|
||||
val kotlinArgs = K2JVMCompilerArguments()
|
||||
configureCommonCompilerArgs(kotlinArgs, args, workingDir)
|
||||
configureCommonCompilerArgs(kotlinArgs, args, baseDir)
|
||||
|
||||
kotlinArgs.classpath = createClasspath(args, workingDir)
|
||||
val classPath = createClasspath(args, baseDir)
|
||||
kotlinArgs.classpath = classPath.joinToString(File.pathSeparator) { it.toString() }
|
||||
|
||||
kotlinArgs.moduleName = info.moduleName
|
||||
kotlinArgs.destination = workingDir.resolve(args.mandatorySingle(JvmBuilderFlags.OUT)).toString()
|
||||
val outFile = baseDir.resolve(args.mandatorySingle(JvmBuilderFlags.OUT))
|
||||
val outFilePath = outFile.toString()
|
||||
kotlinArgs.destination = outFilePath
|
||||
|
||||
val pluginConfigurations = configurePlugins(args = args, workingDir = workingDir, label = info.label)
|
||||
val pluginConfigurations = configurePlugins(args = args, workingDir = baseDir, label = info.label)
|
||||
|
||||
fun printOptions() {
|
||||
wrapOutput(out, info.label, classifier = "K2JVM Compiler Arguments") {
|
||||
@@ -67,12 +79,63 @@ internal suspend fun compileKotlinForJvm(
|
||||
config.put(CLIConfigurationKeys.ALLOW_KOTLIN_PACKAGE, true)
|
||||
}
|
||||
|
||||
config.put(JVMConfigurationKeys.OUTPUT_JAR, outFile.toFile())
|
||||
|
||||
coroutineContext.ensureActive()
|
||||
|
||||
val rootDisposable = Disposer.newDisposable("Disposable for Bazel Kotlin Compiler")
|
||||
var code = try {
|
||||
loadPlugins(configuration = config, pluginConfigurations = pluginConfigurations)
|
||||
k2jvm(args = kotlinArgs, config = config, rootDisposable = rootDisposable).code
|
||||
|
||||
val moduleName = info.moduleName
|
||||
config.put(CommonConfigurationKeys.MODULE_NAME, moduleName)
|
||||
|
||||
val module = ModuleBuilder(moduleName, outFilePath, "java-production")
|
||||
|
||||
args.optional(JvmBuilderFlags.FRIENDS)?.let { value ->
|
||||
for (path in value) {
|
||||
module.addFriendDir(baseDir.resolve(path).normalize().toString())
|
||||
}
|
||||
}
|
||||
|
||||
var isJava9Module = false
|
||||
|
||||
val moduleInfoNameSuffix = File.separatorChar + MODULE_INFO_FILE
|
||||
for (source in sources) {
|
||||
val path = source.toString()
|
||||
if (path.endsWith(".java")) {
|
||||
module.addJavaSourceRoot(JavaRootPath(path, null))
|
||||
config.addJavaSourceRoot(source.toFile(), null)
|
||||
if (!isJava9Module) {
|
||||
isJava9Module = path.endsWith(moduleInfoNameSuffix)
|
||||
}
|
||||
}
|
||||
else {
|
||||
module.addSourceFiles(path)
|
||||
config.addKotlinSourceRoot(path = path, isCommon = false, hmppModuleName = null)
|
||||
}
|
||||
}
|
||||
|
||||
for (path in classPath) {
|
||||
module.addClasspathEntry(path.toString())
|
||||
}
|
||||
|
||||
for (file in classPath) {
|
||||
val ioFile = file.toFile()
|
||||
if (isJava9Module) {
|
||||
config.add(CLIConfigurationKeys.CONTENT_ROOTS, JvmModulePathRoot(ioFile))
|
||||
}
|
||||
config.add(CLIConfigurationKeys.CONTENT_ROOTS, JvmClasspathRoot(ioFile))
|
||||
}
|
||||
|
||||
config.addAll(JVMConfigurationKeys.MODULES, listOf(module))
|
||||
|
||||
k2jvm(
|
||||
config = config,
|
||||
rootDisposable = rootDisposable,
|
||||
module = module,
|
||||
messageCollector = messageCollector,
|
||||
).code
|
||||
}
|
||||
finally {
|
||||
Disposer.dispose(rootDisposable)
|
||||
@@ -92,7 +155,7 @@ internal suspend fun compileKotlinForJvm(
|
||||
|
||||
val renderer = object : PlainTextMessageRenderer(/* colorEnabled = */ true) {
|
||||
override fun getPath(location: CompilerMessageSourceLocation): String {
|
||||
return workingDir.relativize(Path.of(location.path)).toString()
|
||||
return baseDir.relativize(Path.of(location.path)).toString()
|
||||
}
|
||||
|
||||
override fun getName(): String = "RelativePath"
|
||||
@@ -111,14 +174,14 @@ private inline fun wrapOutput(out: Writer, label: String, classifier: String, ta
|
||||
out.appendLine("\u001B[1m=============== END of $classifier ($label) ===============\u001B[0m")
|
||||
}
|
||||
|
||||
private fun createClasspath(args: ArgMap<JvmBuilderFlags>, baseDir: Path): String {
|
||||
private fun createClasspath(args: ArgMap<JvmBuilderFlags>, baseDir: Path): List<Path> {
|
||||
if (!args.boolFlag(JvmBuilderFlags.REDUCED_CLASSPATH_MODE)) {
|
||||
return args.mandatory(JvmBuilderFlags.CLASSPATH).joinToString(File.pathSeparator) { baseDir.resolve(it).normalize().toString() }
|
||||
return args.mandatory(JvmBuilderFlags.CLASSPATH).map { baseDir.resolve(it).normalize() }
|
||||
}
|
||||
|
||||
val directDependencies = args.mandatory(JvmBuilderFlags.DIRECT_DEPENDENCIES)
|
||||
|
||||
val depsArtifacts = args.optional(JvmBuilderFlags.DEPS_ARTIFACTS) ?: return directDependencies.joinToString(File.pathSeparator)
|
||||
val depsArtifacts = args.optional(JvmBuilderFlags.DEPS_ARTIFACTS) ?: return directDependencies.map { baseDir.resolve(it).normalize() }
|
||||
val transitiveDepsForCompile = LinkedHashSet<String>()
|
||||
for (jdepsPath in depsArtifacts) {
|
||||
BufferedInputStream(Files.newInputStream(Path.of(jdepsPath))).use {
|
||||
@@ -131,7 +194,7 @@ private fun createClasspath(args: ArgMap<JvmBuilderFlags>, baseDir: Path): Strin
|
||||
}
|
||||
}
|
||||
|
||||
return (directDependencies.asSequence() + transitiveDepsForCompile).joinToString(File.pathSeparator)
|
||||
return (directDependencies.asSequence() + transitiveDepsForCompile).map { baseDir.resolve(it).normalize() }.toList()
|
||||
}
|
||||
|
||||
private data class LogMessage(
|
||||
|
||||
28
build/jvm-rules/src/kotlin-builder/TestKotlinBuildWorker.kt
Normal file
28
build/jvm-rules/src/kotlin-builder/TestKotlinBuildWorker.kt
Normal file
@@ -0,0 +1,28 @@
|
||||
package org.jetbrains.bazel.jvm.kotlin
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.jetbrains.bazel.jvm.TestModules
|
||||
import org.jetbrains.bazel.jvm.collectSources
|
||||
import org.jetbrains.bazel.jvm.getTestWorkerPaths
|
||||
import org.jetbrains.bazel.jvm.performTestInvocation
|
||||
import kotlin.io.path.ExperimentalPathApi
|
||||
|
||||
internal object TestKotlinBuildWorker {
|
||||
@OptIn(ExperimentalPathApi::class)
|
||||
@JvmStatic
|
||||
fun main(startupArgs: Array<String>) {
|
||||
val testPaths = getTestWorkerPaths()
|
||||
val baseDir = testPaths.baseDir
|
||||
runBlocking(Dispatchers.Default) {
|
||||
val testModule = TestModules.PLATFORM_BOOTSTRAP
|
||||
val sources = collectSources(sourceDirPath = testModule.sourcePath, paths = testPaths)
|
||||
val testParams = testModule.getParams(baseDir)
|
||||
|
||||
val args = parseArgs(testParams.trimStart().lines().toTypedArray())
|
||||
performTestInvocation { out, coroutineScope ->
|
||||
buildKotlin(workingDir = baseDir, out = out, args = args, sources = sources)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,11 @@ import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.createPhaseConfig
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.cli.common.modules.ModuleBuilder
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.pipeline.compileModulesUsingFrontendIrAndLightTree
|
||||
import org.jetbrains.kotlin.cli.jvm.compiler.pipeline.createProjectEnvironment
|
||||
import org.jetbrains.kotlin.cli.jvm.config.configureJdkClasspathRoots
|
||||
import org.jetbrains.kotlin.cli.jvm.configureAdvancedJvmOptions
|
||||
import org.jetbrains.kotlin.cli.jvm.configureModuleChunk
|
||||
import org.jetbrains.kotlin.cli.jvm.plugins.PluginCliParser.RegisteredPluginInfo
|
||||
import org.jetbrains.kotlin.cli.plugins.processCompilerPluginOptions
|
||||
import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
|
||||
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.messageCollector
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.util.ServiceLoaderLite
|
||||
import java.io.File
|
||||
import java.net.URLClassLoader
|
||||
@@ -52,19 +51,20 @@ private fun createCompilerConfigurationTemplate(): CompilerConfiguration {
|
||||
internal val configTemplate = createCompilerConfigurationTemplate()
|
||||
|
||||
internal fun k2jvm(
|
||||
args: K2JVMCompilerArguments,
|
||||
config: CompilerConfiguration,
|
||||
rootDisposable: Disposable,
|
||||
module: ModuleBuilder,
|
||||
messageCollector: MessageCollector,
|
||||
): ExitCode {
|
||||
val messageCollector = config.getNotNull(CommonConfigurationKeys.MESSAGE_COLLECTOR_KEY)
|
||||
val moduleBuilders = listOf(module)
|
||||
|
||||
val modularJdkRoot = module.modularJdkRoot
|
||||
if (modularJdkRoot != null) {
|
||||
// We use the SDK of the first module in the chunk, which is not always correct because some other module in the chunk
|
||||
// might depend on a different SDK
|
||||
config.put(JVMConfigurationKeys.JDK_HOME, File(modularJdkRoot))
|
||||
}
|
||||
|
||||
val moduleName = args.moduleName ?: JvmProtoBufUtil.DEFAULT_MODULE_NAME
|
||||
config.put(CommonConfigurationKeys.MODULE_NAME, moduleName)
|
||||
val chunk = config.configureModuleChunk(arguments = args, buildFile = null).modules
|
||||
config.configureSourceRoots(chunk = chunk, buildFile = null)
|
||||
val targetDescription = chunk
|
||||
.map { input -> input.getModuleName() + "-" + input.getModuleType() }
|
||||
.let { names -> names.singleOrNull() ?: names.joinToString() }
|
||||
require(config.getBoolean(CommonConfigurationKeys.USE_LIGHT_TREE))
|
||||
require(config.getBoolean(CommonConfigurationKeys.USE_FIR))
|
||||
if (messageCollector.hasErrors()) {
|
||||
@@ -85,19 +85,19 @@ internal fun k2jvm(
|
||||
return ExitCode.COMPILATION_ERROR
|
||||
}
|
||||
|
||||
if (!compileModulesUsingFrontendIrAndLightTree(
|
||||
if (compileModulesUsingFrontendIrAndLightTree(
|
||||
projectEnvironment = projectEnvironment,
|
||||
compilerConfiguration = config,
|
||||
messageCollector = messageCollector,
|
||||
buildFile = null,
|
||||
chunk = chunk,
|
||||
targetDescription = targetDescription,
|
||||
chunk = moduleBuilders,
|
||||
targetDescription = module.getModuleName() + "-" + module.getModuleType(),
|
||||
checkSourceFiles = false,
|
||||
isPrintingVersion = false,
|
||||
)) {
|
||||
return ExitCode.COMPILATION_ERROR
|
||||
return ExitCode.OK
|
||||
}
|
||||
return ExitCode.OK
|
||||
return ExitCode.COMPILATION_ERROR
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalCompilerApi::class)
|
||||
|
||||
92
build/jvm-rules/src/worker-framework/testHelper.kt
Normal file
92
build/jvm-rules/src/worker-framework/testHelper.kt
Normal file
@@ -0,0 +1,92 @@
|
||||
package org.jetbrains.bazel.jvm
|
||||
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import java.io.StringWriter
|
||||
import java.io.Writer
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.ExperimentalPathApi
|
||||
import kotlin.io.path.invariantSeparatorsPathString
|
||||
import kotlin.io.path.walk
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
enum class TestModules(@JvmField val sourcePath: String, private val paramsPath: String) {
|
||||
PLATFORM_IMPL("platform/platform-impl/src", "platform/platform-impl/ide-impl.jar-0.params"),
|
||||
PLATFORM_BOOTSTRAP("platform/platform-impl/bootstrap/src", "platform/platform-impl/bootstrap/ide-bootstrap-kt.jar-0.params");
|
||||
|
||||
fun getParams(baseDir: Path): String {
|
||||
@Suppress("SpellCheckingInspection")
|
||||
return Files.readString(baseDir.resolve("bazel-out/community+/darwin_arm64-fastbuild/bin").resolve(paramsPath)).trim()
|
||||
}
|
||||
}
|
||||
|
||||
data class TestWorkerPaths(
|
||||
@JvmField val baseDir: Path,
|
||||
@JvmField val communityDir: Path,
|
||||
val userHomeDir: Path,
|
||||
)
|
||||
|
||||
fun getTestWorkerPaths(): TestWorkerPaths {
|
||||
val userHomeDir = Path.of(System.getProperty("user.home"))
|
||||
val ideaProjectDirName = if (Runtime.getRuntime().availableProcessors() >= 20) "idea-push" else "idea-second"
|
||||
val projectDir = userHomeDir.resolve("projects/$ideaProjectDirName")
|
||||
val communityDir = projectDir.resolve("community")
|
||||
val baseDir = getBazelExecRoot(projectDir)
|
||||
return TestWorkerPaths(
|
||||
baseDir = baseDir,
|
||||
communityDir = communityDir,
|
||||
userHomeDir = Path.of(System.getProperty("user.home")),
|
||||
)
|
||||
}
|
||||
|
||||
private fun getBazelExecRoot(currentWorkingDir: Path): Path {
|
||||
val process = ProcessBuilder("bazelisk", "info", "execution_root")
|
||||
.redirectErrorStream(true)
|
||||
.directory(currentWorkingDir.toFile())
|
||||
.start()
|
||||
|
||||
val output = process.inputStream.readAllBytes().toString(Charsets.UTF_8).trim()
|
||||
val exitCode = process.waitFor()
|
||||
if (exitCode == 0) {
|
||||
val result = Path.of(output)
|
||||
require(Files.isDirectory(result)) {
|
||||
"Not a directory: $result (currentWorkingDir=$currentWorkingDir"
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
throw RuntimeException("Failed to retrieve exec root (output=$output, exitCode=$exitCode)")
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalPathApi::class)
|
||||
fun collectSources(sourceDirPath: String, paths: TestWorkerPaths): List<Path> {
|
||||
val result = paths.communityDir.resolve(sourceDirPath)
|
||||
.walk()
|
||||
.filter {
|
||||
val p = it.toString()
|
||||
p.endsWith(".kt") || p.endsWith(".java")
|
||||
}
|
||||
.map { "../community+/" + paths.communityDir.relativize(it).invariantSeparatorsPathString }
|
||||
.sorted()
|
||||
.map { paths.baseDir.resolve(it).normalize() }
|
||||
.toList()
|
||||
require(result.isNotEmpty())
|
||||
return result
|
||||
}
|
||||
|
||||
fun performTestInvocation(execute: suspend (out: Writer, coroutineScope: CoroutineScope) -> Int) {
|
||||
val out = StringWriter()
|
||||
val exitCode: Int
|
||||
try {
|
||||
exitCode = runBlocking(Dispatchers.Default) {
|
||||
execute(out, this)
|
||||
}
|
||||
}
|
||||
finally {
|
||||
System.out.append(out.toString())
|
||||
}
|
||||
|
||||
exitProcess(exitCode)
|
||||
}
|
||||
@@ -77,6 +77,11 @@ class ZipArchiveOutputStream(
|
||||
)
|
||||
}
|
||||
|
||||
fun writeDataRawEntryWithoutCrc(data: ByteBuffer, name: ByteArray) {
|
||||
val size = data.remaining()
|
||||
writeDataRawEntry(data = data, name = name, size = size, compressedSize = size, method = ZipEntry.STORED, crc = 0)
|
||||
}
|
||||
|
||||
// data contains only data - zip local file header will be generated
|
||||
fun writeDataRawEntry(
|
||||
data: ByteBuffer,
|
||||
|
||||
@@ -22,7 +22,8 @@ import java.util.zip.ZipEntry
|
||||
import kotlin.math.min
|
||||
|
||||
val W_CREATE_NEW: EnumSet<StandardOpenOption> = EnumSet.of(StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW)
|
||||
val WRITE: EnumSet<StandardOpenOption> = EnumSet.of(StandardOpenOption.WRITE)
|
||||
@PublishedApi
|
||||
internal val WRITE: EnumSet<StandardOpenOption> = EnumSet.of(StandardOpenOption.WRITE)
|
||||
private val READ = EnumSet.of(StandardOpenOption.READ)
|
||||
|
||||
// 1 MB
|
||||
|
||||
@@ -4,6 +4,9 @@ package org.jetbrains.intellij.build.io
|
||||
import java.io.File
|
||||
import java.nio.channels.FileChannel
|
||||
import java.nio.file.*
|
||||
import java.nio.file.attribute.DosFileAttributeView
|
||||
import java.nio.file.attribute.PosixFileAttributeView
|
||||
import java.nio.file.attribute.PosixFilePermission
|
||||
import java.util.*
|
||||
import java.util.zip.Deflater
|
||||
|
||||
@@ -198,4 +201,65 @@ inline fun archiveDir(startDir: Path, addFile: (file: Path) -> Unit, excludes: L
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline fun writeZipUsingTempFile(file: Path, indexWriter: IkvIndexBuilder?, task: (ZipArchiveOutputStream) -> Unit) {
|
||||
writeFileUsingTempFile(file) { tempFile ->
|
||||
ZipArchiveOutputStream(
|
||||
channel = FileChannel.open(tempFile, WRITE),
|
||||
zipIndexWriter = ZipIndexWriter(indexWriter),
|
||||
).use {
|
||||
task(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline fun writeFileUsingTempFile(file: Path, task: (tempFile: Path) -> Unit) {
|
||||
val tempFile = Files.createTempFile(file.parent, file.fileName.toString(), ".tmp")
|
||||
var moved = false
|
||||
try {
|
||||
task(tempFile)
|
||||
|
||||
try {
|
||||
moveAtomic(tempFile, file)
|
||||
}
|
||||
catch (e: AccessDeniedException) {
|
||||
makeFileWritable(file, e)
|
||||
moveAtomic(tempFile, file)
|
||||
}
|
||||
moved = true
|
||||
}
|
||||
finally {
|
||||
if (!moved) {
|
||||
Files.deleteIfExists(tempFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
internal fun moveAtomic(from: Path, to: Path) {
|
||||
try {
|
||||
Files.move(from, to, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE)
|
||||
}
|
||||
catch (_: AtomicMoveNotSupportedException) {
|
||||
Files.move(from, to, StandardCopyOption.REPLACE_EXISTING)
|
||||
}
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
internal fun makeFileWritable(file: Path, cause: Throwable) {
|
||||
val posixView = Files.getFileAttributeView<PosixFileAttributeView?>(file, PosixFileAttributeView::class.java)
|
||||
if (posixView != null) {
|
||||
val permissions = posixView.readAttributes().permissions()
|
||||
permissions.add(PosixFilePermission.OWNER_WRITE)
|
||||
posixView.setPermissions(permissions)
|
||||
}
|
||||
|
||||
val dosView = Files.getFileAttributeView<DosFileAttributeView?>(file, DosFileAttributeView::class.java)
|
||||
@Suppress("IfThenToSafeAccess")
|
||||
if (dosView != null) {
|
||||
dosView.setReadOnly(false)
|
||||
}
|
||||
|
||||
throw UnsupportedOperationException("Unable to modify file attributes. Unsupported platform.", cause)
|
||||
}
|
||||
Reference in New Issue
Block a user