diff --git a/build-common/src/org/jetbrains/kotlin/build/BuildMetaInfo.kt b/build-common/src/org/jetbrains/kotlin/build/BuildMetaInfo.kt index d9c73106b42..5514684b4e6 100644 --- a/build-common/src/org/jetbrains/kotlin/build/BuildMetaInfo.kt +++ b/build-common/src/org/jetbrains/kotlin/build/BuildMetaInfo.kt @@ -6,70 +6,132 @@ package org.jetbrains.kotlin.build import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments -import org.jetbrains.kotlin.config.KotlinCompilerVersion +import org.jetbrains.kotlin.config.ApiVersion import org.jetbrains.kotlin.config.LanguageVersion import org.jetbrains.kotlin.config.PluginClasspaths -import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion -import kotlin.reflect.KClass +import org.jetbrains.kotlin.config.PluginClasspathsComparator -interface BuildMetaInfo { - val isEAP: Boolean - val compilerBuildVersion: String - val languageVersionString: String - val apiVersionString: String - val multiplatformEnable: Boolean - val metadataVersionMajor: Int - val metadataVersionMinor: Int - val metadataVersionPatch: Int - val ownVersion: Int - val coroutinesVersion: Int - val multiplatformVersion: Int - val pluginClasspaths: String -} - -abstract class BuildMetaInfoFactory(private val metaInfoClass: KClass) { - protected abstract fun create( - isEAP: Boolean, - compilerBuildVersion: String, - languageVersionString: String, - apiVersionString: String, - multiplatformEnable: Boolean, - ownVersion: Int, - coroutinesVersion: Int, - multiplatformVersion: Int, - metadataVersionArray: IntArray?, - pluginClasspaths: String - ): T - - fun create(args: CommonCompilerArguments): T { - val languageVersion = args.languageVersion?.let { LanguageVersion.fromVersionString(it) } ?: LanguageVersion.LATEST_STABLE - - return create( - isEAP = !languageVersion.isStable, - compilerBuildVersion = KotlinCompilerVersion.VERSION, - languageVersionString = languageVersion.versionString, - apiVersionString = args.apiVersion ?: languageVersion.versionString, - multiplatformEnable = args.multiPlatform, - ownVersion = OWN_VERSION, - coroutinesVersion = COROUTINES_VERSION, - multiplatformVersion = MULTIPLATFORM_VERSION, - metadataVersionArray = args.metadataVersion?.let { BinaryVersion.parseVersionArray(it) }, - pluginClasspaths = PluginClasspaths(args.pluginClasspaths).serialize() - ) +abstract class BuildMetaInfo { + enum class CustomKeys { + LANGUAGE_VERSION_STRING, IS_EAP, METADATA_VERSION_STRING, PLUGIN_CLASSPATHS, API_VERSION_STRING } - fun serializeToString(args: CommonCompilerArguments): String = - serializeToString(create(args)) + fun obtainReasonForRebuild(currentCompilerArgumentsMap: Map, previousCompilerArgsMap: Map): String? { + if (currentCompilerArgumentsMap.keys != previousCompilerArgsMap.keys) { + return "Compiler arguments version was changed" + } - fun serializeToString(info: T): String = - serializeToPlainText(info, metaInfoClass) + val changedCompilerArguments = currentCompilerArgumentsMap.mapNotNull { + val key = it.key + val previousValue = previousCompilerArgsMap[it.key] ?: return@mapNotNull key + val currentValue = it.value + return@mapNotNull if (compareIsChanged(key, currentValue, previousValue)) key else null + } - fun deserializeFromString(str: String): T? = - deserializeFromPlainText(str, metaInfoClass) - - companion object { - const val OWN_VERSION: Int = 0 - const val COROUTINES_VERSION: Int = 0 - const val MULTIPLATFORM_VERSION: Int = 0 + if (changedCompilerArguments.isNotEmpty()) { + val rebuildReason = when (changedCompilerArguments.size) { + 1 -> "One of compiler arguments was changed: " + else -> "Some compiler arguments were changed: " + } + changedCompilerArguments.joinToReadableString() + return rebuildReason + } + return null } -} + + private fun compareIsChanged(key: String, currentValue: String, previousValue: String): Boolean { + // check for specific key changes + checkIfPlatformSpecificCompilerArgumentWasChanged(key, currentValue, previousValue)?.let { comparisonResult -> + return comparisonResult + } + when (key) { + CustomKeys.LANGUAGE_VERSION_STRING.name -> + return LanguageVersion.fromVersionString(currentValue) != LanguageVersion.fromVersionString(previousValue) + CustomKeys.API_VERSION_STRING.name -> return ApiVersion.parse(currentValue) != ApiVersion.parse(previousValue) + CustomKeys.PLUGIN_CLASSPATHS.name -> return !PluginClasspathsComparator(previousValue, currentValue).equals() + } + + // check keys that are sensitive for true -> false change + if (key in argumentsListForSpecialCheck) { + return previousValue == "true" && currentValue != "true" + } + + // compare all other change-sensitive values + if (previousValue != currentValue) { + return true + } + + return false + } + + open fun checkIfPlatformSpecificCompilerArgumentWasChanged(key: String, currentValue: String, previousValue: String): Boolean? { + return null + } + + open fun createPropertiesMapFromCompilerArguments(args: CommonCompilerArguments): Map { + val resultMap = transformClassToPropertiesMap(args, excludedProperties).toMutableMap() + val languageVersion = args.languageVersion?.let { LanguageVersion.fromVersionString(it) } + ?: LanguageVersion.LATEST_STABLE + val languageVersionSting = languageVersion.versionString + resultMap[CustomKeys.LANGUAGE_VERSION_STRING.name] = languageVersionSting + + val isEAP = !languageVersion.isStable + resultMap[CustomKeys.IS_EAP.name] = isEAP.toString() + + val apiVersionString = args.apiVersion ?: languageVersionSting + resultMap[CustomKeys.API_VERSION_STRING.name] = apiVersionString + + val pluginClasspaths = PluginClasspaths(args.pluginClasspaths).serialize() + resultMap[CustomKeys.PLUGIN_CLASSPATHS.name] = pluginClasspaths + + return resultMap + } + + fun deserializeMapFromString(inputString: String): Map = inputString + .split("\n") + .filter(String::isNotBlank) + .associate { it.substringBefore("=") to it.substringAfter("=") } + + private fun serializeMapToString(myList: Map) = myList.map { "${it.key}=${it.value}" }.joinToString("\n") + fun serializeArgsToString(args: CommonCompilerArguments) = serializeMapToString(createPropertiesMapFromCompilerArguments(args)) + + open val excludedProperties = listOf( + "languageVersion", + "apiVersion", + "pluginClasspaths", + "metadataVersion", + "dumpDirectory", + "dumpOnlyFqName", + "dumpPerf", + "errors", + "extraHelp", + "freeArgs", + "help", + "intellijPluginRoot", + "kotlinHome", + "listPhases", + "namesExcludedFromDumping", + "phasesToDump", + "phasesToDumpAfter", + "phasesToDumpBefore", + "profilePhases", + "renderInternalDiagnosticNames", + "reportOutputFiles", + "reportPerf", + "script", + "verbose", + "verbosePhases", + "version" + ) + + open val argumentsListForSpecialCheck = listOf( + "allowAnyScriptsInSourceRoots", + "allowKotlinPackage", + "allowResultReturnType", + "noCheckActual", + "skipMetadataVersionCheck", + "skipPrereleaseCheck", + "suppressVersionWarnings", + "suppressWarnings", + CustomKeys.IS_EAP.name + ) +} \ No newline at end of file diff --git a/build-common/src/org/jetbrains/kotlin/build/CommonBuildMetaInfo.kt b/build-common/src/org/jetbrains/kotlin/build/CommonBuildMetaInfo.kt index b2aa9ccd27a..34e2e99c751 100644 --- a/build-common/src/org/jetbrains/kotlin/build/CommonBuildMetaInfo.kt +++ b/build-common/src/org/jetbrains/kotlin/build/CommonBuildMetaInfo.kt @@ -5,53 +5,34 @@ package org.jetbrains.kotlin.build +import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments +import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion -/** - * If you want to add a new field, check its type is supported by [serializeToPlainText], [deserializeFromPlainText] - */ -data class CommonBuildMetaInfo( - override val isEAP: Boolean, - override val compilerBuildVersion: String, - override val languageVersionString: String, - override val apiVersionString: String, - override val multiplatformEnable: Boolean, - override val metadataVersionMajor: Int, - override val metadataVersionMinor: Int, - override val metadataVersionPatch: Int, - override val ownVersion: Int, - override val coroutinesVersion: Int, - override val multiplatformVersion: Int, - override val pluginClasspaths: String -) : BuildMetaInfo { - companion object : BuildMetaInfoFactory(CommonBuildMetaInfo::class) { - override fun create( - isEAP: Boolean, - compilerBuildVersion: String, - languageVersionString: String, - apiVersionString: String, - multiplatformEnable: Boolean, - ownVersion: Int, - coroutinesVersion: Int, - multiplatformVersion: Int, - metadataVersionArray: IntArray?, - pluginClasspaths: String - ): CommonBuildMetaInfo { - val metadataVersion = metadataVersionArray?.let(::JvmMetadataVersion) ?: JvmMetadataVersion.INSTANCE - return CommonBuildMetaInfo( - isEAP = isEAP, - compilerBuildVersion = compilerBuildVersion, - languageVersionString = languageVersionString, - apiVersionString = apiVersionString, - multiplatformEnable = multiplatformEnable, - metadataVersionMajor = metadataVersion.major, - metadataVersionMinor = metadataVersion.minor, - metadataVersionPatch = metadataVersion.patch, - ownVersion = ownVersion, - coroutinesVersion = coroutinesVersion, - multiplatformVersion = multiplatformVersion, - pluginClasspaths = pluginClasspaths - ) +class CommonBuildMetaInfo : BuildMetaInfo() { + override fun checkIfPlatformSpecificCompilerArgumentWasChanged(key: String, currentValue: String, previousValue: String): Boolean? { + when (key) { + CustomKeys.METADATA_VERSION_STRING.name -> { + val currentVersionIntArray = BinaryVersion.parseVersionArray(currentValue) + if (currentVersionIntArray?.size != 3) return null + val currentVersion = JvmMetadataVersion(currentVersionIntArray[0], currentVersionIntArray[1], currentVersionIntArray[2]) + + val previousVersionIntArray = BinaryVersion.parseVersionArray(previousValue) + if (previousVersionIntArray?.size != 3) return null + val previousVersion = JvmMetadataVersion(previousVersionIntArray[0], previousVersionIntArray[1], previousVersionIntArray[2]) + return currentVersion == previousVersion + } } + return null } -} + + override fun createPropertiesMapFromCompilerArguments(args: CommonCompilerArguments): Map { + val resultMap = mutableMapOf() + val metadataVersionArray = args.metadataVersion?.let { BinaryVersion.parseVersionArray(it) } + val metadataVersion = metadataVersionArray?.let(::JvmMetadataVersion) ?: JvmMetadataVersion.INSTANCE + val metadataVersionString = metadataVersion.toString() + resultMap[CustomKeys.METADATA_VERSION_STRING.name] = metadataVersionString + + return super.createPropertiesMapFromCompilerArguments(args) + resultMap + } +} \ No newline at end of file diff --git a/build-common/src/org/jetbrains/kotlin/build/JsBuildMetaInfo.kt b/build-common/src/org/jetbrains/kotlin/build/JsBuildMetaInfo.kt index 095d20725f6..54bb9c9587a 100644 --- a/build-common/src/org/jetbrains/kotlin/build/JsBuildMetaInfo.kt +++ b/build-common/src/org/jetbrains/kotlin/build/JsBuildMetaInfo.kt @@ -5,53 +5,37 @@ package org.jetbrains.kotlin.build +import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments +import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion import org.jetbrains.kotlin.utils.JsMetadataVersion -/** - * If you want to add a new field, check its type is supported by [serializeToPlainText], [deserializeFromPlainText] - */ -data class JsBuildMetaInfo( - override val isEAP: Boolean, - override val compilerBuildVersion: String, - override val languageVersionString: String, - override val apiVersionString: String, - override val multiplatformEnable: Boolean, - override val metadataVersionMajor: Int, - override val metadataVersionMinor: Int, - override val metadataVersionPatch: Int, - override val ownVersion: Int, - override val coroutinesVersion: Int, - override val multiplatformVersion: Int, - override val pluginClasspaths: String -) : BuildMetaInfo { - companion object : BuildMetaInfoFactory(JsBuildMetaInfo::class) { - override fun create( - isEAP: Boolean, - compilerBuildVersion: String, - languageVersionString: String, - apiVersionString: String, - multiplatformEnable: Boolean, - ownVersion: Int, - coroutinesVersion: Int, - multiplatformVersion: Int, - metadataVersionArray: IntArray?, - pluginClasspaths: String - ): JsBuildMetaInfo { - val metadataVersion = metadataVersionArray?.let(::JsMetadataVersion) ?: JsMetadataVersion.INSTANCE - return JsBuildMetaInfo( - isEAP = isEAP, - compilerBuildVersion = compilerBuildVersion, - languageVersionString = languageVersionString, - apiVersionString = apiVersionString, - multiplatformEnable = multiplatformEnable, - metadataVersionMajor = metadataVersion.major, - metadataVersionMinor = metadataVersion.minor, - metadataVersionPatch = metadataVersion.patch, - ownVersion = ownVersion, - coroutinesVersion = coroutinesVersion, - multiplatformVersion = multiplatformVersion, - pluginClasspaths = pluginClasspaths - ) +class JsBuildMetaInfo : BuildMetaInfo() { + override fun checkIfPlatformSpecificCompilerArgumentWasChanged(key: String, currentValue: String, previousValue: String): Boolean? { + when (key) { + CustomKeys.METADATA_VERSION_STRING.name -> { + val currentValueIntArray = BinaryVersion.parseVersionArray(currentValue) + if (currentValueIntArray?.size != 3) return null + val currentVersion = JsMetadataVersion(currentValueIntArray[0], currentValueIntArray[1], currentValueIntArray[2]) + + val previousValueIntArray = BinaryVersion.parseVersionArray(previousValue) + if (previousValueIntArray?.size != 3) return null + val previousVersion = JsMetadataVersion(previousValueIntArray[0], previousValueIntArray[1], previousValueIntArray[2]) + return currentVersion == previousVersion + } } + return null } -} + + override fun createPropertiesMapFromCompilerArguments(args: CommonCompilerArguments): Map { + val resultMap = mutableMapOf() + val metadataVersionArray = args.metadataVersion?.let { BinaryVersion.parseVersionArray(it) } + val metadataVersion = metadataVersionArray?.let(::JsMetadataVersion) ?: JsMetadataVersion.INSTANCE + val metadataVersionString = metadataVersion.toInteger().toString() + resultMap[CustomKeys.METADATA_VERSION_STRING.name] = metadataVersionString + + return super.createPropertiesMapFromCompilerArguments(args) + resultMap + } + + override val argumentsListForSpecialCheck: List + get() = super.argumentsListForSpecialCheck + listOf("sourceMap", "metaInfo" + "partialLinkage" + "wasmDebug") +} \ No newline at end of file diff --git a/build-common/src/org/jetbrains/kotlin/build/JvmBuildMetaInfo.kt b/build-common/src/org/jetbrains/kotlin/build/JvmBuildMetaInfo.kt index 24f735a08ae..138bb535f3c 100644 --- a/build-common/src/org/jetbrains/kotlin/build/JvmBuildMetaInfo.kt +++ b/build-common/src/org/jetbrains/kotlin/build/JvmBuildMetaInfo.kt @@ -16,60 +16,62 @@ package org.jetbrains.kotlin.build -import org.jetbrains.kotlin.load.kotlin.JvmBytecodeBinaryVersion +import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments +import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion -/** - * If you want to add a new field, check its type is supported by [serializeToPlainText], [deserializeFromPlainText] - */ -data class JvmBuildMetaInfo( - override val isEAP: Boolean, - override val compilerBuildVersion: String, - override val languageVersionString: String, - override val apiVersionString: String, - override val multiplatformEnable: Boolean, - override val metadataVersionMajor: Int, - override val metadataVersionMinor: Int, - override val metadataVersionPatch: Int, - val bytecodeVersionMajor: Int, - val bytecodeVersionMinor: Int, - val bytecodeVersionPatch: Int, - override val ownVersion: Int, - override val coroutinesVersion: Int, - override val multiplatformVersion: Int, - override val pluginClasspaths: String -) : BuildMetaInfo { - companion object : BuildMetaInfoFactory(JvmBuildMetaInfo::class) { - override fun create( - isEAP: Boolean, - compilerBuildVersion: String, - languageVersionString: String, - apiVersionString: String, - multiplatformEnable: Boolean, - ownVersion: Int, - coroutinesVersion: Int, - multiplatformVersion: Int, - metadataVersionArray: IntArray?, - pluginClasspaths: String - ): JvmBuildMetaInfo { - val metadataVersion = metadataVersionArray?.let(::JvmMetadataVersion) ?: JvmMetadataVersion.INSTANCE - return JvmBuildMetaInfo( - isEAP = isEAP, - compilerBuildVersion = compilerBuildVersion, - languageVersionString = languageVersionString, - apiVersionString = apiVersionString, - multiplatformEnable = multiplatformEnable, - metadataVersionMajor = metadataVersion.major, - metadataVersionMinor = metadataVersion.minor, - metadataVersionPatch = metadataVersion.patch, - bytecodeVersionMajor = JvmBytecodeBinaryVersion.INSTANCE.major, - bytecodeVersionMinor = JvmBytecodeBinaryVersion.INSTANCE.minor, - bytecodeVersionPatch = JvmBytecodeBinaryVersion.INSTANCE.patch, - ownVersion = ownVersion, - coroutinesVersion = coroutinesVersion, - multiplatformVersion = multiplatformVersion, - pluginClasspaths = pluginClasspaths - ) +class JvmBuildMetaInfo : BuildMetaInfo() { + override fun checkIfPlatformSpecificCompilerArgumentWasChanged(key: String, currentValue: String, previousValue: String): Boolean? { + when (key) { + CustomKeys.METADATA_VERSION_STRING.name -> { + val currentVersionIntArray = BinaryVersion.parseVersionArray(currentValue) + if (currentVersionIntArray?.size != 3) return null + val currentVersion = JvmMetadataVersion(currentVersionIntArray[0], currentVersionIntArray[1], currentVersionIntArray[2]) + + val previousVersionIntArray = BinaryVersion.parseVersionArray(previousValue) + if (previousVersionIntArray?.size != 3) return null + val previousVersion = JvmMetadataVersion(previousVersionIntArray[0], previousVersionIntArray[1], previousVersionIntArray[2]) + return currentVersion != previousVersion + } } + return null } + + override fun createPropertiesMapFromCompilerArguments(args: CommonCompilerArguments): Map { + val resultMap = mutableMapOf() + val metadataVersionArray = args.metadataVersion?.let { BinaryVersion.parseVersionArray(it) } + val metadataVersion = metadataVersionArray?.let(::JvmMetadataVersion) ?: JvmMetadataVersion.INSTANCE + val metadataVersionString = metadataVersion.toString() + resultMap[CustomKeys.METADATA_VERSION_STRING.name] = metadataVersionString + + return super.createPropertiesMapFromCompilerArguments(args) + resultMap + } + + override val excludedProperties: List + get() = super.excludedProperties + listOf( + "excludedProperties", + "backendThreads", + "buildFile", + "classpath", + "declarationsOutputPath", + "defaultScriptExtension", + "enableDebugMode", + "expression", + "internalArguments", + "profileCompilerCommand", + "repeatCompileModules", + "scriptResolverEnvironment", + "scriptTemplates", + "suppressDeprecatedJvmTargetWarning", + "useFastJarFileSystem", + ) + + override val argumentsListForSpecialCheck: List + get() = super.argumentsListForSpecialCheck + listOf( + "allowNoSourceFiles", + "allowUnstableDependencies", + "enableJvmPreview", + "ignoreConstOptimizationErrors", + "suppressMissingBuiltinsError", + ) } diff --git a/build-common/src/org/jetbrains/kotlin/build/serializationUtils.kt b/build-common/src/org/jetbrains/kotlin/build/serializationUtils.kt index 5f52d1e47ba..e9f8f825cfd 100644 --- a/build-common/src/org/jetbrains/kotlin/build/serializationUtils.kt +++ b/build-common/src/org/jetbrains/kotlin/build/serializationUtils.kt @@ -16,6 +16,8 @@ package org.jetbrains.kotlin.build +import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments +import org.jetbrains.kotlin.cli.common.arguments.collectProperties import kotlin.reflect.KClass import kotlin.reflect.full.memberProperties import kotlin.reflect.full.primaryConstructor @@ -38,12 +40,12 @@ inline fun deserializeFromPlainText(str: String): T? = deseria fun deserializeFromPlainText(str: String, klass: KClass): T? { val args = ArrayList() val properties = str - .split("\n") - .filter(String::isNotBlank) - .associate { it.substringBefore("=") to it.substringAfter("=") } + .split("\n") + .filter(String::isNotBlank) + .associate { it.substringBefore("=") to it.substringAfter("=") } val primaryConstructor = klass.primaryConstructor - ?: throw IllegalStateException("${klass.java} does not have primary constructor") + ?: throw IllegalStateException("${klass.java} does not have primary constructor") for (param in primaryConstructor.parameters.sortedBy { it.index }) { val argumentString = properties[param.name] @@ -51,8 +53,7 @@ fun deserializeFromPlainText(str: String, klass: KClass): T? { if (param.type.isMarkedNullable) { args.add(null) continue - } - else { + } else { return null } } @@ -69,3 +70,18 @@ fun deserializeFromPlainText(str: String, klass: KClass): T? { return primaryConstructor.call(*args.toTypedArray()) } + +@Suppress("UNCHECKED_CAST") +fun transformClassToPropertiesMap(classToTransform: T, excludedProperties: List = emptyList()) = + collectProperties(classToTransform::class as KClass, false) + .filter { property -> property.name !in excludedProperties } + .associateBy( + keySelector = { property -> property.name }, + valueTransform = { property -> property.get(classToTransform).toString() }) + +fun List.joinToReadableString(): String = when { + size > 5 -> take(5).joinToString() + " and ${size - 5} more" + size > 1 -> dropLast(1).joinToString() + " and ${last()}" + size == 1 -> single() + else -> "" +} \ No newline at end of file diff --git a/build-common/test/org/jetbrains/kotlin/build/BuildMetaInfoTest.kt b/build-common/test/org/jetbrains/kotlin/build/BuildMetaInfoTest.kt deleted file mode 100644 index a3c7282831b..00000000000 --- a/build-common/test/org/jetbrains/kotlin/build/BuildMetaInfoTest.kt +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright 2010-2017 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.build - -import junit.framework.TestCase -import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments -import org.junit.Assert.assertNotEquals -import org.junit.Test - -class BuildMetaInfoTest : TestCase() { - @Test - fun testJvmSerialization() { - val args = K2JVMCompilerArguments() - val info = JvmBuildMetaInfo.create(args) - val actual = JvmBuildMetaInfo.serializeToString(info) - val expectedKeys = listOf( - "apiVersionString", - "bytecodeVersionMajor", - "bytecodeVersionMinor", - "bytecodeVersionPatch", - "compilerBuildVersion", - "coroutinesVersion", - "isEAP", - "languageVersionString", - "metadataVersionMajor", - "metadataVersionMinor", - "metadataVersionPatch", - "multiplatformEnable", - "multiplatformVersion", - "ownVersion", - "pluginClasspaths" - ) - assertEquals(expectedKeys, actual.split("\r\n", "\n").map { line -> line.split("=").first() }) - } - - @Test - fun testJvmSerializationDeserialization() { - val args = K2JVMCompilerArguments() - val info = JvmBuildMetaInfo.create(args) - val serialized = JvmBuildMetaInfo.serializeToString(info) - val deserialized = JvmBuildMetaInfo.deserializeFromString(serialized) - assertEquals(info, deserialized) - } - - @Test - fun testJsSerializationDeserialization() { - val args = K2JVMCompilerArguments() - val info = JvmBuildMetaInfo.create(args) - val serialized = JvmBuildMetaInfo.serializeToString(info) - val deserialized = JvmBuildMetaInfo.deserializeFromString(serialized) - assertEquals(info, deserialized) - } - - @Test - fun testJvmEquals() { - val args1 = K2JVMCompilerArguments() - val info1 = JvmBuildMetaInfo.create(args1) - - val args2 = K2JVMCompilerArguments() - val info2 = JvmBuildMetaInfo.create(args2) - - assertEquals(info1, info2) - assertEquals(info1, info2.copy()) - } -} diff --git a/jps/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/JoinToReadableStringTest.kt b/build-common/test/org/jetbrains/kotlin/build/JoinToReadableStringTest.kt similarity index 92% rename from jps/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/JoinToReadableStringTest.kt rename to build-common/test/org/jetbrains/kotlin/build/JoinToReadableStringTest.kt index cdba8ef49b7..d949ad17e8e 100644 --- a/jps/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/JoinToReadableStringTest.kt +++ b/build-common/test/org/jetbrains/kotlin/build/JoinToReadableStringTest.kt @@ -1,9 +1,9 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.jps.build +package org.jetbrains.kotlin.build import junit.framework.TestCase diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/argumentUtils.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/argumentUtils.kt index ba548425d69..0650334d157 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/argumentUtils.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/argumentUtils.kt @@ -112,4 +112,3 @@ fun CommonCompilerArguments.setApiVersionToLanguageVersionIfNeeded() { apiVersion = languageVersion } } - diff --git a/jps/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/AbstractIncrementalLazyCachesTest.kt b/jps/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/AbstractIncrementalLazyCachesTest.kt index 4f4eef38302..2225ff5e5f9 100644 --- a/jps/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/AbstractIncrementalLazyCachesTest.kt +++ b/jps/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/AbstractIncrementalLazyCachesTest.kt @@ -108,11 +108,11 @@ abstract class AbstractIncrementalLazyCachesTest : AbstractIncrementalJpsTest() }.sortedBy { it.target.jpsModuleBuildTarget.presentableName } allTargets.forEach { (chunk, target) -> - val metaBuildInfo = chunk.buildMetaInfoFile(target.jpsModuleBuildTarget) + val compilerArgumentsFile = chunk.compilerArgumentsFile(target.jpsModuleBuildTarget) dumpCachesForTarget( printer, paths, target.jpsModuleBuildTarget, target.localCacheVersionManager.versionFileForTesting, - metaBuildInfo.toFile(), + compilerArgumentsFile.toFile(), subdirectory = KOTLIN_CACHE_DIRECTORY_NAME ) } diff --git a/jps/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/KotlinJpsBuildTest.kt b/jps/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/KotlinJpsBuildTest.kt index 662818ed4cc..5402b2fa92b 100644 --- a/jps/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/KotlinJpsBuildTest.kt +++ b/jps/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/KotlinJpsBuildTest.kt @@ -45,6 +45,7 @@ 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.JvmDefaultMode import org.jetbrains.kotlin.config.KotlinFacetSettings import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.jps.build.KotlinJpsBuildTestBase.LibraryDependency.* @@ -828,6 +829,121 @@ open class KotlinJpsBuildTest : KotlinJpsBuildTestBase() { checkWhen(emptyArray(), null, packageClasses("kotlinProject", "src/test1.kt", "Test1Kt")) } + @WorkingDir("KotlinProject") + fun testModuleRebuildOnJvmTargetChange() { + initProject(JVM_MOCK_RUNTIME) + myProject.modules.forEach { + val facet = KotlinFacetSettings() + facet.useProjectSettings = false + facet.compilerArguments = K2JVMCompilerArguments() + (facet.compilerArguments as K2JVMCompilerArguments).jvmTarget = "1.8" + + it.container.setChild( + JpsKotlinFacetModuleExtension.KIND, + JpsKotlinFacetModuleExtension(facet) + ) + } + buildAllModules().assertSuccessful() + myProject.modules.forEach { + val facet = KotlinFacetSettings() + facet.useProjectSettings = false + facet.compilerArguments = K2JVMCompilerArguments() + (facet.compilerArguments as K2JVMCompilerArguments).jvmTarget = "9" + it.container.setChild( + JpsKotlinFacetModuleExtension.KIND, + JpsKotlinFacetModuleExtension(facet) + ) + } + + checkWhen(emptyArray(), null, packageClasses("kotlinProject", "src/test1.kt", "Test1Kt")) + } + + @WorkingDir("KotlinProject") + fun testModuleRebuildOnBackendChange() { + initProject(JVM_MOCK_RUNTIME) + myProject.modules.forEach { + val facet = KotlinFacetSettings() + facet.useProjectSettings = false + facet.compilerArguments = K2JVMCompilerArguments() + (facet.compilerArguments as K2JVMCompilerArguments).useK2 = false + + it.container.setChild( + JpsKotlinFacetModuleExtension.KIND, + JpsKotlinFacetModuleExtension(facet) + ) + } + buildAllModules().assertSuccessful() + myProject.modules.forEach { + val facet = KotlinFacetSettings() + facet.useProjectSettings = false + facet.compilerArguments = K2JVMCompilerArguments() + (facet.compilerArguments as K2JVMCompilerArguments).useK2 = true + it.container.setChild( + JpsKotlinFacetModuleExtension.KIND, + JpsKotlinFacetModuleExtension(facet) + ) + } + + checkWhen(emptyArray(), null, packageClasses("kotlinProject", "src/test1.kt", "Test1Kt")) + } + + @WorkingDir("KotlinProject") + fun testModuleRebuildOnJvmDefaultChange() { + initProject(JVM_MOCK_RUNTIME) + myProject.modules.forEach { + val facet = KotlinFacetSettings() + facet.useProjectSettings = false + facet.compilerArguments = K2JVMCompilerArguments() + (facet.compilerArguments as K2JVMCompilerArguments).jvmDefault = JvmDefaultMode.DEFAULT.description + + it.container.setChild( + JpsKotlinFacetModuleExtension.KIND, + JpsKotlinFacetModuleExtension(facet) + ) + } + buildAllModules().assertSuccessful() + myProject.modules.forEach { + val facet = KotlinFacetSettings() + facet.useProjectSettings = false + facet.compilerArguments = K2JVMCompilerArguments() + (facet.compilerArguments as K2JVMCompilerArguments).jvmDefault = JvmDefaultMode.ALL_COMPATIBILITY.description + it.container.setChild( + JpsKotlinFacetModuleExtension.KIND, + JpsKotlinFacetModuleExtension(facet) + ) + } + + checkWhen(emptyArray(), null, packageClasses("kotlinProject", "src/test1.kt", "Test1Kt")) + } + + @WorkingDir("KotlinProject") + fun testModuleRebuildOnAddJavaMoudlesChange() { + initProject(JVM_MOCK_RUNTIME) + myProject.modules.forEach { + val facet = KotlinFacetSettings() + facet.useProjectSettings = false + facet.compilerArguments = K2JVMCompilerArguments() + + it.container.setChild( + JpsKotlinFacetModuleExtension.KIND, + JpsKotlinFacetModuleExtension(facet) + ) + } + buildAllModules().assertSuccessful() + myProject.modules.forEach { + val facet = KotlinFacetSettings() + facet.useProjectSettings = false + facet.compilerArguments = K2JVMCompilerArguments() + (facet.compilerArguments as K2JVMCompilerArguments).additionalJavaModules = arrayOf("ALL-MODULE-PATH") + it.container.setChild( + JpsKotlinFacetModuleExtension.KIND, + JpsKotlinFacetModuleExtension(facet) + ) + } + + checkWhen(emptyArray(), null, packageClasses("kotlinProject", "src/test1.kt", "Test1Kt")) + } + fun testBuildAfterGdwBuild() { initProject(JVM_FULL_RUNTIME) findModule("module2").let { diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinChunk.kt b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinChunk.kt index c08e8af3768..ff5d8c680e7 100644 --- a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinChunk.kt +++ b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinChunk.kt @@ -139,10 +139,8 @@ class KotlinChunk internal constructor(val context: KotlinCompileContext, val ta } fun shouldRebuild(): Boolean { - val buildMetaInfo = representativeTarget.buildMetaInfoFactory.create(compilerArguments) - targets.forEach { target -> - if (target.isVersionChanged(this, buildMetaInfo)) { + if (target.isVersionChanged(this, compilerArguments)) { KotlinBuilder.LOG.info("$target version changed, rebuilding $this") return true } @@ -157,10 +155,10 @@ class KotlinChunk internal constructor(val context: KotlinCompileContext, val ta return false } - fun buildMetaInfoFile(target: ModuleBuildTarget): Path = context.dataPaths + fun compilerArgumentsFile(target: ModuleBuildTarget): Path = context.dataPaths .getTargetDataRoot(target) .toPath() - .resolve(representativeTarget.buildMetaInfoFileName) + .resolve(representativeTarget.compilerArgumentsFileName) fun saveVersions() { context.ensureLookupsCacheAttributesSaved() @@ -169,10 +167,10 @@ class KotlinChunk internal constructor(val context: KotlinCompileContext, val ta it.initialLocalCacheAttributesDiff.manager.writeVersion() } - val serializedMetaInfo = representativeTarget.buildMetaInfoFactory.serializeToString(compilerArguments) - + val serializedCompilerArguments = representativeTarget.buildMetaInfo.serializeArgsToString(compilerArguments) targets.forEach { target -> - Files.newOutputStream(buildMetaInfoFile(target.jpsModuleBuildTarget)).bufferedWriter().use { it.append(serializedMetaInfo) } + Files.newOutputStream(compilerArgumentsFile(target.jpsModuleBuildTarget)).bufferedWriter() + .use { it.append(serializedCompilerArguments) } } } diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinCompileContext.kt b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinCompileContext.kt index 4ae5c4c4e6f..cf75df7ba2c 100644 --- a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinCompileContext.kt +++ b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinCompileContext.kt @@ -12,6 +12,7 @@ import org.jetbrains.jps.incremental.GlobalContextKey import org.jetbrains.jps.incremental.fs.CompilationRound import org.jetbrains.jps.incremental.messages.BuildMessage import org.jetbrains.jps.incremental.messages.CompilerMessage +import org.jetbrains.kotlin.build.joinToReadableString import org.jetbrains.kotlin.config.CompilerRunnerConstants.KOTLIN_COMPILER_NAME import org.jetbrains.kotlin.incremental.LookupSymbol import org.jetbrains.kotlin.incremental.storage.FileToPathConverter @@ -303,10 +304,3 @@ class KotlinCompileContext(val jpsContext: CompileContext) { } } } - -fun List.joinToReadableString(): String = when { - size > 5 -> take(5).joinToString() + " and ${size - 5} more" - size > 1 -> dropLast(1).joinToString() + " and ${last()}" - size == 1 -> single() - else -> "" -} \ No newline at end of file diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinCommonModuleBuildTarget.kt b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinCommonModuleBuildTarget.kt index 001f9555df9..ee2de736f19 100644 --- a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinCommonModuleBuildTarget.kt +++ b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinCommonModuleBuildTarget.kt @@ -34,12 +34,12 @@ class KotlinCommonModuleBuildTarget(kotlinContext: KotlinCompileContext, jpsModu override val isIncrementalCompilationEnabled: Boolean get() = false - override val buildMetaInfoFactory - get() = CommonBuildMetaInfo - - override val buildMetaInfoFileName + override val compilerArgumentsFileName get() = COMMON_BUILD_META_INFO_FILE_NAME + override val buildMetaInfo: CommonBuildMetaInfo + get() = CommonBuildMetaInfo() + override val globalLookupCacheId: String get() = "metadata-compiler" diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinJsModuleBuildTarget.kt b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinJsModuleBuildTarget.kt index 2e53f7cf9e2..70997609492 100644 --- a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinJsModuleBuildTarget.kt +++ b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinJsModuleBuildTarget.kt @@ -54,12 +54,12 @@ class KotlinJsModuleBuildTarget(kotlinContext: KotlinCompileContext, jpsModuleBu override val isIncrementalCompilationEnabled: Boolean get() = IncrementalCompilation.isEnabledForJs() - override val buildMetaInfoFactory - get() = JsBuildMetaInfo - - override val buildMetaInfoFileName: String + override val compilerArgumentsFileName: String get() = JS_BUILD_META_INFO_FILE_NAME + override val buildMetaInfo: JsBuildMetaInfo + get() = JsBuildMetaInfo() + val isFirstBuild: Boolean get() { val targetDataRoot = jpsGlobalContext.projectDescriptor.dataManager.dataPaths.getTargetDataRoot(jpsModuleBuildTarget) diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinJvmModuleBuildTarget.kt b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinJvmModuleBuildTarget.kt index 0b1aa30ae02..841ad6ff5a1 100644 --- a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinJvmModuleBuildTarget.kt +++ b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinJvmModuleBuildTarget.kt @@ -62,12 +62,12 @@ class KotlinJvmModuleBuildTarget(kotlinContext: KotlinCompileContext, jpsModuleB override fun createCacheStorage(paths: BuildDataPaths) = JpsIncrementalJvmCache(jpsModuleBuildTarget, paths, kotlinContext.fileToPathConverter) - override val buildMetaInfoFactory - get() = JvmBuildMetaInfo - - override val buildMetaInfoFileName + override val compilerArgumentsFileName get() = JVM_BUILD_META_INFO_FILE_NAME + override val buildMetaInfo: JvmBuildMetaInfo + get() = JvmBuildMetaInfo() + override val targetId: TargetId get() { val moduleName = module.k2JvmCompilerArguments.moduleName diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinModuleBuildTarget.kt b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinModuleBuildTarget.kt index d470e96a263..10d9b0067aa 100644 --- a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinModuleBuildTarget.kt +++ b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinModuleBuildTarget.kt @@ -15,9 +15,7 @@ import org.jetbrains.jps.model.java.JpsJavaClasspathKind import org.jetbrains.jps.model.java.JpsJavaExtensionService import org.jetbrains.jps.model.module.JpsModule import org.jetbrains.jps.util.JpsPathUtil -import org.jetbrains.kotlin.build.BuildMetaInfo -import org.jetbrains.kotlin.build.BuildMetaInfoFactory -import org.jetbrains.kotlin.build.GeneratedFile +import org.jetbrains.kotlin.build.* import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity import org.jetbrains.kotlin.compilerRunner.JpsCompilerEnvironment @@ -306,7 +304,7 @@ abstract class KotlinModuleBuildTarget intern ) inner class SourcesToCompile( - sources: Collection, + sources: Collection, val removedFiles: Collection ) { val allFiles = sources.map { it.file } @@ -330,45 +328,36 @@ abstract class KotlinModuleBuildTarget intern } } - abstract val buildMetaInfoFactory: BuildMetaInfoFactory + abstract val compilerArgumentsFileName: String - abstract val buildMetaInfoFileName: String + abstract val buildMetaInfo: BuildMetaInfoType - fun isVersionChanged(chunk: KotlinChunk, buildMetaInfo: BuildMetaInfo): Boolean { - val file = chunk.buildMetaInfoFile(jpsModuleBuildTarget) + fun isVersionChanged(chunk: KotlinChunk, compilerArguments: CommonCompilerArguments): Boolean { + fun printReasonToRebuild(reasonToRebuild: String) { + KotlinBuilder.LOG.info("$reasonToRebuild. Performing non-incremental rebuild (kotlin only)") + } + + val currentCompilerArgumentsMap = buildMetaInfo.createPropertiesMapFromCompilerArguments(compilerArguments) + + val file = chunk.compilerArgumentsFile(jpsModuleBuildTarget) if (Files.notExists(file)) return false - val prevBuildMetaInfo = + val previousCompilerArgsMap = try { - buildMetaInfoFactory.deserializeFromString(Files.newInputStream(file).bufferedReader().use { it.readText() }) - ?: return false + buildMetaInfo.deserializeMapFromString(Files.newInputStream(file).bufferedReader().use { it.readText() }) } catch (e: Exception) { - KotlinBuilder.LOG.error("Could not deserialize build meta info", e) + KotlinBuilder.LOG.error("Could not deserialize previous compiler arguments info", e) return false } - val prevLangVersion = LanguageVersion.fromVersionString(prevBuildMetaInfo.languageVersionString) - val prevApiVersion = ApiVersion.parse(prevBuildMetaInfo.apiVersionString) + val rebuildReason = buildMetaInfo.obtainReasonForRebuild(currentCompilerArgumentsMap, previousCompilerArgsMap) - val reasonToRebuild = when { - chunk.langVersion != prevLangVersion -> "Language version was changed ($prevLangVersion -> ${chunk.langVersion})" - chunk.apiVersion != prevApiVersion -> "Api version was changed ($prevApiVersion -> ${chunk.apiVersion})" - prevLangVersion != LanguageVersion.KOTLIN_1_0 && prevBuildMetaInfo.isEAP && !buildMetaInfo.isEAP -> { - // If EAP->Non-EAP build with IC, then rebuild all kotlin - "Last build was compiled with EAP-plugin" - } - else -> PluginClasspathsComparator( - prevBuildMetaInfo.pluginClasspaths, - buildMetaInfo.pluginClasspaths - ).describeDifferencesOrNull() + return if (rebuildReason != null) { + printReasonToRebuild(rebuildReason) + true + } else { + false } - - if (reasonToRebuild != null) { - KotlinBuilder.LOG.info("$reasonToRebuild. Performing non-incremental rebuild (kotlin only)") - return true - } - - return false } private fun checkRepresentativeTarget(chunk: KotlinChunk) { diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinUnsupportedModuleBuildTarget.kt b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinUnsupportedModuleBuildTarget.kt index a1154e6fc1c..99df21cfce7 100644 --- a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinUnsupportedModuleBuildTarget.kt +++ b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/targets/KotlinUnsupportedModuleBuildTarget.kt @@ -8,7 +8,6 @@ package org.jetbrains.kotlin.jps.targets import org.jetbrains.jps.builders.storage.BuildDataPaths import org.jetbrains.jps.incremental.ModuleBuildTarget import org.jetbrains.kotlin.build.BuildMetaInfo -import org.jetbrains.kotlin.build.BuildMetaInfoFactory import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.compilerRunner.JpsCompilerEnvironment import org.jetbrains.kotlin.jps.build.KotlinCompileContext @@ -50,9 +49,9 @@ class KotlinUnsupportedModuleBuildTarget( shouldNotBeCalled() } - override val buildMetaInfoFactory: BuildMetaInfoFactory + override val compilerArgumentsFileName: String get() = shouldNotBeCalled() - override val buildMetaInfoFileName: String + override val buildMetaInfo: BuildMetaInfo get() = shouldNotBeCalled() } \ No newline at end of file