From 07f6059f4403f515e658f70ac9448862ff953e3e Mon Sep 17 00:00:00 2001 From: Dmitriy Dolovov Date: Fri, 26 Apr 2019 19:57:14 +0700 Subject: [PATCH] Refactor "lite" API for Kotlin/Native libraries --- .../idea/configuration/nativeLibrariesUtil.kt | 22 +-- .../library/lite/LiteKonanDistribution.kt | 11 +- .../lite/LiteKonanDistributionInfoProvider.kt | 37 ----- .../lite/LiteKonanDistributionProvider.kt | 24 +++ .../konan/library/lite/LiteKonanLibrary.kt | 13 +- .../library/lite/LiteKonanLibraryFacade.kt | 137 ++++++++++++++++++ .../lite/LiteKonanLibraryInfoProvider.kt | 104 ------------- 7 files changed, 186 insertions(+), 162 deletions(-) delete mode 100644 konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanDistributionInfoProvider.kt create mode 100644 konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanDistributionProvider.kt create mode 100644 konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanLibraryFacade.kt delete mode 100644 konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanLibraryInfoProvider.kt 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 3511e29c3f8..f7d06c69c5f 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,7 +29,7 @@ import org.jetbrains.kotlin.idea.configuration.DependencySubstitute.NoSubstitute import org.jetbrains.kotlin.idea.configuration.DependencySubstitute.YesSubstitute 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.kotlin.konan.library.lite.LiteKonanLibraryFacade import org.jetbrains.plugins.gradle.ExternalDependencyId import org.jetbrains.plugins.gradle.model.DefaultExternalMultiLibraryDependency import org.jetbrains.plugins.gradle.model.ExternalDependency @@ -86,7 +86,7 @@ class KotlinNativeLibraryDataService : AbstractProjectDataService listOf(it[0], it[1], "0") - 3 -> it - else -> null - } - } - ?.mapNotNull { it.toIntOrNull() } - ?.takeIf { it.size == 3 } - ?.let { - KotlinVersion(it[0], it[1], it[2]) - } ?: return null - - return LiteKonanDistribution(konanHomeDir, version, versionString) - } -} diff --git a/konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanDistributionProvider.kt b/konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanDistributionProvider.kt new file mode 100644 index 00000000000..a36a7be0c4d --- /dev/null +++ b/konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanDistributionProvider.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2010-2019 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.konan.library.lite + +import org.jetbrains.kotlin.konan.KonanVersion +import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME +import org.jetbrains.kotlin.konan.library.konanCommonLibraryPath +import java.io.File + +object LiteKonanDistributionProvider { + fun getDistribution(konanHomeDir: File): LiteKonanDistribution? { + val stdlib = LiteKonanLibraryFacade.getDistributionLibraryProvider(konanHomeDir) + .getLibrary(konanHomeDir.resolve(konanCommonLibraryPath(KONAN_STDLIB_NAME).toFile())) as? LiteKonanLibraryImpl ?: return null + + return LiteKonanDistribution( + konanHomeDir, + KonanVersion.fromString(stdlib.compilerVersion), + stdlib.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 1ac49bfe775..c51b7696044 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 @@ -7,10 +7,9 @@ package org.jetbrains.kotlin.konan.library.lite import java.io.File -data class LiteKonanLibrary( - val path: File, - val sourcePaths: Collection, - val name: String, - val platform: String?, - internal val compilerVersion: String -) +interface LiteKonanLibrary { + val path: File + val sourcePaths: Collection + val name: String + val platform: String? +} diff --git a/konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanLibraryFacade.kt b/konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanLibraryFacade.kt new file mode 100644 index 00000000000..b152fcfa24f --- /dev/null +++ b/konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanLibraryFacade.kt @@ -0,0 +1,137 @@ +/* + * Copyright 2010-2019 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.konan.library.lite + +import org.jetbrains.kotlin.konan.library.* +import java.io.File +import java.io.IOException +import java.nio.file.Path +import java.nio.file.Paths +import java.util.* + +// TODO: agree how to distinguish between Native and non-Native (ex: JS) KLIBs +object LiteKonanLibraryFacade { + /** + * Use this [LiteKonanLibraryProvider] to get information about any Kotlin/Native library. + */ + fun getLibraryProvider(): LiteKonanLibraryProvider = DefaultLiteKonanLibraryProvider + + /** + * Use this [LiteKonanLibraryProvider] to get information about libraries inside of Kotlin/Native distribution. + */ + fun getDistributionLibraryProvider(customKonanHomeDir: File?): LiteKonanLibraryProvider = + FromDistributionLiteKonanLibraryProvider(customKonanHomeDir) + +} + +interface LiteKonanLibraryProvider { + /** + * Returns either [LiteKonanLibrary], or null if path does not point to a valid Kotlin/Native library + * or the current [LiteKonanLibraryProvider] does not accept the library due to internal restrictions. + */ + fun getLibrary(libraryPath: File): LiteKonanLibrary? +} + +private object DefaultLiteKonanLibraryProvider : LiteKonanLibraryProvider { + override fun getLibrary(libraryPath: File): LiteKonanLibraryImpl? { + val manifest = loadManifest(libraryPath) ?: return null + + val name = manifest.getProperty(KLIB_PROPERTY_UNIQUE_NAME) ?: return null + val compilerVersion = manifest.getProperty(KLIB_PROPERTY_COMPILER_VERSION) ?: return null + + return LiteKonanLibraryImpl( + path = libraryPath, + name = name, + compilerVersion = compilerVersion + ) + } + + private fun loadManifest(libraryPath: File): Properties? { + val manifestFile = libraryPath.resolve(KLIB_MANIFEST_FILE_NAME).takeIf { it.isFile } ?: return null + + return try { + manifestFile.inputStream().use { Properties().apply { load(it) } } + } catch (_: IOException) { + return null + } + } +} + +private class FromDistributionLiteKonanLibraryProvider(customKonanHomeDir: File?) : LiteKonanLibraryProvider { + private val konanHomeDir: Path? by lazy { + customKonanHomeDir?.takeIf { + // small sanity check to ensure that it's a valid Kotlin/Native home directory + customKonanHomeDir.resolve(KLIB_DIR_NAME).isDirectory + }?.toPath() + } + + private val konanDataDir: Path by lazy { + val path = System.getenv("KONAN_DATA_DIR")?.let { Paths.get(it) } + ?: Paths.get(System.getProperty("user.home"), ".konan") + path.toAbsolutePath() + } + + override fun getLibrary(libraryPath: File): LiteKonanLibrary? { + // check whether it under Kotlin/Native root + if (!isUnderKonanRoot(libraryPath)) return null + + val library = DefaultLiteKonanLibraryProvider.getLibrary(libraryPath) ?: return null + + val (platform: String?, dataDir: File) = getPlatformAndDataDir(libraryPath) ?: return null + library.platform = platform + + if (library.name == KONAN_STDLIB_NAME) + library.sourcePaths = getStdlibSources(dataDir) + + return library + } + + private fun isUnderKonanRoot(libraryPath: File): Boolean { + with(libraryPath.toPath()) { + if (konanHomeDir != null && startsWith(konanHomeDir)) + return true + + 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() + } +} + +internal class LiteKonanLibraryImpl( + override val path: File, + override val name: String, + internal val compilerVersion: String +) : LiteKonanLibrary { + override var platform: String? = null + override var sourcePaths: Collection = emptyList() +} 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 deleted file mode 100644 index 79ba81ac905..00000000000 --- a/konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanLibraryInfoProvider.kt +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2010-2019 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.konan.library.lite - -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.Paths -import java.util.* - -class LiteKonanLibraryInfoProvider(customKonanHomeDir: String? = null) { - - private val konanHomeDir by lazy { - customKonanHomeDir - ?.takeIf { it.isNotEmpty() } - ?.let { Paths.get(it) } - ?.takeIf { - // small sanity check to ensure that it's a valid Kotlin/Native home directory - Files.isDirectory(it.resolve(KLIB_DIR_NAME)) - } - } - - private val konanDataDir by lazy { - val path = System.getenv("KONAN_DATA_DIR")?.let { Paths.get(it) } - ?: Paths.get(System.getProperty("user.home"), ".konan") - path.toAbsolutePath() - } - - /** - * Returns either [LiteKonanLibrary], or null if there is no such library in - * Kotlin/Native distribution. - */ - 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).takeIf { it.isFile } ?: return null - val (platform: String?, dataDir: File) = getPlatformAndDataDir(libraryPath) ?: return null - - val manifestProperties = Properties().apply { - try { - manifestFile.inputStream().use { load(it) } - } catch (e: IOException) { - return null - } - } - - val name = manifestProperties[KLIB_PROPERTY_UNIQUE_NAME]?.toString() ?: return null - val compilerVersion = manifestProperties[KLIB_PROPERTY_COMPILER_VERSION]?.toString() ?: return null - - val sourcePaths = if (name == KONAN_STDLIB_NAME) getStdlibSources(dataDir) else emptyList() - - return LiteKonanLibrary(libraryPath, sourcePaths, name, platform, compilerVersion) - } - - private fun isUnderKonanRoot(libraryPath: File): Boolean { - with(libraryPath.toPath()) { - if (konanHomeDir != null && startsWith(konanHomeDir)) - return true - - 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() - } -}