Attach K/N stdlib sources on MPP project import
Issue #KT-30635:fixed
This commit is contained in:
@@ -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.KONAN_STDLIB_NAME
|
||||||
import org.jetbrains.kotlin.konan.library.lite.LiteKonanLibraryInfoProvider
|
import org.jetbrains.kotlin.konan.library.lite.LiteKonanLibraryInfoProvider
|
||||||
import org.jetbrains.plugins.gradle.ExternalDependencyId
|
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.ExternalDependency
|
||||||
import org.jetbrains.plugins.gradle.model.ExternalLibraryDependency
|
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.FileCollectionDependency
|
||||||
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
|
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
|
||||||
import org.jetbrains.plugins.gradle.service.project.ProjectResolverContext
|
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
|
// 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.
|
// `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<LibraryData, Library>() {
|
class KotlinNativeLibraryDataService : AbstractProjectDataService<LibraryData, Library>() {
|
||||||
override fun getTargetDataKey() = ProjectKeys.LIBRARY
|
override fun getTargetDataKey() = ProjectKeys.LIBRARY
|
||||||
|
|
||||||
@@ -86,7 +87,6 @@ internal class KotlinNativeLibrariesDependencySubstitutor(
|
|||||||
private val gradleModule: IdeaModule,
|
private val gradleModule: IdeaModule,
|
||||||
private val resolverCtx: ProjectResolverContext
|
private val resolverCtx: ProjectResolverContext
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// Substitutes `ExternalDependency` entries that represent KLIBs with new dependency entries with proper type and name:
|
// 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
|
// - 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)
|
// - 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
|
result[i] = newDependency
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val ProjectResolverContext.dependencySubstitutionCache
|
private val ProjectResolverContext.dependencySubstitutionCache
|
||||||
@@ -150,17 +149,18 @@ internal class KotlinNativeLibrariesDependencySubstitutor(
|
|||||||
private fun buildSubstituteIfNecessary(libraryFile: File): DependencySubstitute {
|
private fun buildSubstituteIfNecessary(libraryFile: File): DependencySubstitute {
|
||||||
// need to check whether `libraryFile` points to a real KLIB,
|
// 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
|
// 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 nonNullKotlinVersion = kotlinVersion ?: return NoSubstitute
|
||||||
|
|
||||||
val platformNamePart = libraryInfo.platform?.let { " [$it]" }.orEmpty()
|
val platformNamePart = libraryInfo.platform?.let { " [$it]" }.orEmpty()
|
||||||
val newLibraryName = "$KOTLIN_NATIVE_LIBRARY_PREFIX_PLUS_SPACE$nonNullKotlinVersion - ${libraryInfo.name}$platformNamePart"
|
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
|
classpathOrder = if (libraryInfo.name == KONAN_STDLIB_NAME) -1 else 0 // keep stdlib upper
|
||||||
name = newLibraryName
|
name = newLibraryName
|
||||||
packaging = DEFAULT_PACKAGING
|
packaging = DEFAULT_PACKAGING
|
||||||
file = libraryFile
|
files += libraryInfo.path
|
||||||
|
sources += libraryInfo.sourcePaths
|
||||||
scope = DependencyScope.PROVIDED.name
|
scope = DependencyScope.PROVIDED.name
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,7 +178,6 @@ internal class KotlinNativeLibrariesDependencySubstitutor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal object KotlinNativeLibrariesNameFixer {
|
internal object KotlinNativeLibrariesNameFixer {
|
||||||
|
|
||||||
// Gradle IDE plugin creates `LibraryData` nodes with internal name consisting of two parts:
|
// Gradle IDE plugin creates `LibraryData` nodes with internal name consisting of two parts:
|
||||||
// - mandatory "Gradle: " prefix
|
// - mandatory "Gradle: " prefix
|
||||||
// - and library name
|
// - and library name
|
||||||
@@ -196,7 +195,7 @@ internal object KotlinNativeLibrariesNameFixer {
|
|||||||
|
|
||||||
private sealed class DependencySubstitute {
|
private sealed class DependencySubstitute {
|
||||||
object NoSubstitute : 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"
|
private const val KOTLIN_NATIVE_LIBRARY_PREFIX = "Kotlin/Native"
|
||||||
|
|||||||
+6
-2
@@ -23,12 +23,16 @@ const val KLIB_MANIFEST_FILE_NAME = "manifest"
|
|||||||
const val KONAN_STDLIB_NAME = "stdlib"
|
const val KONAN_STDLIB_NAME = "stdlib"
|
||||||
|
|
||||||
const val KLIB_DIR_NAME = "klib"
|
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
|
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
|
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)
|
fun konanCommonLibraryPath(libraryName: String): Path = KONAN_COMMON_LIBS_PATH.resolve(libraryName)
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@ class LiteKonanDistributionInfoProvider(private val konanHomeDir: String) {
|
|||||||
|
|
||||||
fun getDistributionInfo(): LiteKonanDistribution? {
|
fun getDistributionInfo(): LiteKonanDistribution? {
|
||||||
val stdlibInfo = LiteKonanLibraryInfoProvider(konanHomeDir).getDistributionLibraryInfo(
|
val stdlibInfo = LiteKonanLibraryInfoProvider(konanHomeDir).getDistributionLibraryInfo(
|
||||||
Paths.get(konanHomeDir).resolve(konanCommonLibraryPath(KONAN_STDLIB_NAME))
|
Paths.get(konanHomeDir).resolve(konanCommonLibraryPath(KONAN_STDLIB_NAME)).toFile()
|
||||||
) ?: return null
|
) ?: return null
|
||||||
|
|
||||||
val versionString = stdlibInfo.compilerVersion
|
val versionString = stdlibInfo.compilerVersion
|
||||||
|
|||||||
+3
-2
@@ -5,10 +5,11 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.konan.library.lite
|
package org.jetbrains.kotlin.konan.library.lite
|
||||||
|
|
||||||
import java.nio.file.Path
|
import java.io.File
|
||||||
|
|
||||||
data class LiteKonanLibrary(
|
data class LiteKonanLibrary(
|
||||||
val path: Path,
|
val path: File,
|
||||||
|
val sourcePaths: Collection<File>,
|
||||||
val name: String,
|
val name: String,
|
||||||
val platform: String?,
|
val platform: String?,
|
||||||
internal val compilerVersion: String
|
internal val compilerVersion: String
|
||||||
|
|||||||
+46
-25
@@ -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_MANIFEST_FILE_NAME
|
||||||
import org.jetbrains.kotlin.konan.library.KLIB_PROPERTY_COMPILER_VERSION
|
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.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.io.IOException
|
||||||
import java.nio.file.Files
|
import java.nio.file.Files
|
||||||
import java.nio.file.Path
|
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@@ -37,32 +41,17 @@ class LiteKonanLibraryInfoProvider(customKonanHomeDir: String? = null) {
|
|||||||
* Returns either [LiteKonanLibrary], or null if there is no such library in
|
* Returns either [LiteKonanLibrary], or null if there is no such library in
|
||||||
* Kotlin/Native distribution.
|
* Kotlin/Native distribution.
|
||||||
*/
|
*/
|
||||||
fun getDistributionLibraryInfo(libraryPath: Path): LiteKonanLibrary? {
|
fun getDistributionLibraryInfo(libraryPath: File): LiteKonanLibrary? {
|
||||||
// check whether it under Kotlin/Native root
|
// check whether it under Kotlin/Native root
|
||||||
if (!isUnderKonanRoot(libraryPath))
|
if (!isUnderKonanRoot(libraryPath))
|
||||||
return null
|
return null
|
||||||
|
|
||||||
val manifestFile = libraryPath.resolve(KLIB_MANIFEST_FILE_NAME)
|
val manifestFile = libraryPath.resolve(KLIB_MANIFEST_FILE_NAME).takeIf { it.isFile } ?: return null
|
||||||
if (!Files.isRegularFile(manifestFile))
|
val (platform: String?, dataDir: File) = getPlatformAndDataDir(libraryPath) ?: return null
|
||||||
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 manifestProperties = Properties().apply {
|
val manifestProperties = Properties().apply {
|
||||||
try {
|
try {
|
||||||
Files.newInputStream(manifestFile).use { load(it) }
|
manifestFile.inputStream().use { load(it) }
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -71,13 +60,45 @@ class LiteKonanLibraryInfoProvider(customKonanHomeDir: String? = null) {
|
|||||||
val name = manifestProperties[KLIB_PROPERTY_UNIQUE_NAME]?.toString() ?: return null
|
val name = manifestProperties[KLIB_PROPERTY_UNIQUE_NAME]?.toString() ?: return null
|
||||||
val compilerVersion = manifestProperties[KLIB_PROPERTY_COMPILER_VERSION]?.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 {
|
private fun isUnderKonanRoot(libraryPath: File): Boolean {
|
||||||
if (konanHomeDir != null && libraryPath.startsWith(konanHomeDir))
|
with(libraryPath.toPath()) {
|
||||||
return true
|
if (konanHomeDir != null && startsWith(konanHomeDir))
|
||||||
|
return true
|
||||||
|
|
||||||
return libraryPath.startsWith(konanDataDir)
|
return startsWith(konanDataDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getPlatformAndDataDir(libraryPath: File): Pair<String?, File>? {
|
||||||
|
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<File> {
|
||||||
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user