K/N: Get rid of remaining parts of "lite" KLIB API

Rewrite it in clean way and move to 'idea-gradle' module.
This commit is contained in:
Dmitriy Dolovov
2020-01-26 14:51:44 +07:00
parent a7da605816
commit 224b2acdcc
30 changed files with 319 additions and 307 deletions
-1
View File
@@ -610,7 +610,6 @@ tasks {
register("konan-tests") {
dependsOn("dist")
dependsOn(
":kotlin-native:kotlin-native-library-reader:test",
":kotlin-native:commonizer:test"
)
}
@@ -0,0 +1,32 @@
/*
* Copyright 2010-2020 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.idea.configuration.klib
import org.jetbrains.kotlin.konan.target.KonanTarget
import java.io.File
sealed class KlibInfo(
val path: File,
val sourcePaths: Collection<File>,
val name: String
)
class NativeDistributionKlibInfo(
path: File,
sourcePaths: Collection<File>,
name: String,
val target: KonanTarget? // null means "common"
) : KlibInfo(path, sourcePaths, name)
class NativeDistributionCommonizedKlibInfo(
path: File,
sourcePaths: Collection<File>,
name: String,
val ownTarget: KonanTarget?, // null means "common"
val commonizedTargets: Set<KonanTarget>
) : KlibInfo(path, sourcePaths, name)
// TODO: add other subclasses as necessary
@@ -0,0 +1,153 @@
/*
* Copyright 2010-2020 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.idea.configuration.klib
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_COMMON_LIBS_DIR
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_SOURCES_DIR
import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME
import org.jetbrains.kotlin.idea.configuration.klib.KlibInfoProvider.Origin.*
import org.jetbrains.kotlin.konan.target.Distribution
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.target.TargetSupportException
import org.jetbrains.kotlin.library.KLIB_MANIFEST_FILE_NAME
import org.jetbrains.kotlin.library.KLIB_PROPERTY_UNIQUE_NAME
import java.io.File
import java.io.IOException
import java.nio.file.Files.*
import java.nio.file.Path
import java.util.*
class KlibInfoProvider(
kotlinNativeHome: File,
nativeDistributionCommonizedLibsDir: File? = null
) {
private enum class Origin {
NATIVE_DISTRIBUTION,
NATIVE_DISTRIBUTION_COMMONIZED,
// TODO: add other origins as necessary
}
private class ResultWrapper<T>(val result: T)
private val kotlinNativePath = kotlinNativeHome.toPath()
private val nativeDistributionCommonizedLibsPath = nativeDistributionCommonizedLibsDir?.toPath()
private val hostManager by lazy {
HostManager(
distribution = Distribution(konanHomeOverride = kotlinNativeHome.path),
experimental = true
)
}
private val nativeDistributionLibrarySourceFiles by lazy {
kotlinNativeHome.resolve(KONAN_DISTRIBUTION_SOURCES_DIR)
.takeIf { it.isDirectory }
?.walkTopDown()
?.maxDepth(1)
?.filter { it.isFile && it.name.endsWith(".zip") }
?.toList()
?: emptyList()
}
private val cachedProperties = mutableMapOf<Path, Properties>()
fun getKlibInfo(libraryFile: File): KlibInfo? {
val libraryPath = libraryFile.toPath()
val origin = detectOrigin(libraryPath) ?: return null
val manifest = loadProperties(libraryPath.resolve(KLIB_MANIFEST_FILE_NAME))
val name = manifest.getProperty(KLIB_PROPERTY_UNIQUE_NAME) ?: return null
val target = (detectTarget(libraryPath) ?: return null).result
return when (origin) {
NATIVE_DISTRIBUTION -> {
val sourcePaths = if (target == null) getLibrarySourcesFromDistribution(name) else emptyList()
NativeDistributionKlibInfo(libraryFile, sourcePaths, name, target)
}
NATIVE_DISTRIBUTION_COMMONIZED -> {
val commonizedTargets = (detectCommonizedTargets(libraryPath, target) ?: return null).result
NativeDistributionCommonizedKlibInfo(libraryFile, emptyList(), name, target, commonizedTargets)
}
}
}
private fun detectOrigin(libraryPath: Path): Origin? = when {
libraryPath.startsWith(kotlinNativePath) -> NATIVE_DISTRIBUTION
nativeDistributionCommonizedLibsPath?.let { libraryPath.startsWith(it) } == true -> NATIVE_DISTRIBUTION_COMMONIZED
else -> null
}
private fun loadProperties(propertiesPath: Path): Properties = cachedProperties.computeIfAbsent(propertiesPath) {
val properties = Properties()
if (isRegularFile(propertiesPath)) {
try {
newInputStream(propertiesPath).use { properties.load(it) }
} catch (_: IOException) {
// do nothing
}
}
properties
}
private fun detectTarget(libraryPath: Path): ResultWrapper<KonanTarget?>? {
if (libraryPath.nameCount < 3) return null
val parentDirName = libraryPath.getName(libraryPath.nameCount - 2).toString()
if (parentDirName == KONAN_DISTRIBUTION_COMMON_LIBS_DIR)
return ResultWrapper(/* common */ null)
else {
val target = parentDirName.safeToTarget() ?: return null
val grandParentDirName = libraryPath.getName(libraryPath.nameCount - 3).toString()
return if (grandParentDirName == KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR)
ResultWrapper(target)
else
null
}
}
private fun detectCommonizedTargets(libraryPath: Path, ownTarget: KonanTarget?): ResultWrapper<Set<KonanTarget>>? {
if (libraryPath.nameCount < 4) return null
val additionalOffset = if (ownTarget == null) /* common */ 0 else 1
val basePath = libraryPath.subpath(0, libraryPath.nameCount - 2 - additionalOffset)
val props = loadProperties(basePath.resolve(COMMONIZED_PROPERTIES_FILE_NAME))
val rawTargets = props.getProperty(COMMONIZED_TARGETS)?.split(' ') ?: return null
val targets = rawTargets.mapNotNullTo(mutableSetOf()) { it.safeToTarget() }
if (targets.isEmpty() || targets.size != rawTargets.size || ownTarget !in targets) return null
return ResultWrapper(targets)
}
private fun getLibrarySourcesFromDistribution(libraryName: String): Collection<File> {
val nameFilter: (String) -> Boolean = if (libraryName == KONAN_STDLIB_NAME) {
// stdlib is a special case
{ it.startsWith("kotlin-stdlib") || it.startsWith("kotlin-test") }
} else {
{ it.startsWith(libraryName) }
}
return nativeDistributionLibrarySourceFiles.filter { nameFilter(it.name) }
}
private fun String.safeToTarget(): KonanTarget? = try {
hostManager.targetByName(this)
} catch (_: TargetSupportException) {
null
}
private companion object {
const val COMMONIZED_PROPERTIES_FILE_NAME = ".commonized"
const val COMMONIZED_TARGETS = "targets"
}
}
@@ -8,7 +8,10 @@ package org.jetbrains.kotlin.idea.configuration
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.externalSystem.model.DataNode
import com.intellij.openapi.externalSystem.model.ProjectKeys
import com.intellij.openapi.externalSystem.model.project.*
import com.intellij.openapi.externalSystem.model.project.LibraryData
import com.intellij.openapi.externalSystem.model.project.LibraryDependencyData
import com.intellij.openapi.externalSystem.model.project.LibraryLevel
import com.intellij.openapi.externalSystem.model.project.ProjectData
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider
import com.intellij.openapi.externalSystem.service.project.IdeUIModifiableModelsProvider
import com.intellij.openapi.externalSystem.service.project.manage.AbstractProjectDataService
@@ -25,15 +28,12 @@ import org.jetbrains.kotlin.gradle.KotlinMPPGradleModel
import org.jetbrains.kotlin.idea.configuration.DependencySubstitute.NoSubstitute
import org.jetbrains.kotlin.idea.configuration.DependencySubstitute.YesSubstitute
import org.jetbrains.kotlin.idea.configuration.KotlinNativeLibraryNameUtil.buildIDELibraryName
import org.jetbrains.kotlin.idea.configuration.klib.KlibInfoProvider
import org.jetbrains.kotlin.idea.configuration.klib.NativeDistributionKlibInfo
import org.jetbrains.kotlin.idea.inspections.gradle.findKotlinPluginVersion
import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME
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
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.*
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
import org.jetbrains.plugins.gradle.service.project.GradleProjectResolverUtil
import org.jetbrains.plugins.gradle.service.project.ProjectResolverContext
@@ -110,9 +110,22 @@ internal class KotlinNativeLibrariesDependencySubstitutor(
private val ProjectResolverContext.dependencySubstitutionCache
get() = getUserData(KLIB_DEPENDENCY_SUBSTITUTION_CACHE) ?: putUserDataIfAbsent(KLIB_DEPENDENCY_SUBSTITUTION_CACHE, HashMap())
private val libraryProvider = LiteKonanLibraryFacade.getDistributionLibraryProvider(
mppModel.kotlinNativeHome.takeIf { it != KotlinMPPGradleModel.NO_KOTLIN_NATIVE_HOME }?.let { File(it) }
)
private val klibInfoProvider: KlibInfoProvider? by lazy {
val kotlinNativeHome = mppModel.kotlinNativeHome.takeIf { it != KotlinMPPGradleModel.NO_KOTLIN_NATIVE_HOME }?.let(::File)
if (kotlinNativeHome == null) {
LOG.warn(
"""
Can't obtain Kotlin/Native home path in Kotlin Gradle plugin.
${KotlinMPPGradleModel::class.java.simpleName} is $mppModel.
${KotlinNativeLibrariesDependencySubstitutor::class.java.simpleName} will run in idle mode. No dependencies will be substituted.
""".trimIndent()
)
null
} else
KlibInfoProvider(kotlinNativeHome = kotlinNativeHome)
}
private val kotlinVersion: String? by lazy {
// first, try to figure out Kotlin plugin version by classpath (the default approach)
@@ -159,17 +172,17 @@ internal class KotlinNativeLibrariesDependencySubstitutor(
private fun buildSubstituteIfNecessary(libraryFile: File): DependencySubstitute {
// need to check whether `library` points to a real KLIB,
// and if answer is yes then build a new dependency that will substitute original one
val library = libraryProvider.getLibrary(libraryFile) ?: return NoSubstitute
val klib = klibInfoProvider?.getKlibInfo(libraryFile) as? NativeDistributionKlibInfo ?: return NoSubstitute
val nonNullKotlinVersion = kotlinVersion ?: return NoSubstitute
val newLibraryName = buildIDELibraryName(nonNullKotlinVersion, library.name, library.platform)
val newLibraryName = buildIDELibraryName(nonNullKotlinVersion, klib.name, klib.target?.name)
val substitute = DefaultExternalMultiLibraryDependency().apply {
classpathOrder = if (library.name == KONAN_STDLIB_NAME) -1 else 0 // keep stdlib upper
classpathOrder = if (klib.name == KONAN_STDLIB_NAME) -1 else 0 // keep stdlib upper
name = newLibraryName
packaging = DEFAULT_PACKAGING
files += library.path
sources += library.sourcePaths
files += klib.path
sources += klib.sourcePaths
scope = DependencyScope.PROVIDED.name
}
@@ -0,0 +1,101 @@
/*
* Copyright 2010-2020 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.idea.configuration.klib
import junit.framework.TestCase
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.test.KotlinTestUtils.getHomeDirectory
import java.io.File
class KlibInfoProviderTest : TestCase() {
fun testKlibsFromNativeDistributionRecognized() {
val klibProvider = KlibInfoProvider(kotlinNativeHome = kotlinNativeHome)
val potentialKlibPaths = mutableListOf<File>()
potentialKlibPaths += externalLibsDir.children()
potentialKlibPaths += kotlinNativeHome.resolve("klib", "common").children()
potentialKlibPaths += kotlinNativeHome.resolve("klib", "platform", "macos_x64").children()
val actualKlibs = potentialKlibPaths
.mapNotNull { klibProvider.getKlibInfo(it) as? NativeDistributionKlibInfo }
.associateBy { it.path.relativeTo(testDataDir) }
assertEquals(expectedKlibsFromDistribution.keys, actualKlibs.keys)
for (klibPath in actualKlibs.keys) {
val actualKlib = actualKlibs.getValue(klibPath)
val expectedKlib = expectedKlibsFromDistribution.getValue(klibPath)
assertEquals(expectedKlib.path, actualKlib.path)
assertEquals(expectedKlib.name, actualKlib.name)
val actualSources = actualKlib.sourcePaths.map { it.relativeTo(sourcesDir) }.toSet()
val expectedSources = expectedKlib.sourcePaths.map { it.relativeTo(sourcesDir) }.toSet()
assertEquals(expectedSources, actualSources)
assertEquals(expectedKlib.target, actualKlib.target)
}
}
companion object {
private val testDataDir = File(getHomeDirectory() + "/idea/testData/configuration/klib")
.also { assertTrue("Test data directory does not exist: $it", it.isDirectory) }
private val externalLibsDir = testDataDir.resolve("external-libs")
private val kotlinNativeHome = testDataDir.resolve("kotlin-native-PLATFORM-VERSION")
private val sourcesDir = kotlinNativeHome.resolve("sources")
private val expectedKlibsFromDistribution = listOf(
NativeDistributionKlibInfo(
path = kotlinNativeHome.resolve("klib", "common", "stdlib"),
sourcePaths = listOf(
sourcesDir.resolve("kotlin-stdlib-native-sources.zip"),
sourcesDir.resolve("kotlin-test-anotations-common-sources.zip")
),
name = "stdlib",
target = null
),
NativeDistributionKlibInfo(
path = kotlinNativeHome.resolve("klib", "common", "kotlinx-cli"),
sourcePaths = listOf(
sourcesDir.resolve("kotlinx-cli-common-sources.zip"),
sourcesDir.resolve("kotlinx-cli-native-sources.zip")
),
name = "kotlinx-cli",
target = null
),
NativeDistributionKlibInfo(
path = kotlinNativeHome.resolve("klib", "platform", "macos_x64", "foo"),
sourcePaths = emptyList(),
name = "foo",
target = KonanTarget.MACOS_X64
),
NativeDistributionKlibInfo(
path = kotlinNativeHome.resolve("klib", "platform", "macos_x64", "bar"),
sourcePaths = emptyList(),
name = "bar",
target = KonanTarget.MACOS_X64
),
NativeDistributionKlibInfo(
path = kotlinNativeHome.resolve("klib", "platform", "macos_x64", "baz"),
sourcePaths = emptyList(),
name = "baz",
target = KonanTarget.MACOS_X64
)
).associateBy { it.path.relativeTo(testDataDir) }
private fun File.children(): List<File> = (listFiles()?.toList() ?: emptyList())
.also { assertTrue("$this does not have children files or directories", it.isNotEmpty()) }
private fun File.resolve(relative: String, next: String, vararg others: String): File {
var temp = resolve(relative).resolve(next)
for (other in others)
temp = temp.resolve(other)
return temp
}
}
}
@@ -0,0 +1 @@
unique_name=kotlinx-cli
+1 -3
View File
@@ -13,13 +13,11 @@ dependencies {
compile(project(":kotlin-util-io"))
compile(project(":kotlin-util-klib"))
compile(project(":kotlin-util-klib-metadata"))
testCompile(commonDep("junit:junit"))
}
sourceSets {
"main" { projectDefault() }
"test" { projectDefault() }
"test" { none() }
}
standardPublicJars()
@@ -1,15 +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 java.io.File
interface LiteKonanLibrary {
val path: File
val sourcePaths: Collection<File>
val name: String
val platform: String?
}
@@ -1,134 +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.*
import org.jetbrains.kotlin.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
return LiteKonanLibraryImpl(
path = libraryPath,
name = name
)
}
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(KONAN_DISTRIBUTION_KLIB_DIR).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<String?, File>? {
val parentDir = libraryPath.parentFile ?: return null
val parentDirName = parentDir.name
fun getDataDir(platformDir: File): File = platformDir.parentFile.parentFile
return when (parentDirName) {
KONAN_DISTRIBUTION_COMMON_LIBS_DIR -> null to getDataDir(parentDir)
else -> {
val grandParentDir = parentDir.parentFile ?: return null
when {
grandParentDir.name == KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR -> parentDirName to getDataDir(grandParentDir)
else -> return null
}
}
}
}
private fun getStdlibSources(dataDir: File): Collection<File> {
val sourcesDir = dataDir.resolve(KONAN_DISTRIBUTION_SOURCES_DIR).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
) : LiteKonanLibrary {
override var platform: String? = null
override var sourcePaths: Collection<File> = emptyList()
}
@@ -1,123 +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.KONAN_DISTRIBUTION_KLIB_DIR
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_COMMON_LIBS_DIR
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR
import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME
import org.junit.Assert.*
import org.junit.Test
import java.io.File
import java.io.FileFilter
import java.nio.file.Files
import java.util.zip.ZipException
import java.util.zip.ZipFile
class LiteKonanLibraryFacadeTests {
@Test
fun allLibrariesRecognized() {
val libraryProvider = LiteKonanLibraryFacade.getLibraryProvider()
val actualLibraries = collectLibrariesFromLocalFS(libraryProvider)
val expectedLibraries = librariesExpectedInDistribution() + librariesExpectedInExternalDir()
compareLibraries(
expectedLibraries,
actualLibraries,
/* `LiteKonanLibraryFacade.getLibraryProvider()` is currently platform-agnostic */ true
)
}
@Test
fun onlyFromDistributionLibrariesRecognized() {
val libraryProvider = LiteKonanLibraryFacade.getDistributionLibraryProvider(konanHomeDir)
val actualLibraries = collectLibrariesFromLocalFS(libraryProvider)
val expectedLibraries = librariesExpectedInDistribution()
compareLibraries(expectedLibraries, actualLibraries, false)
}
@Test
fun sourcesAttachedToStdlib() {
val libraryProvider = LiteKonanLibraryFacade.getDistributionLibraryProvider(konanHomeDir)
val stdlib = collectLibrariesFromLocalFS(libraryProvider).values.firstOrNull { it.name == KONAN_STDLIB_NAME }
?: error("Could not load Kotlin/Native $KONAN_STDLIB_NAME from $konanHomeDir")
assertTrue("Kotlin/Native $KONAN_STDLIB_NAME sources must not be empty", stdlib.sourcePaths.isNotEmpty())
assertTrue(
"Each path in $KONAN_STDLIB_NAME.sourcePaths must be either non-empty directory or ZIP (JAR) file",
stdlib.sourcePaths.all { sourcePath ->
when {
sourcePath.isDirectory -> Files.newDirectoryStream(sourcePath.toPath()).use { it.any { true } }
sourcePath.isFile -> try {
ZipFile(sourcePath).use { it.name != null }
} catch (e: ZipException) {
false
}
else -> false
}
})
}
private fun getPotentialLibraryPathsOnLocalFS(): List<File> {
val roots = mutableListOf(externalLibsDir)
roots += klibDir.resolve(KONAN_DISTRIBUTION_COMMON_LIBS_DIR)
roots += klibDir.resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR).listFiles(FileFilter { it.isDirectory })?.toList() ?: emptyList()
return roots.flatMap { it.listFiles()?.toList() ?: emptyList() }
}
private fun collectLibrariesFromLocalFS(libraryProvider: LiteKonanLibraryProvider): Map<File, LiteKonanLibrary> =
getPotentialLibraryPathsOnLocalFS().mapNotNull { libraryProvider.getLibrary(it) }.toLibraryMap()
private fun librariesExpectedInDistribution(): Map<File, FakeLibraryForTest> = listOf(
FakeLibraryForTest(klibDir.resolve(KONAN_DISTRIBUTION_COMMON_LIBS_DIR, KONAN_STDLIB_NAME)),
FakeLibraryForTest(klibDir.resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR, "macos_x64", "foo"), platform = "macos_x64"),
FakeLibraryForTest(klibDir.resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR, "macos_x64", "bar"), platform = "macos_x64"),
FakeLibraryForTest(klibDir.resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR, "macos_x64", "baz"), platform = "macos_x64")
).toLibraryMap()
private fun librariesExpectedInExternalDir(): Map<File, FakeLibraryForTest> = listOf(
FakeLibraryForTest(externalLibsDir.resolve("correct"))
).toLibraryMap()
private fun compareLibraries(expected: Map<File, FakeLibraryForTest>, actual: Map<File, LiteKonanLibrary>, ignorePlatform: Boolean) {
assertEquals("Libraries paths mismatch", expected.keys, actual.keys)
for (key in expected.keys) {
val expectedLibrary = expected.getValue(key)
val actualLibrary = actual.getValue(key)
assertEquals("Library path mismatch", expectedLibrary.path, actualLibrary.path)
if (!ignorePlatform) {
assertEquals("Library platform mismatch, path=${expectedLibrary.path}", expectedLibrary.platform, actualLibrary.platform)
}
}
}
private companion object {
val klibDir = konanHomeDir.resolve(KONAN_DISTRIBUTION_KLIB_DIR)
val externalLibsDir = testDataDir.resolve("external-libs")
fun <T : LiteKonanLibrary> List<T>.toLibraryMap() = map { it.path to it }.toMap()
}
}
private class FakeLibraryForTest(
override val path: File,
override val platform: String? = null
) : LiteKonanLibrary {
override val sourcePaths: Collection<File> = emptyList()
override val name: String = path.name
}
@@ -1,16 +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 java.io.File
internal val testDataDir = File(System.getProperty("user.dir") ?: ".").canonicalFile.resolve("testData")
internal val konanHomeDir = testDataDir.resolve("kotlin-native-data-dir", "kotlin-native-PLATFORM-VERSION")
internal fun File.resolve(relative: String, next: String) = resolve(relative).resolve(next)
internal fun File.resolve(relative: String, next: String, another: String) = resolve(relative, next).resolve(another)