diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/nativeLibrariesUtil.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/nativeLibrariesUtil.kt index da45b977355..2261c1dce73 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/nativeLibrariesUtil.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/nativeLibrariesUtil.kt @@ -29,9 +29,10 @@ import org.jetbrains.kotlin.idea.inspections.gradle.findKotlinPluginVersion import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME import org.jetbrains.kotlin.konan.library.lite.LiteKonanLibraryInfoProvider import org.jetbrains.plugins.gradle.ExternalDependencyId -import org.jetbrains.plugins.gradle.model.DefaultExternalLibraryDependency +import org.jetbrains.plugins.gradle.model.DefaultExternalMultiLibraryDependency import org.jetbrains.plugins.gradle.model.ExternalDependency import org.jetbrains.plugins.gradle.model.ExternalLibraryDependency +import org.jetbrains.plugins.gradle.model.ExternalMultiLibraryDependency import org.jetbrains.plugins.gradle.model.FileCollectionDependency import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData import org.jetbrains.plugins.gradle.service.project.ProjectResolverContext @@ -39,7 +40,7 @@ import java.io.File // KT-30490. This `ProjectDataService` must be executed immediately after // `com.intellij.openapi.externalSystem.service.project.manage.LibraryDataService` to clean-up KLIBs before any other actions taken on them. -@Order(ExternalSystemConstants.BUILTIN_LIBRARY_DATA_SERVICE_ORDER + 1) // force +@Order(ExternalSystemConstants.BUILTIN_LIBRARY_DATA_SERVICE_ORDER + 1) // force order class KotlinNativeLibraryDataService : AbstractProjectDataService() { override fun getTargetDataKey() = ProjectKeys.LIBRARY @@ -86,7 +87,6 @@ internal class KotlinNativeLibrariesDependencySubstitutor( private val gradleModule: IdeaModule, private val resolverCtx: ProjectResolverContext ) { - // Substitutes `ExternalDependency` entries that represent KLIBs with new dependency entries with proper type and name: // - every `FileCollectionDependency` is checked whether it points to an existing KLIB, and substituted if it is // - similarly for every `ExternalLibraryDependency` with `groupId == "Kotlin/Native"` (legacy KLIB provided by Gradle plugin <= 1.3.20) @@ -104,7 +104,6 @@ internal class KotlinNativeLibrariesDependencySubstitutor( result[i] = newDependency } return result - } private val ProjectResolverContext.dependencySubstitutionCache @@ -150,17 +149,18 @@ internal class KotlinNativeLibrariesDependencySubstitutor( private fun buildSubstituteIfNecessary(libraryFile: File): DependencySubstitute { // need to check whether `libraryFile` points to a real KLIB, // and if answer is yes then build a new dependency that will substitute original one - val libraryInfo = libraryInfoProvider.getDistributionLibraryInfo(libraryFile.toPath()) ?: return NoSubstitute + val libraryInfo = libraryInfoProvider.getDistributionLibraryInfo(libraryFile) ?: return NoSubstitute val nonNullKotlinVersion = kotlinVersion ?: return NoSubstitute val platformNamePart = libraryInfo.platform?.let { " [$it]" }.orEmpty() val newLibraryName = "$KOTLIN_NATIVE_LIBRARY_PREFIX_PLUS_SPACE$nonNullKotlinVersion - ${libraryInfo.name}$platformNamePart" - val substitute = DefaultExternalLibraryDependency().apply { + val substitute = DefaultExternalMultiLibraryDependency().apply { classpathOrder = if (libraryInfo.name == KONAN_STDLIB_NAME) -1 else 0 // keep stdlib upper name = newLibraryName packaging = DEFAULT_PACKAGING - file = libraryFile + files += libraryInfo.path + sources += libraryInfo.sourcePaths scope = DependencyScope.PROVIDED.name } @@ -178,7 +178,6 @@ internal class KotlinNativeLibrariesDependencySubstitutor( } internal object KotlinNativeLibrariesNameFixer { - // Gradle IDE plugin creates `LibraryData` nodes with internal name consisting of two parts: // - mandatory "Gradle: " prefix // - and library name @@ -196,7 +195,7 @@ internal object KotlinNativeLibrariesNameFixer { private sealed class DependencySubstitute { object NoSubstitute : DependencySubstitute() - class YesSubstitute(val substitute: ExternalLibraryDependency) : DependencySubstitute() + class YesSubstitute(val substitute: ExternalMultiLibraryDependency) : DependencySubstitute() } private const val KOTLIN_NATIVE_LIBRARY_PREFIX = "Kotlin/Native" diff --git a/konan/library-reader/src/org/jetbrains/kotlin/konan/library/KonanLibraryConstants.kt b/konan/library-reader/src/org/jetbrains/kotlin/konan/library/KonanLibraryConstants.kt index f387946e55c..67bf732e6a0 100644 --- a/konan/library-reader/src/org/jetbrains/kotlin/konan/library/KonanLibraryConstants.kt +++ b/konan/library-reader/src/org/jetbrains/kotlin/konan/library/KonanLibraryConstants.kt @@ -23,12 +23,16 @@ const val KLIB_MANIFEST_FILE_NAME = "manifest" const val KONAN_STDLIB_NAME = "stdlib" const val KLIB_DIR_NAME = "klib" +const val KONAN_COMMON_LIBS_DIR_NAME = "common" +const val KONAN_PLATFORM_LIBS_DIR_NAME = "platform" + +const val KONAN_SOURCES_DIR_NAME = "sources" val KONAN_COMMON_LIBS_PATH: Path - get() = Paths.get(KLIB_DIR_NAME, "common") + get() = Paths.get(KLIB_DIR_NAME, KONAN_COMMON_LIBS_DIR_NAME) val KONAN_ALL_PLATFORM_LIBS_PATH: Path - get() = Paths.get(KLIB_DIR_NAME, "platform") + get() = Paths.get(KLIB_DIR_NAME, KONAN_PLATFORM_LIBS_DIR_NAME) fun konanCommonLibraryPath(libraryName: String): Path = KONAN_COMMON_LIBS_PATH.resolve(libraryName) diff --git a/konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanDistributionInfoProvider.kt b/konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanDistributionInfoProvider.kt index 78e1b49a42c..50a11c5075a 100644 --- a/konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanDistributionInfoProvider.kt +++ b/konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanDistributionInfoProvider.kt @@ -13,7 +13,7 @@ class LiteKonanDistributionInfoProvider(private val konanHomeDir: String) { fun getDistributionInfo(): LiteKonanDistribution? { val stdlibInfo = LiteKonanLibraryInfoProvider(konanHomeDir).getDistributionLibraryInfo( - Paths.get(konanHomeDir).resolve(konanCommonLibraryPath(KONAN_STDLIB_NAME)) + Paths.get(konanHomeDir).resolve(konanCommonLibraryPath(KONAN_STDLIB_NAME)).toFile() ) ?: return null val versionString = stdlibInfo.compilerVersion diff --git a/konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanLibrary.kt b/konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanLibrary.kt index f41f6cbe6f7..c6746f3a2dc 100644 --- a/konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanLibrary.kt +++ b/konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanLibrary.kt @@ -5,10 +5,11 @@ package org.jetbrains.kotlin.konan.library.lite -import java.nio.file.Path +import java.io.File data class LiteKonanLibrary( - val path: Path, + val path: File, + val sourcePaths: Collection, val name: String, val platform: String?, internal val compilerVersion: String diff --git a/konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanLibraryInfoProvider.kt b/konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanLibraryInfoProvider.kt index 62d5fc152e5..6a836960009 100644 --- a/konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanLibraryInfoProvider.kt +++ b/konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanLibraryInfoProvider.kt @@ -9,9 +9,13 @@ import org.jetbrains.kotlin.konan.library.KLIB_DIR_NAME import org.jetbrains.kotlin.konan.library.KLIB_MANIFEST_FILE_NAME import org.jetbrains.kotlin.konan.library.KLIB_PROPERTY_COMPILER_VERSION import org.jetbrains.kotlin.konan.library.KLIB_PROPERTY_UNIQUE_NAME +import org.jetbrains.kotlin.konan.library.KONAN_COMMON_LIBS_DIR_NAME +import org.jetbrains.kotlin.konan.library.KONAN_PLATFORM_LIBS_DIR_NAME +import org.jetbrains.kotlin.konan.library.KONAN_SOURCES_DIR_NAME +import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME +import java.io.File import java.io.IOException import java.nio.file.Files -import java.nio.file.Path import java.nio.file.Paths import java.util.* @@ -37,32 +41,17 @@ class LiteKonanLibraryInfoProvider(customKonanHomeDir: String? = null) { * Returns either [LiteKonanLibrary], or null if there is no such library in * Kotlin/Native distribution. */ - fun getDistributionLibraryInfo(libraryPath: Path): LiteKonanLibrary? { + fun getDistributionLibraryInfo(libraryPath: File): LiteKonanLibrary? { // check whether it under Kotlin/Native root if (!isUnderKonanRoot(libraryPath)) return null - val manifestFile = libraryPath.resolve(KLIB_MANIFEST_FILE_NAME) - if (!Files.isRegularFile(manifestFile)) - return null - - val parentPath = libraryPath.parent ?: return null - val parentName = parentPath.toFile().name - - val platform = when (parentName) { - "common" -> null - else -> { - val grandParentName = parentPath.parent?.toFile()?.name ?: return null - when (grandParentName) { - "platform" -> parentName - else -> return null - } - } - } + val manifestFile = libraryPath.resolve(KLIB_MANIFEST_FILE_NAME).takeIf { it.isFile } ?: return null + val (platform: String?, dataDir: File) = getPlatformAndDataDir(libraryPath) ?: return null val manifestProperties = Properties().apply { try { - Files.newInputStream(manifestFile).use { load(it) } + manifestFile.inputStream().use { load(it) } } catch (e: IOException) { return null } @@ -71,13 +60,45 @@ class LiteKonanLibraryInfoProvider(customKonanHomeDir: String? = null) { val name = manifestProperties[KLIB_PROPERTY_UNIQUE_NAME]?.toString() ?: return null val compilerVersion = manifestProperties[KLIB_PROPERTY_COMPILER_VERSION]?.toString() ?: return null - return LiteKonanLibrary(libraryPath, name, platform, compilerVersion) + val sourcePaths = if (name == KONAN_STDLIB_NAME) getStdlibSources(dataDir) else emptyList() + + return LiteKonanLibrary(libraryPath, sourcePaths, name, platform, compilerVersion) } - private fun isUnderKonanRoot(libraryPath: Path): Boolean { - if (konanHomeDir != null && libraryPath.startsWith(konanHomeDir)) - return true + private fun isUnderKonanRoot(libraryPath: File): Boolean { + with(libraryPath.toPath()) { + if (konanHomeDir != null && startsWith(konanHomeDir)) + return true - return libraryPath.startsWith(konanDataDir) + return startsWith(konanDataDir) + } + } + + private fun getPlatformAndDataDir(libraryPath: File): Pair? { + val parentDir = libraryPath.parentFile ?: return null + val parentDirName = parentDir.name + + fun getDataDir(platformDir: File): File = platformDir.parentFile.parentFile + + return when (parentDirName) { + KONAN_COMMON_LIBS_DIR_NAME -> null to getDataDir(parentDir) + else -> { + val grandParentDir = parentDir.parentFile ?: return null + when { + grandParentDir.name == KONAN_PLATFORM_LIBS_DIR_NAME -> parentDirName to getDataDir(grandParentDir) + else -> return null + } + } + } + } + + private fun getStdlibSources(dataDir: File): Collection { + val sourcesDir = dataDir.resolve(KONAN_SOURCES_DIR_NAME).takeIf { it.isDirectory } ?: return emptyList() + + return sourcesDir.walkTopDown().maxDepth(1) + .filter { it.isFile } + .filter { + with(it.name) { endsWith(".zip") && (startsWith("kotlin-stdlib") || startsWith("kotlin-test")) } + }.toList() } }