IDE: Fix friendly displaying of K/N KLIBs with components

Issue #KT-36213
This commit is contained in:
Dmitriy Dolovov
2020-01-30 14:16:53 +07:00
parent 4336096775
commit 623b554297
67 changed files with 122 additions and 53 deletions
@@ -60,7 +60,9 @@ class KlibInfoProvider(
val libraryPath = libraryFile.toPath()
val origin = detectOrigin(libraryPath) ?: return null
val manifest = loadProperties(libraryPath.resolve(KLIB_MANIFEST_FILE_NAME))
val manifestFile = findManifestFile(libraryPath) ?: return null
val manifest = loadProperties(manifestFile)
val name = manifest.getProperty(KLIB_PROPERTY_UNIQUE_NAME) ?: return null
val target = (detectTarget(libraryPath) ?: return null).result
@@ -84,15 +86,39 @@ class KlibInfoProvider(
else -> null
}
private fun findManifestFile(libraryPath: Path): Path? {
libraryPath.resolve(KLIB_MANIFEST_FILE_NAME).let { propertiesPath ->
// KLIB layout without components
if (isRegularFile(propertiesPath)) return propertiesPath
}
if (!isDirectory(libraryPath)) return null
// look up through all components and find all manifest files
val candidates = newDirectoryStream(libraryPath).use { stream ->
stream.mapNotNull { componentPath ->
val candidate = componentPath.resolve(KLIB_MANIFEST_FILE_NAME)
if (isRegularFile(candidate)) candidate else null
}
}
return when (candidates.size) {
0 -> null
1 -> candidates.single()
else -> {
// there are multiple components, let's take just the first one alphabetically
candidates.minBy { it.getName(it.nameCount - 2).toString() }!!
}
}
}
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
}
try {
newInputStream(propertiesPath).use { properties.load(it) }
} catch (_: IOException) {
// do nothing
}
properties
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.idea.configuration.klib
import com.intellij.testFramework.PlatformTestUtil.getTestName
import junit.framework.TestCase
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.test.KotlinTestUtils.getHomeDirectory
@@ -12,7 +13,16 @@ import java.io.File
class KlibInfoProviderTest : TestCase() {
fun testKlibsFromNativeDistributionRecognized() {
fun testOldStyleKlibsFromNativeDistributionRecognized() = doTest()
fun testKlibsFromNativeDistributionWithSingleComponentRecognized() = doTest()
fun testKlibsFromNativeDistributionWithMultipleComponentsRecognized() = doTest()
private fun doTest() {
val kotlinNativeHome = testDataDir.resolve(getTestName(name, true)).resolve("kotlin-native-PLATFORM-VERSION")
val sourcesDir = kotlinNativeHome.resolve("sources")
val klibProvider = KlibInfoProvider(kotlinNativeHome = kotlinNativeHome)
val potentialKlibPaths = mutableListOf<File>()
@@ -22,7 +32,12 @@ class KlibInfoProviderTest : TestCase() {
val actualKlibs = potentialKlibPaths
.mapNotNull { klibProvider.getKlibInfo(it) as? NativeDistributionKlibInfo }
.associateBy { it.path.relativeTo(testDataDir) }
.associateBy { it.path.relativeTo(kotlinNativeHome) }
val expectedKlibsFromDistribution = generateExpectedKlibsFromDistribution(
kotlinNativeHome = kotlinNativeHome,
sourcesDir = sourcesDir
)
assertEquals(expectedKlibsFromDistribution.keys, actualKlibs.keys)
for (klibPath in actualKlibs.keys) {
@@ -40,52 +55,50 @@ class KlibInfoProviderTest : TestCase() {
}
}
private fun generateExpectedKlibsFromDistribution(kotlinNativeHome: File, sourcesDir: File) = 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(kotlinNativeHome) }
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()) }
@@ -1 +0,0 @@
SPOILED_unique_name=anotherBroken
@@ -0,0 +1 @@
SPOILED_unique_name=invalid2
@@ -0,0 +1 @@
unique_name=invalid3
@@ -1 +0,0 @@
unique_name=yetAnotherBroken
@@ -1 +0,0 @@
SPOILED_unique_name=broken