Rebuild module on plugin classpaths change
Add another one reason for rebuild: if pluginClasspaths was changed or even its jar content, module will be marked for rebuild Merge-request: KT-MR-5839 Merged-by: Aleksei Cherepanov <aleksei.cherepanov@jetbrains.com>
This commit is contained in:
committed by
Space
parent
281e381223
commit
e0029b14ee
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.build
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||
import org.jetbrains.kotlin.config.KotlinCompilerVersion
|
||||
import org.jetbrains.kotlin.config.LanguageVersion
|
||||
import org.jetbrains.kotlin.config.PluginClasspaths
|
||||
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@@ -23,6 +24,7 @@ interface BuildMetaInfo {
|
||||
val ownVersion: Int
|
||||
val coroutinesVersion: Int
|
||||
val multiplatformVersion: Int
|
||||
val pluginClasspaths: String
|
||||
}
|
||||
|
||||
abstract class BuildMetaInfoFactory<T : BuildMetaInfo>(private val metaInfoClass: KClass<T>) {
|
||||
@@ -35,7 +37,8 @@ abstract class BuildMetaInfoFactory<T : BuildMetaInfo>(private val metaInfoClass
|
||||
ownVersion: Int,
|
||||
coroutinesVersion: Int,
|
||||
multiplatformVersion: Int,
|
||||
metadataVersionArray: IntArray?
|
||||
metadataVersionArray: IntArray?,
|
||||
pluginClasspaths: String
|
||||
): T
|
||||
|
||||
fun create(args: CommonCompilerArguments): T {
|
||||
@@ -50,7 +53,8 @@ abstract class BuildMetaInfoFactory<T : BuildMetaInfo>(private val metaInfoClass
|
||||
ownVersion = OWN_VERSION,
|
||||
coroutinesVersion = COROUTINES_VERSION,
|
||||
multiplatformVersion = MULTIPLATFORM_VERSION,
|
||||
metadataVersionArray = args.metadataVersion?.let { BinaryVersion.parseVersionArray(it) }
|
||||
metadataVersionArray = args.metadataVersion?.let { BinaryVersion.parseVersionArray(it) },
|
||||
pluginClasspaths = PluginClasspaths(args.pluginClasspaths).serialize()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,8 @@ data class CommonBuildMetaInfo(
|
||||
override val metadataVersionPatch: Int,
|
||||
override val ownVersion: Int,
|
||||
override val coroutinesVersion: Int,
|
||||
override val multiplatformVersion: Int
|
||||
override val multiplatformVersion: Int,
|
||||
override val pluginClasspaths: String
|
||||
) : BuildMetaInfo {
|
||||
companion object : BuildMetaInfoFactory<CommonBuildMetaInfo>(CommonBuildMetaInfo::class) {
|
||||
override fun create(
|
||||
@@ -33,7 +34,8 @@ data class CommonBuildMetaInfo(
|
||||
ownVersion: Int,
|
||||
coroutinesVersion: Int,
|
||||
multiplatformVersion: Int,
|
||||
metadataVersionArray: IntArray?
|
||||
metadataVersionArray: IntArray?,
|
||||
pluginClasspaths: String
|
||||
): CommonBuildMetaInfo {
|
||||
val metadataVersion = metadataVersionArray?.let(::JvmMetadataVersion) ?: JvmMetadataVersion.INSTANCE
|
||||
return CommonBuildMetaInfo(
|
||||
@@ -47,7 +49,8 @@ data class CommonBuildMetaInfo(
|
||||
metadataVersionPatch = metadataVersion.patch,
|
||||
ownVersion = ownVersion,
|
||||
coroutinesVersion = coroutinesVersion,
|
||||
multiplatformVersion = multiplatformVersion
|
||||
multiplatformVersion = multiplatformVersion,
|
||||
pluginClasspaths = pluginClasspaths
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@ data class JsBuildMetaInfo(
|
||||
override val metadataVersionPatch: Int,
|
||||
override val ownVersion: Int,
|
||||
override val coroutinesVersion: Int,
|
||||
override val multiplatformVersion: Int
|
||||
override val multiplatformVersion: Int,
|
||||
override val pluginClasspaths: String
|
||||
) : BuildMetaInfo {
|
||||
companion object : BuildMetaInfoFactory<JsBuildMetaInfo>(JsBuildMetaInfo::class) {
|
||||
override fun create(
|
||||
@@ -33,7 +34,8 @@ data class JsBuildMetaInfo(
|
||||
ownVersion: Int,
|
||||
coroutinesVersion: Int,
|
||||
multiplatformVersion: Int,
|
||||
metadataVersionArray: IntArray?
|
||||
metadataVersionArray: IntArray?,
|
||||
pluginClasspaths: String
|
||||
): JsBuildMetaInfo {
|
||||
val metadataVersion = metadataVersionArray?.let(::JsMetadataVersion) ?: JsMetadataVersion.INSTANCE
|
||||
return JsBuildMetaInfo(
|
||||
@@ -47,7 +49,8 @@ data class JsBuildMetaInfo(
|
||||
metadataVersionPatch = metadataVersion.patch,
|
||||
ownVersion = ownVersion,
|
||||
coroutinesVersion = coroutinesVersion,
|
||||
multiplatformVersion = multiplatformVersion
|
||||
multiplatformVersion = multiplatformVersion,
|
||||
pluginClasspaths = pluginClasspaths
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,8 @@ data class JvmBuildMetaInfo(
|
||||
val bytecodeVersionPatch: Int,
|
||||
override val ownVersion: Int,
|
||||
override val coroutinesVersion: Int,
|
||||
override val multiplatformVersion: Int
|
||||
override val multiplatformVersion: Int,
|
||||
override val pluginClasspaths: String
|
||||
) : BuildMetaInfo {
|
||||
companion object : BuildMetaInfoFactory<JvmBuildMetaInfo>(JvmBuildMetaInfo::class) {
|
||||
override fun create(
|
||||
@@ -48,7 +49,8 @@ data class JvmBuildMetaInfo(
|
||||
ownVersion: Int,
|
||||
coroutinesVersion: Int,
|
||||
multiplatformVersion: Int,
|
||||
metadataVersionArray: IntArray?
|
||||
metadataVersionArray: IntArray?,
|
||||
pluginClasspaths: String
|
||||
): JvmBuildMetaInfo {
|
||||
val metadataVersion = metadataVersionArray?.let(::JvmMetadataVersion) ?: JvmMetadataVersion.INSTANCE
|
||||
return JvmBuildMetaInfo(
|
||||
@@ -65,7 +67,8 @@ data class JvmBuildMetaInfo(
|
||||
bytecodeVersionPatch = JvmBytecodeBinaryVersion.INSTANCE.patch,
|
||||
ownVersion = ownVersion,
|
||||
coroutinesVersion = coroutinesVersion,
|
||||
multiplatformVersion = multiplatformVersion
|
||||
multiplatformVersion = multiplatformVersion,
|
||||
pluginClasspaths = pluginClasspaths
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,8 @@ class BuildMetaInfoTest : TestCase() {
|
||||
"metadataVersionPatch",
|
||||
"multiplatformEnable",
|
||||
"multiplatformVersion",
|
||||
"ownVersion"
|
||||
"ownVersion",
|
||||
"pluginClasspaths"
|
||||
)
|
||||
assertEquals(expectedKeys, actual.split("\r\n", "\n").map { line -> line.split("=").first() })
|
||||
}
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.config
|
||||
|
||||
import java.io.File
|
||||
import java.security.DigestInputStream
|
||||
import java.security.MessageDigest
|
||||
|
||||
class PluginClasspaths(val classpaths: Array<String>?) {
|
||||
companion object {
|
||||
fun deserializeWithHashes(str: String): List<Pair<String, String>> =
|
||||
str.split(":")
|
||||
.filter(String::isNotBlank)
|
||||
.map { Pair(File(it.substringBeforeLast("-")).name, it.substringAfterLast("-")) }
|
||||
}
|
||||
|
||||
fun serialize() = classpaths?.mapNotNull { it ->
|
||||
val jar = File(it).takeIf { it.exists() } ?: return@mapNotNull null
|
||||
val jarPath = jar.absolutePath
|
||||
val jarHash = jar.sha256()
|
||||
"$jarPath-$jarHash"
|
||||
}?.joinToString(":") ?: ""
|
||||
|
||||
private fun File.sha256(): String {
|
||||
val digest = MessageDigest.getInstance("SHA-256")
|
||||
DigestInputStream(this.inputStream(), digest).use { dis ->
|
||||
val buffer = ByteArray(8192)
|
||||
var bytesRead = 0
|
||||
while (bytesRead != -1) {
|
||||
bytesRead = dis.read(buffer, 0, buffer.size)
|
||||
}
|
||||
}
|
||||
// Convert to hex:
|
||||
return digest.digest().joinToString("") {
|
||||
Integer.toHexString((it.toInt() and 0xff) + 0x100).substring(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PluginClasspathsComparator(old: String, new: String) {
|
||||
private val oldPluginClasspath: List<Pair<String, String>> by lazy { PluginClasspaths.deserializeWithHashes(old) }
|
||||
private val newPluginClasspath: List<Pair<String, String>> by lazy { PluginClasspaths.deserializeWithHashes(new) }
|
||||
|
||||
fun equals() = oldPluginClasspath == newPluginClasspath
|
||||
|
||||
fun describeDifferencesOrNull(): String? {
|
||||
val changed = oldPluginClasspath != newPluginClasspath
|
||||
if (!changed) return null
|
||||
val added = newPluginClasspath.subtract(oldPluginClasspath).takeIf { it.isNotEmpty() }?.toList()
|
||||
val deleted = oldPluginClasspath.subtract(newPluginClasspath).takeIf { it.isNotEmpty() }?.toList()
|
||||
return StringBuilder().apply {
|
||||
if (added == null && deleted == null) {
|
||||
this.append("Plugin classpaths was reordered.")
|
||||
return@apply
|
||||
}
|
||||
this.append("Plugin classpaths was changed.")
|
||||
if (added != null) this.append(" Added: ${added.joinToString(", ")}.")
|
||||
if (deleted != null) this.append(" Deleted: ${deleted.joinToString(", ")}.")
|
||||
this.append(" Rebuild initiated.")
|
||||
}.toString()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,9 +45,11 @@ import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil
|
||||
import org.jetbrains.kotlin.codegen.JvmCodegenUtil
|
||||
import org.jetbrains.kotlin.config.IncrementalCompilation
|
||||
import org.jetbrains.kotlin.config.KotlinFacetSettings
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.jps.build.KotlinJpsBuildTestBase.LibraryDependency.*
|
||||
import org.jetbrains.kotlin.jps.incremental.CacheAttributesDiff
|
||||
import org.jetbrains.kotlin.jps.model.JpsKotlinFacetModuleExtension
|
||||
import org.jetbrains.kotlin.jps.model.kotlinCommonCompilerArguments
|
||||
import org.jetbrains.kotlin.jps.model.kotlinCompilerArguments
|
||||
import org.jetbrains.kotlin.jps.targets.KotlinModuleBuildTarget
|
||||
@@ -952,6 +954,38 @@ open class KotlinJpsBuildTest : KotlinJpsBuildTestBase() {
|
||||
buildAllModules().assertSuccessful()
|
||||
}
|
||||
|
||||
@WorkingDir("KotlinProject")
|
||||
fun testModuleRebuildOnPluginClasspathsChange() {
|
||||
initProject(JVM_MOCK_RUNTIME)
|
||||
myProject.modules.forEach {
|
||||
val facet = KotlinFacetSettings()
|
||||
facet.useProjectSettings = false
|
||||
facet.compilerArguments = K2JVMCompilerArguments()
|
||||
facet.compilerArguments?.pluginClasspaths = arrayOf(PathUtil.kotlinPathsForDistDirectory.lombokPluginJarPath.path)
|
||||
|
||||
it.container.setChild(
|
||||
JpsKotlinFacetModuleExtension.KIND,
|
||||
JpsKotlinFacetModuleExtension(facet)
|
||||
)
|
||||
}
|
||||
buildAllModules().assertSuccessful()
|
||||
myProject.modules.forEach {
|
||||
val facet = KotlinFacetSettings()
|
||||
facet.useProjectSettings = false
|
||||
facet.compilerArguments = K2JVMCompilerArguments()
|
||||
facet.compilerArguments?.pluginClasspaths = arrayOf(
|
||||
PathUtil.kotlinPathsForDistDirectory.lombokPluginJarPath.path,
|
||||
PathUtil.kotlinPathsForDistDirectory.allOpenPluginJarPath.path
|
||||
)
|
||||
it.container.setChild(
|
||||
JpsKotlinFacetModuleExtension.KIND,
|
||||
JpsKotlinFacetModuleExtension(facet)
|
||||
)
|
||||
}
|
||||
|
||||
checkWhen(emptyArray(), null, packageClasses("kotlinProject", "src/test1.kt", "Test1Kt"))
|
||||
}
|
||||
|
||||
private fun BuildResult.checkErrors() {
|
||||
val actualErrors = getMessages(BuildMessage.Kind.ERROR)
|
||||
.map { it as CompilerMessage }
|
||||
|
||||
@@ -21,9 +21,7 @@ import org.jetbrains.kotlin.build.GeneratedFile
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||
import org.jetbrains.kotlin.compilerRunner.JpsCompilerEnvironment
|
||||
import org.jetbrains.kotlin.config.ApiVersion
|
||||
import org.jetbrains.kotlin.config.LanguageVersion
|
||||
import org.jetbrains.kotlin.config.Services
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.incremental.ChangesCollector
|
||||
import org.jetbrains.kotlin.incremental.ExpectActualTrackerImpl
|
||||
import org.jetbrains.kotlin.incremental.components.ExpectActualTracker
|
||||
@@ -339,7 +337,8 @@ abstract class KotlinModuleBuildTarget<BuildMetaInfoType : BuildMetaInfo> intern
|
||||
|
||||
val prevBuildMetaInfo =
|
||||
try {
|
||||
buildMetaInfoFactory.deserializeFromString(Files.newInputStream(file).bufferedReader().use { it.readText() }) ?: return false
|
||||
buildMetaInfoFactory.deserializeFromString(Files.newInputStream(file).bufferedReader().use { it.readText() })
|
||||
?: return false
|
||||
} catch (e: Exception) {
|
||||
KotlinBuilder.LOG.error("Could not deserialize build meta info", e)
|
||||
return false
|
||||
@@ -355,7 +354,10 @@ abstract class KotlinModuleBuildTarget<BuildMetaInfoType : BuildMetaInfo> intern
|
||||
// If EAP->Non-EAP build with IC, then rebuild all kotlin
|
||||
"Last build was compiled with EAP-plugin"
|
||||
}
|
||||
else -> null
|
||||
else -> PluginClasspathsComparator(
|
||||
prevBuildMetaInfo.pluginClasspaths,
|
||||
buildMetaInfo.pluginClasspaths
|
||||
).describeDifferencesOrNull()
|
||||
}
|
||||
|
||||
if (reasonToRebuild != null) {
|
||||
|
||||
Reference in New Issue
Block a user