[Commonizer] Properly detect commonized KLIBs in IDE
This commit is contained in:
+25
-26
@@ -5,11 +5,8 @@
|
||||
|
||||
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.library.*
|
||||
import org.jetbrains.kotlin.konan.target.Distribution
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
@@ -22,10 +19,7 @@ import java.nio.file.Files.*
|
||||
import java.nio.file.Path
|
||||
import java.util.*
|
||||
|
||||
class KlibInfoProvider(
|
||||
kotlinNativeHome: File,
|
||||
nativeDistributionCommonizedLibsDir: File? = null
|
||||
) {
|
||||
class KlibInfoProvider(kotlinNativeHome: File) {
|
||||
private enum class Origin {
|
||||
NATIVE_DISTRIBUTION,
|
||||
NATIVE_DISTRIBUTION_COMMONIZED,
|
||||
@@ -34,8 +28,7 @@ class KlibInfoProvider(
|
||||
|
||||
private class ResultWrapper<T>(val result: T)
|
||||
|
||||
private val kotlinNativePath = kotlinNativeHome.toPath()
|
||||
private val nativeDistributionCommonizedLibsPath = nativeDistributionCommonizedLibsDir?.toPath()
|
||||
private val nativeDistributionLibrariesPath = kotlinNativeHome.resolve(KONAN_DISTRIBUTION_KLIB_DIR).toPath()
|
||||
|
||||
private val hostManager by lazy {
|
||||
HostManager(
|
||||
@@ -80,11 +73,15 @@ class KlibInfoProvider(
|
||||
}
|
||||
}
|
||||
|
||||
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 detectOrigin(libraryPath: Path): Origin? =
|
||||
if (!libraryPath.startsWith(nativeDistributionLibrariesPath)) {
|
||||
null
|
||||
} else {
|
||||
if (libraryPath.getNameOrNull(nativeDistributionLibrariesPath.nameCount) == KONAN_DISTRIBUTION_COMMONIZED_LIBS_DIR)
|
||||
NATIVE_DISTRIBUTION_COMMONIZED
|
||||
else
|
||||
NATIVE_DISTRIBUTION
|
||||
}
|
||||
|
||||
private fun findManifestFile(libraryPath: Path): Path? {
|
||||
libraryPath.resolve(KLIB_MANIFEST_FILE_NAME).let { propertiesPath ->
|
||||
@@ -131,7 +128,7 @@ class KlibInfoProvider(
|
||||
if (parentDirName == KONAN_DISTRIBUTION_COMMON_LIBS_DIR)
|
||||
return ResultWrapper(/* common */ null)
|
||||
else {
|
||||
val target = parentDirName.safeToTarget() ?: return null
|
||||
val target = parentDirName.toTargetOrNull() ?: return null
|
||||
val grandParentDirName = libraryPath.getName(libraryPath.nameCount - 3).toString()
|
||||
return if (grandParentDirName == KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR)
|
||||
ResultWrapper(target)
|
||||
@@ -144,13 +141,17 @@ class KlibInfoProvider(
|
||||
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 commonizedLibsDirName = libraryPath.getName(libraryPath.nameCount - 3 - additionalOffset).toString()
|
||||
|
||||
val props = loadProperties(basePath.resolve(COMMONIZED_PROPERTIES_FILE_NAME))
|
||||
val rawTargets = props.getProperty(COMMONIZED_TARGETS)?.split(' ') ?: return null
|
||||
val rawTargets = commonizedLibsDirName.split('-').dropLast(1)
|
||||
val targets = rawTargets.mapNotNullTo(mutableSetOf()) { it.toTargetOrNull() }
|
||||
|
||||
val targets = rawTargets.mapNotNullTo(mutableSetOf()) { it.safeToTarget() }
|
||||
if (targets.isEmpty() || targets.size != rawTargets.size || ownTarget !in targets) return null
|
||||
if (targets.isEmpty()
|
||||
|| targets.size != rawTargets.size
|
||||
|| (ownTarget != null && ownTarget !in targets)
|
||||
) {
|
||||
return null
|
||||
}
|
||||
|
||||
return ResultWrapper(targets)
|
||||
}
|
||||
@@ -166,14 +167,12 @@ class KlibInfoProvider(
|
||||
return nativeDistributionLibrarySourceFiles.filter { nameFilter(it.name) }
|
||||
}
|
||||
|
||||
private fun String.safeToTarget(): KonanTarget? = try {
|
||||
private fun String.toTargetOrNull(): KonanTarget? = try {
|
||||
hostManager.targetByName(this)
|
||||
} catch (_: TargetSupportException) {
|
||||
null
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val COMMONIZED_PROPERTIES_FILE_NAME = ".commonized"
|
||||
const val COMMONIZED_TARGETS = "targets"
|
||||
}
|
||||
private fun Path.getNameOrNull(index: Int): String? =
|
||||
if (index < 0 || index >= nameCount) null else getName(index).toString()
|
||||
}
|
||||
|
||||
+118
-41
@@ -7,43 +7,71 @@ package org.jetbrains.kotlin.idea.configuration.klib
|
||||
|
||||
import com.intellij.testFramework.PlatformTestUtil.getTestName
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.kotlin.konan.library.*
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils.getHomeDirectory
|
||||
import java.io.File
|
||||
|
||||
class KlibInfoProviderTest : TestCase() {
|
||||
|
||||
fun testOldStyleKlibsFromNativeDistributionRecognized() = doTest()
|
||||
fun testOldStyleKlibsFromNativeDistributionRecognized() = doTest(
|
||||
::generateExpectedKlibsFromDistribution
|
||||
)
|
||||
|
||||
fun testKlibsFromNativeDistributionWithSingleComponentRecognized() = doTest()
|
||||
fun testKlibsFromNativeDistributionWithSingleComponentRecognized() = doTest(
|
||||
::generateExpectedKlibsFromDistribution
|
||||
)
|
||||
|
||||
fun testKlibsFromNativeDistributionWithMultipleComponentsRecognized() = doTest()
|
||||
fun testKlibsFromNativeDistributionWithMultipleComponentsRecognized() = doTest(
|
||||
::generateExpectedKlibsFromDistribution
|
||||
)
|
||||
|
||||
private fun doTest() {
|
||||
fun testCommonizedKlibsFromNativeDistributionRecognized() = doTest(
|
||||
::generateExpectedKlibsFromDistribution,
|
||||
::generateExpectedCommonizedKlibsFromDistribution
|
||||
)
|
||||
|
||||
private fun doTest(vararg expectedKlibsGenerators: (kotlinNativeHome: File) -> Map<File, KlibInfo>) {
|
||||
val kotlinNativeHome = testDataDir.resolve(getTestName(name, true)).resolve("kotlin-native-PLATFORM-VERSION")
|
||||
val sourcesDir = kotlinNativeHome.resolve("sources")
|
||||
val sourcesDir = kotlinNativeHome.resolve(KONAN_DISTRIBUTION_SOURCES_DIR)
|
||||
|
||||
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 }
|
||||
with(kotlinNativeHome.resolve(KONAN_DISTRIBUTION_KLIB_DIR)) {
|
||||
potentialKlibPaths += resolve(KONAN_DISTRIBUTION_COMMON_LIBS_DIR).children()
|
||||
potentialKlibPaths += resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR, "macos_x64").children()
|
||||
|
||||
with(resolve(KONAN_DISTRIBUTION_COMMONIZED_LIBS_DIR, "ios_arm64-ios_x64-discriminator")) {
|
||||
potentialKlibPaths += resolve(KONAN_DISTRIBUTION_COMMON_LIBS_DIR).children()
|
||||
potentialKlibPaths += resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR, "ios_arm64").children()
|
||||
potentialKlibPaths += resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR, "ios_x64").children()
|
||||
}
|
||||
|
||||
with(resolve(KONAN_DISTRIBUTION_COMMONIZED_LIBS_DIR, "ios_arm32-ios_arm64-ios_x64-discriminator")) {
|
||||
potentialKlibPaths += resolve(KONAN_DISTRIBUTION_COMMON_LIBS_DIR).children()
|
||||
potentialKlibPaths += resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR, "ios_arm32").children()
|
||||
potentialKlibPaths += resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR, "ios_arm64").children()
|
||||
potentialKlibPaths += resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR, "ios_x64").children()
|
||||
}
|
||||
}
|
||||
|
||||
val actualKlibs = potentialKlibPaths.mapNotNull { klibProvider.getKlibInfo(it) }
|
||||
.associateBy { it.path.relativeTo(kotlinNativeHome) }
|
||||
|
||||
val expectedKlibsFromDistribution = generateExpectedKlibsFromDistribution(
|
||||
kotlinNativeHome = kotlinNativeHome,
|
||||
sourcesDir = sourcesDir
|
||||
)
|
||||
val expectedKlibsFromDistribution = mutableMapOf<File, KlibInfo>().apply {
|
||||
expectedKlibsGenerators.forEach { this += it(kotlinNativeHome) }
|
||||
}
|
||||
|
||||
assertEquals(expectedKlibsFromDistribution.keys, actualKlibs.keys)
|
||||
for (klibPath in actualKlibs.keys) {
|
||||
val actualKlib = actualKlibs.getValue(klibPath)
|
||||
val expectedKlib = expectedKlibsFromDistribution.getValue(klibPath)
|
||||
|
||||
assertEquals(expectedKlib::class.java, actualKlib::class.java)
|
||||
|
||||
assertEquals(expectedKlib.path, actualKlib.path)
|
||||
assertEquals(expectedKlib.name, actualKlib.name)
|
||||
|
||||
@@ -51,48 +79,98 @@ class KlibInfoProviderTest : TestCase() {
|
||||
val expectedSources = expectedKlib.sourcePaths.map { it.relativeTo(sourcesDir) }.toSet()
|
||||
|
||||
assertEquals(expectedSources, actualSources)
|
||||
assertEquals(expectedKlib.target, actualKlib.target)
|
||||
|
||||
if (expectedKlib is NativeDistributionKlibInfo) {
|
||||
require(actualKlib is NativeDistributionKlibInfo)
|
||||
|
||||
assertEquals(expectedKlib.target, actualKlib.target)
|
||||
} else if (expectedKlib is NativeDistributionCommonizedKlibInfo) {
|
||||
require(actualKlib is NativeDistributionCommonizedKlibInfo)
|
||||
|
||||
assertEquals(expectedKlib.ownTarget, actualKlib.ownTarget)
|
||||
assertEquals(expectedKlib.commonizedTargets, actualKlib.commonizedTargets)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateExpectedKlibsFromDistribution(kotlinNativeHome: File, sourcesDir: File) = listOf(
|
||||
NativeDistributionKlibInfo(
|
||||
path = kotlinNativeHome.resolve("klib", "common", "stdlib"),
|
||||
private fun generateExpectedKlibsFromDistribution(kotlinNativeHome: File): Map<File, NativeDistributionKlibInfo> {
|
||||
val sourcesDir = kotlinNativeHome.resolve(KONAN_DISTRIBUTION_SOURCES_DIR)
|
||||
val basePath = kotlinNativeHome.resolve(KONAN_DISTRIBUTION_KLIB_DIR)
|
||||
|
||||
val result = mutableListOf<NativeDistributionKlibInfo>()
|
||||
|
||||
result += NativeDistributionKlibInfo(
|
||||
path = basePath.resolve(KONAN_DISTRIBUTION_COMMON_LIBS_DIR, KONAN_STDLIB_NAME),
|
||||
sourcePaths = listOf(
|
||||
sourcesDir.resolve("kotlin-stdlib-native-sources.zip"),
|
||||
sourcesDir.resolve("kotlin-test-anotations-common-sources.zip")
|
||||
),
|
||||
name = "stdlib",
|
||||
name = KONAN_STDLIB_NAME,
|
||||
target = null
|
||||
),
|
||||
NativeDistributionKlibInfo(
|
||||
path = kotlinNativeHome.resolve("klib", "common", "kotlinx-cli"),
|
||||
)
|
||||
|
||||
result += NativeDistributionKlibInfo(
|
||||
path = basePath.resolve(KONAN_DISTRIBUTION_COMMON_LIBS_DIR, "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) }
|
||||
|
||||
result += listOf("foo", "bar", "baz").map { name ->
|
||||
NativeDistributionKlibInfo(
|
||||
path = basePath.resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR, "macos_x64", name),
|
||||
sourcePaths = emptyList(),
|
||||
name = name,
|
||||
target = KonanTarget.MACOS_X64
|
||||
)
|
||||
}
|
||||
|
||||
return result.associateBy { it.path.relativeTo(kotlinNativeHome) }
|
||||
}
|
||||
|
||||
private fun generateExpectedCommonizedKlibsFromDistribution(kotlinNativeHome: File): Map<File, NativeDistributionCommonizedKlibInfo> {
|
||||
val basePath = kotlinNativeHome.resolve(KONAN_DISTRIBUTION_KLIB_DIR, KONAN_DISTRIBUTION_COMMONIZED_LIBS_DIR)
|
||||
|
||||
fun generateCommonizedKlibsForDir(commonizedLibsDirName: String): Map<File, NativeDistributionCommonizedKlibInfo> {
|
||||
val rawTargets = commonizedLibsDirName.split('-').dropLast(1)
|
||||
val targets = rawTargets.map {
|
||||
when (it) {
|
||||
"ios_x64" -> KonanTarget.IOS_X64
|
||||
"ios_arm32" -> KonanTarget.IOS_ARM32
|
||||
"ios_arm64" -> KonanTarget.IOS_ARM64
|
||||
else -> error("Unexpected target: $it")
|
||||
}
|
||||
}.toSet()
|
||||
|
||||
val result = mutableListOf<NativeDistributionCommonizedKlibInfo>()
|
||||
|
||||
with(basePath.resolve(commonizedLibsDirName)) {
|
||||
val libraryDirsToTargets: Map<File, KonanTarget?> =
|
||||
targets.associateBy { resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR, it.name) } +
|
||||
(resolve(KONAN_DISTRIBUTION_COMMON_LIBS_DIR) to null)
|
||||
|
||||
libraryDirsToTargets.forEach { (libraryDir, target) ->
|
||||
result += listOf("foo", "bar", "baz").map { name ->
|
||||
NativeDistributionCommonizedKlibInfo(
|
||||
path = libraryDir.resolve(name),
|
||||
sourcePaths = emptyList(),
|
||||
name = name,
|
||||
ownTarget = target,
|
||||
commonizedTargets = targets
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.associateBy { it.path.relativeTo(kotlinNativeHome) }
|
||||
}
|
||||
|
||||
return generateCommonizedKlibsForDir("ios_arm64-ios_x64-discriminator") +
|
||||
generateCommonizedKlibsForDir("ios_arm32-ios_arm64-ios_x64-discriminator")
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val testDataDir = File(getHomeDirectory() + "/idea/testData/configuration/klib")
|
||||
@@ -101,7 +179,6 @@ class KlibInfoProviderTest : TestCase() {
|
||||
private val externalLibsDir = testDataDir.resolve("external-libs")
|
||||
|
||||
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)
|
||||
|
||||
+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 @@
|
||||
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 @@
|
||||
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 @@
|
||||
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 @@
|
||||
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 @@
|
||||
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 @@
|
||||
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 @@
|
||||
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