IDE: Fix friendly displaying of K/N KLIBs with components
Issue #KT-36213
This commit is contained in:
+33
-7
@@ -60,7 +60,9 @@ class KlibInfoProvider(
|
|||||||
val libraryPath = libraryFile.toPath()
|
val libraryPath = libraryFile.toPath()
|
||||||
|
|
||||||
val origin = detectOrigin(libraryPath) ?: return null
|
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 name = manifest.getProperty(KLIB_PROPERTY_UNIQUE_NAME) ?: return null
|
||||||
val target = (detectTarget(libraryPath) ?: return null).result
|
val target = (detectTarget(libraryPath) ?: return null).result
|
||||||
@@ -84,15 +86,39 @@ class KlibInfoProvider(
|
|||||||
else -> null
|
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) {
|
private fun loadProperties(propertiesPath: Path): Properties = cachedProperties.computeIfAbsent(propertiesPath) {
|
||||||
val properties = Properties()
|
val properties = Properties()
|
||||||
|
|
||||||
if (isRegularFile(propertiesPath)) {
|
try {
|
||||||
try {
|
newInputStream(propertiesPath).use { properties.load(it) }
|
||||||
newInputStream(propertiesPath).use { properties.load(it) }
|
} catch (_: IOException) {
|
||||||
} catch (_: IOException) {
|
// do nothing
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
properties
|
properties
|
||||||
|
|||||||
+56
-43
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.configuration.klib
|
package org.jetbrains.kotlin.idea.configuration.klib
|
||||||
|
|
||||||
|
import com.intellij.testFramework.PlatformTestUtil.getTestName
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
import org.jetbrains.kotlin.test.KotlinTestUtils.getHomeDirectory
|
import org.jetbrains.kotlin.test.KotlinTestUtils.getHomeDirectory
|
||||||
@@ -12,7 +13,16 @@ import java.io.File
|
|||||||
|
|
||||||
class KlibInfoProviderTest : TestCase() {
|
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 klibProvider = KlibInfoProvider(kotlinNativeHome = kotlinNativeHome)
|
||||||
|
|
||||||
val potentialKlibPaths = mutableListOf<File>()
|
val potentialKlibPaths = mutableListOf<File>()
|
||||||
@@ -22,7 +32,12 @@ class KlibInfoProviderTest : TestCase() {
|
|||||||
|
|
||||||
val actualKlibs = potentialKlibPaths
|
val actualKlibs = potentialKlibPaths
|
||||||
.mapNotNull { klibProvider.getKlibInfo(it) as? NativeDistributionKlibInfo }
|
.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)
|
assertEquals(expectedKlibsFromDistribution.keys, actualKlibs.keys)
|
||||||
for (klibPath in 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 {
|
companion object {
|
||||||
private val testDataDir = File(getHomeDirectory() + "/idea/testData/configuration/klib")
|
private val testDataDir = File(getHomeDirectory() + "/idea/testData/configuration/klib")
|
||||||
.also { assertTrue("Test data directory does not exist: $it", it.isDirectory) }
|
.also { assertTrue("Test data directory does not exist: $it", it.isDirectory) }
|
||||||
|
|
||||||
private val externalLibsDir = testDataDir.resolve("external-libs")
|
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())
|
private fun File.children(): List<File> = (listFiles()?.toList() ?: emptyList())
|
||||||
.also { assertTrue("$this does not have children files or directories", it.isNotEmpty()) }
|
.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
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
unique_name=invalid3
|
||||||
-1
@@ -1 +0,0 @@
|
|||||||
unique_name=yetAnotherBroken
|
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
unique_name=kotlinx-cli
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
unique_name=stdlib
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
unique_name=bar
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
unique_name=baz
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
unique_name=foo
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
SPOILED_unique_name=invalid2
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
SPOILED_unique_name=invalid2
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
unique_name=invalid3
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
unique_name=invalid3
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
unique_name=kotlinx-cli
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
unique_name=stdlib
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
unique_name=bar
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
unique_name=baz
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
unique_name=foo
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
SPOILED_unique_name=invalid2
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
unique_name=invalid3
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
// this file is empty
|
||||||
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
// this file is empty
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
// this file is empty
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
// this file is empty
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
-1
@@ -1 +0,0 @@
|
|||||||
SPOILED_unique_name=broken
|
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
unique_name=kotlinx-cli
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
unique_name=stdlib
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
unique_name=bar
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
unique_name=baz
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
unique_name=foo
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
SPOILED_unique_name=invalid2
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
unique_name=invalid3
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
// this file is empty
|
||||||
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
// this file is empty
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
// this file is empty
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
+1
@@ -0,0 +1 @@
|
|||||||
|
// this file is empty
|
||||||
BIN
Binary file not shown.
Reference in New Issue
Block a user