diff --git a/build-common/src/org/jetbrains/kotlin/build/BuildMetaInfo.kt b/build-common/src/org/jetbrains/kotlin/build/BuildMetaInfo.kt index f6872c701bc..9069c76ab3e 100644 --- a/build-common/src/org/jetbrains/kotlin/build/BuildMetaInfo.kt +++ b/build-common/src/org/jetbrains/kotlin/build/BuildMetaInfo.kt @@ -7,8 +7,9 @@ package org.jetbrains.kotlin.build import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.config.* +import org.jetbrains.kotlin.incremental.storage.RelativeFileToPathConverter -abstract class BuildMetaInfo { +abstract class BuildMetaInfo(val converter: RelativeFileToPathConverter?) { enum class CustomKeys { LANGUAGE_VERSION_STRING, IS_EAP, METADATA_VERSION_STRING, PLUGIN_CLASSPATHS, API_VERSION_STRING } @@ -44,7 +45,7 @@ abstract class BuildMetaInfo { 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() + CustomKeys.PLUGIN_CLASSPATHS.name -> return !PluginClasspathComparator(previousValue, currentValue).equals() } // check keys that are sensitive for true -> false change @@ -77,8 +78,8 @@ abstract class BuildMetaInfo { val apiVersionString = args.apiVersion ?: languageVersionSting resultMap[CustomKeys.API_VERSION_STRING.name] = apiVersionString - val pluginClasspaths = PluginClasspaths(args.pluginClasspaths).serialize() - resultMap[CustomKeys.PLUGIN_CLASSPATHS.name] = pluginClasspaths + val pluginClasspath = PluginClasspath(args.pluginClasspaths, converter).serialize() + resultMap[CustomKeys.PLUGIN_CLASSPATHS.name] = pluginClasspath return resultMap } diff --git a/build-common/src/org/jetbrains/kotlin/build/CommonBuildMetaInfo.kt b/build-common/src/org/jetbrains/kotlin/build/CommonBuildMetaInfo.kt index 34e2e99c751..dbed81d3c1c 100644 --- a/build-common/src/org/jetbrains/kotlin/build/CommonBuildMetaInfo.kt +++ b/build-common/src/org/jetbrains/kotlin/build/CommonBuildMetaInfo.kt @@ -6,10 +6,11 @@ package org.jetbrains.kotlin.build import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments +import org.jetbrains.kotlin.incremental.storage.RelativeFileToPathConverter import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion -class CommonBuildMetaInfo : BuildMetaInfo() { +class CommonBuildMetaInfo(converter: RelativeFileToPathConverter?) : BuildMetaInfo(converter) { override fun checkIfPlatformSpecificCompilerArgumentWasChanged(key: String, currentValue: String, previousValue: String): Boolean? { when (key) { CustomKeys.METADATA_VERSION_STRING.name -> { diff --git a/build-common/src/org/jetbrains/kotlin/build/JsBuildMetaInfo.kt b/build-common/src/org/jetbrains/kotlin/build/JsBuildMetaInfo.kt index 54bb9c9587a..6f979ad2f3a 100644 --- a/build-common/src/org/jetbrains/kotlin/build/JsBuildMetaInfo.kt +++ b/build-common/src/org/jetbrains/kotlin/build/JsBuildMetaInfo.kt @@ -6,10 +6,11 @@ package org.jetbrains.kotlin.build import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments +import org.jetbrains.kotlin.incremental.storage.RelativeFileToPathConverter import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion import org.jetbrains.kotlin.utils.JsMetadataVersion -class JsBuildMetaInfo : BuildMetaInfo() { +class JsBuildMetaInfo(converter: RelativeFileToPathConverter?) : BuildMetaInfo(converter) { override fun checkIfPlatformSpecificCompilerArgumentWasChanged(key: String, currentValue: String, previousValue: String): Boolean? { when (key) { CustomKeys.METADATA_VERSION_STRING.name -> { diff --git a/build-common/src/org/jetbrains/kotlin/build/JvmBuildMetaInfo.kt b/build-common/src/org/jetbrains/kotlin/build/JvmBuildMetaInfo.kt index 34f49496106..b8a62651ae8 100644 --- a/build-common/src/org/jetbrains/kotlin/build/JvmBuildMetaInfo.kt +++ b/build-common/src/org/jetbrains/kotlin/build/JvmBuildMetaInfo.kt @@ -17,10 +17,11 @@ package org.jetbrains.kotlin.build import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments +import org.jetbrains.kotlin.incremental.storage.RelativeFileToPathConverter import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion -class JvmBuildMetaInfo : BuildMetaInfo() { +class JvmBuildMetaInfo(converter: RelativeFileToPathConverter?) : BuildMetaInfo(converter) { override fun checkIfPlatformSpecificCompilerArgumentWasChanged(key: String, currentValue: String, previousValue: String): Boolean? { when (key) { CustomKeys.METADATA_VERSION_STRING.name -> { diff --git a/compiler/util/src/org/jetbrains/kotlin/config/PluginClasspathsUtils.kt b/build-common/src/org/jetbrains/kotlin/build/PluginClasspathsUtils.kt similarity index 52% rename from compiler/util/src/org/jetbrains/kotlin/config/PluginClasspathsUtils.kt rename to build-common/src/org/jetbrains/kotlin/build/PluginClasspathsUtils.kt index ae1e303326f..b05d879cf19 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/PluginClasspathsUtils.kt +++ b/build-common/src/org/jetbrains/kotlin/build/PluginClasspathsUtils.kt @@ -1,15 +1,16 @@ /* - * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2023 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 +package org.jetbrains.kotlin.build +import org.jetbrains.kotlin.incremental.storage.RelativeFileToPathConverter import java.io.File import java.security.DigestInputStream import java.security.MessageDigest -class PluginClasspaths(val classpaths: Array?) { +internal class PluginClasspath(private val classpath: Array?, val converter: RelativeFileToPathConverter?) { companion object { fun deserializeWithHashes(str: String): List> = str.split(":") @@ -17,9 +18,9 @@ class PluginClasspaths(val classpaths: Array?) { .map { Pair(File(it.substringBeforeLast("-")).name, it.substringAfterLast("-")) } } - fun serialize() = classpaths?.mapNotNull { it -> + fun serialize() = classpath?.mapNotNull { it -> val jar = File(it).takeIf { it.exists() } ?: return@mapNotNull null - val jarPath = jar.absolutePath + val jarPath = converter?.toPath(jar) ?: jar.absolutePath val jarHash = jar.sha256() "$jarPath-$jarHash" }?.joinToString(":") ?: "" @@ -40,27 +41,10 @@ class PluginClasspaths(val classpaths: Array?) { } } -class PluginClasspathsComparator(old: String, new: String) { - private val oldPluginClasspath: List> by lazy { PluginClasspaths.deserializeWithHashes(old) } - private val newPluginClasspath: List> by lazy { PluginClasspaths.deserializeWithHashes(new) } +internal class PluginClasspathComparator(old: String, new: String) { + private val oldPluginClasspath: List> by lazy { PluginClasspath.deserializeWithHashes(old) } + private val newPluginClasspath: List> by lazy { PluginClasspath.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() - } } diff --git a/jps/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/RelocatableJpsCachesTest.kt b/jps/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/RelocatableJpsCachesTest.kt index 382f4b974b0..08784a06e89 100644 --- a/jps/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/RelocatableJpsCachesTest.kt +++ b/jps/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/RelocatableJpsCachesTest.kt @@ -11,11 +11,17 @@ import org.jetbrains.jps.builders.* import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor import org.jetbrains.jps.cmdline.ProjectDescriptor import org.jetbrains.jps.incremental.ModuleBuildTarget +import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments +import org.jetbrains.kotlin.config.KotlinFacetSettings import org.jetbrains.kotlin.incremental.KOTLIN_CACHE_DIRECTORY_NAME import org.jetbrains.kotlin.incremental.testingUtils.assertEqualDirectories import org.jetbrains.kotlin.jps.build.fixtures.EnableICFixture import org.jetbrains.kotlin.jps.incremental.KotlinDataContainerTarget +import org.jetbrains.kotlin.jps.model.JpsKotlinFacetModuleExtension +import org.jetbrains.kotlin.test.MockLibraryUtilExt import java.io.File +import java.nio.file.Files +import java.nio.file.StandardCopyOption import kotlin.io.path.ExperimentalPathApi import kotlin.io.path.createTempDirectory import kotlin.reflect.KFunction1 @@ -43,6 +49,11 @@ class RelocatableJpsCachesTest : BaseKotlinJpsBuildTestCase() { buildTwiceAndCompare(RelocatableCacheTestCase::testRelocatableCaches) } + + fun testRelocatablePluginClasspath() { + buildTwiceAndCompare(RelocatableCacheTestCase::testRelocatablePluginClasspath) + } + private fun buildTwiceAndCompare(testMethod: KFunction1) { val test1WorkingDir = workingDir.resolve("test1") val test1KotlinCachesDir = workingDir.resolve("test1KotlinCaches") @@ -91,6 +102,39 @@ abstract class RelocatableCacheTestCase( ) } + @WorkingDir("KotlinProject") + fun testRelocatablePluginClasspath() { + initProject(LibraryDependency.JVM_FULL_RUNTIME) + + //create lib + val libraryName = "module1-1.0-SNAPSHOT" + val libraryJar = MockLibraryUtilExt.compileJvmLibraryToJar(workDir.resolve("non-existent-folder").absolutePath, libraryName) + val module1Lib = this.workDir.resolve("lib").resolve("$libraryName.jar") + Files.createDirectories(module1Lib.parentFile.toPath()) + Files.copy(libraryJar.toPath(), module1Lib.toPath(), StandardCopyOption.REPLACE_EXISTING) + assert(module1Lib.exists()) + + // Add facet + myProject.modules.forEach { + val facet = KotlinFacetSettings() + facet.useProjectSettings = false + facet.compilerArguments = K2JVMCompilerArguments().apply { + pluginClasspaths = arrayOf(module1Lib.absolutePath) + } + + it.container.setChild( + JpsKotlinFacetModuleExtension.KIND, + JpsKotlinFacetModuleExtension(facet) + ) + } + buildAllModules().assertSuccessful() + + assertFilesExistInOutput( + myProject.modules.single(), + "Test1Kt.class" + ) + } + override fun copyTestDataToTmpDir(testDataDir: File): File { testDataDir.copyRecursively(projectWorkingDir) return projectWorkingDir @@ -115,6 +159,8 @@ abstract class RelocatableCacheTestCase( kotlinDataPaths.add(kotlinDataRoot) } + findFileInDirectory(descriptor.dataManager.dataPaths.dataStorageRoot, "jvm-build-meta-info.txt")!!.also { kotlinDataPaths.add(it) } + dirToCopyKotlinCaches.deleteRecursively() val originalStorageRoot = descriptor.dataManager.dataPaths.dataStorageRoot for (kotlinCacheRoot in kotlinDataPaths) { @@ -125,6 +171,27 @@ abstract class RelocatableCacheTestCase( } } + private fun findFileInDirectory(directory: File, fileNameToFind: String): File? { + val foundFiles = directory.listFiles { file -> + file.isFile && file.name == fileNameToFind + } ?: return null + + if (foundFiles.isNotEmpty()) { + return foundFiles.firstOrNull() + } + + val subdirectories = directory.listFiles { file -> file.isDirectory } ?: return null + + for (subdirectory in subdirectories) { + val foundFile = findFileInDirectory(subdirectory, fileNameToFind) + if (foundFile != null) { + return foundFile + } + } + + return null + } + private fun BuildTarget<*>.isKotlinTarget(descriptor: ProjectDescriptor): Boolean { fun JavaSourceRootDescriptor.containsKotlinSources() = root.walk().any { it.isKotlinSourceFile } 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 fb6a9046ed2..b015a5a6db2 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 @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.K2MetadataCompilerArguments import org.jetbrains.kotlin.compilerRunner.JpsCompilerEnvironment import org.jetbrains.kotlin.compilerRunner.JpsKotlinCompilerRunner +import org.jetbrains.kotlin.incremental.storage.RelativeFileToPathConverter import org.jetbrains.kotlin.jps.build.KotlinCompileContext import org.jetbrains.kotlin.jps.build.KotlinDirtySourceFilesHolder import org.jetbrains.kotlin.jps.build.ModuleBuildTarget @@ -38,7 +39,7 @@ class KotlinCommonModuleBuildTarget(kotlinContext: KotlinCompileContext, jpsModu get() = COMMON_BUILD_META_INFO_FILE_NAME override val buildMetaInfo: CommonBuildMetaInfo - get() = CommonBuildMetaInfo() + get() = CommonBuildMetaInfo(kotlinContext.fileToPathConverter as? RelativeFileToPathConverter) 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 e91e10d7506..9e0d4a0c8a6 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 @@ -25,6 +25,7 @@ import org.jetbrains.kotlin.incremental.js.IncrementalDataProvider import org.jetbrains.kotlin.incremental.js.IncrementalDataProviderFromCache import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumer import org.jetbrains.kotlin.incremental.js.IncrementalResultsConsumerImpl +import org.jetbrains.kotlin.incremental.storage.RelativeFileToPathConverter import org.jetbrains.kotlin.jps.build.KotlinCompileContext import org.jetbrains.kotlin.jps.build.KotlinDirtySourceFilesHolder import org.jetbrains.kotlin.jps.build.ModuleBuildTarget @@ -55,7 +56,7 @@ class KotlinJsModuleBuildTarget(kotlinContext: KotlinCompileContext, jpsModuleBu get() = JS_BUILD_META_INFO_FILE_NAME override val buildMetaInfo: JsBuildMetaInfo - get() = JsBuildMetaInfo() + get() = JsBuildMetaInfo(kotlinContext.fileToPathConverter as? RelativeFileToPathConverter) val isFirstBuild: Boolean get() { 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 9c6145e2371..25fb049e5ad 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 @@ -29,6 +29,7 @@ import org.jetbrains.kotlin.config.IncrementalCompilation import org.jetbrains.kotlin.config.Services import org.jetbrains.kotlin.incremental.* import org.jetbrains.kotlin.incremental.components.* +import org.jetbrains.kotlin.incremental.storage.RelativeFileToPathConverter import org.jetbrains.kotlin.jps.build.KotlinBuilder import org.jetbrains.kotlin.jps.build.KotlinCompileContext import org.jetbrains.kotlin.jps.build.KotlinDirtySourceFilesHolder @@ -64,7 +65,7 @@ class KotlinJvmModuleBuildTarget(kotlinContext: KotlinCompileContext, jpsModuleB get() = JVM_BUILD_META_INFO_FILE_NAME override val buildMetaInfo: JvmBuildMetaInfo - get() = JvmBuildMetaInfo() + get() = JvmBuildMetaInfo(kotlinContext.fileToPathConverter as? RelativeFileToPathConverter) override val targetId: TargetId get() {