diff --git a/build.gradle.kts b/build.gradle.kts index 5e049a9a11b..a2256426939 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -610,7 +610,6 @@ tasks { register("konan-tests") { dependsOn("dist") dependsOn( - ":kotlin-native:kotlin-native-library-reader:test", ":kotlin-native:commonizer:test" ) } diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/klib/KlibInfo.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/klib/KlibInfo.kt new file mode 100644 index 00000000000..8d72c2babff --- /dev/null +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/klib/KlibInfo.kt @@ -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, + val name: String +) + +class NativeDistributionKlibInfo( + path: File, + sourcePaths: Collection, + name: String, + val target: KonanTarget? // null means "common" +) : KlibInfo(path, sourcePaths, name) + +class NativeDistributionCommonizedKlibInfo( + path: File, + sourcePaths: Collection, + name: String, + val ownTarget: KonanTarget?, // null means "common" + val commonizedTargets: Set +) : KlibInfo(path, sourcePaths, name) + +// TODO: add other subclasses as necessary diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/klib/KlibInfoProvider.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/klib/KlibInfoProvider.kt new file mode 100644 index 00000000000..c4b2909ea6c --- /dev/null +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/klib/KlibInfoProvider.kt @@ -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(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() + + 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? { + 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>? { + 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 { + 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" + } +} 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 f04102d811b..76605b7ddaa 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 @@ -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 } diff --git a/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/configuration/klib/KlibInfoProviderTest.kt b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/configuration/klib/KlibInfoProviderTest.kt new file mode 100644 index 00000000000..1f951328eff --- /dev/null +++ b/idea/idea-gradle/tests/org/jetbrains/kotlin/idea/configuration/klib/KlibInfoProviderTest.kt @@ -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() + 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 = (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 + } + } +} diff --git a/konan/library-reader/testData/external-libs/anotherBroken/manifest b/idea/testData/configuration/klib/external-libs/anotherBroken/manifest similarity index 100% rename from konan/library-reader/testData/external-libs/anotherBroken/manifest rename to idea/testData/configuration/klib/external-libs/anotherBroken/manifest diff --git a/konan/library-reader/testData/external-libs/correct/manifest b/idea/testData/configuration/klib/external-libs/correct/manifest similarity index 100% rename from konan/library-reader/testData/external-libs/correct/manifest rename to idea/testData/configuration/klib/external-libs/correct/manifest diff --git a/konan/library-reader/testData/external-libs/invalid b/idea/testData/configuration/klib/external-libs/invalid similarity index 100% rename from konan/library-reader/testData/external-libs/invalid rename to idea/testData/configuration/klib/external-libs/invalid diff --git a/konan/library-reader/testData/external-libs/yetAnotherBroken/not-a-manifest b/idea/testData/configuration/klib/external-libs/yetAnotherBroken/not-a-manifest similarity index 100% rename from konan/library-reader/testData/external-libs/yetAnotherBroken/not-a-manifest rename to idea/testData/configuration/klib/external-libs/yetAnotherBroken/not-a-manifest diff --git a/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/klib/common/kotlinx-cli/manifest b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/klib/common/kotlinx-cli/manifest new file mode 100644 index 00000000000..ce949fd9395 --- /dev/null +++ b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/klib/common/kotlinx-cli/manifest @@ -0,0 +1 @@ +unique_name=kotlinx-cli diff --git a/konan/library-reader/testData/kotlin-native-data-dir/kotlin-native-PLATFORM-VERSION/klib/common/stdlib/manifest b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/klib/common/stdlib/manifest similarity index 100% rename from konan/library-reader/testData/kotlin-native-data-dir/kotlin-native-PLATFORM-VERSION/klib/common/stdlib/manifest rename to idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/klib/common/stdlib/manifest diff --git a/konan/library-reader/testData/kotlin-native-data-dir/kotlin-native-PLATFORM-VERSION/klib/platform/macos_x64/bar/manifest b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/klib/platform/macos_x64/bar/manifest similarity index 100% rename from konan/library-reader/testData/kotlin-native-data-dir/kotlin-native-PLATFORM-VERSION/klib/platform/macos_x64/bar/manifest rename to idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/klib/platform/macos_x64/bar/manifest diff --git a/konan/library-reader/testData/kotlin-native-data-dir/kotlin-native-PLATFORM-VERSION/klib/platform/macos_x64/baz/manifest b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/klib/platform/macos_x64/baz/manifest similarity index 100% rename from konan/library-reader/testData/kotlin-native-data-dir/kotlin-native-PLATFORM-VERSION/klib/platform/macos_x64/baz/manifest rename to idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/klib/platform/macos_x64/baz/manifest diff --git a/konan/library-reader/testData/kotlin-native-data-dir/kotlin-native-PLATFORM-VERSION/klib/platform/macos_x64/broken/manifest b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/klib/platform/macos_x64/broken/manifest similarity index 100% rename from konan/library-reader/testData/kotlin-native-data-dir/kotlin-native-PLATFORM-VERSION/klib/platform/macos_x64/broken/manifest rename to idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/klib/platform/macos_x64/broken/manifest diff --git a/konan/library-reader/testData/kotlin-native-data-dir/kotlin-native-PLATFORM-VERSION/klib/platform/macos_x64/foo/manifest b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/klib/platform/macos_x64/foo/manifest similarity index 100% rename from konan/library-reader/testData/kotlin-native-data-dir/kotlin-native-PLATFORM-VERSION/klib/platform/macos_x64/foo/manifest rename to idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/klib/platform/macos_x64/foo/manifest diff --git a/konan/library-reader/testData/kotlin-native-data-dir/kotlin-native-PLATFORM-VERSION/klib/platform/macos_x64/invalid b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/klib/platform/macos_x64/invalid similarity index 100% rename from konan/library-reader/testData/kotlin-native-data-dir/kotlin-native-PLATFORM-VERSION/klib/platform/macos_x64/invalid rename to idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/klib/platform/macos_x64/invalid diff --git a/konan/library-reader/testData/kotlin-native-data-dir/kotlin-native-PLATFORM-VERSION/sources/kotlin-stdlib-common-sources/placeholder.kt b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlin-something-unexpected-a/placeholder.kt similarity index 100% rename from konan/library-reader/testData/kotlin-native-data-dir/kotlin-native-PLATFORM-VERSION/sources/kotlin-stdlib-common-sources/placeholder.kt rename to idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlin-something-unexpected-a/placeholder.kt diff --git a/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlin-something-unexpected-b.zip b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlin-something-unexpected-b.zip new file mode 100644 index 00000000000..f430c8fda29 Binary files /dev/null and b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlin-something-unexpected-b.zip differ diff --git a/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlin-something-unexpected-b/placeholder.kt b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlin-something-unexpected-b/placeholder.kt new file mode 100644 index 00000000000..9c71eb811fe --- /dev/null +++ b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlin-something-unexpected-b/placeholder.kt @@ -0,0 +1 @@ +// this file is empty diff --git a/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlin-stdlib-common-sources/placeholder.kt b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlin-stdlib-common-sources/placeholder.kt new file mode 100644 index 00000000000..9c71eb811fe --- /dev/null +++ b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlin-stdlib-common-sources/placeholder.kt @@ -0,0 +1 @@ +// this file is empty diff --git a/konan/library-reader/testData/kotlin-native-data-dir/kotlin-native-PLATFORM-VERSION/sources/kotlin-stdlib-native-sources.zip b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlin-stdlib-native-sources.zip similarity index 100% rename from konan/library-reader/testData/kotlin-native-data-dir/kotlin-native-PLATFORM-VERSION/sources/kotlin-stdlib-native-sources.zip rename to idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlin-stdlib-native-sources.zip diff --git a/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlin-test-anotations-common-sources.zip b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlin-test-anotations-common-sources.zip new file mode 100644 index 00000000000..a1fcf901c00 Binary files /dev/null and b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlin-test-anotations-common-sources.zip differ diff --git a/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlin-test-common-sources/placeholder.kt b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlin-test-common-sources/placeholder.kt new file mode 100644 index 00000000000..9c71eb811fe --- /dev/null +++ b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlin-test-common-sources/placeholder.kt @@ -0,0 +1 @@ +// this file is empty diff --git a/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlinx-cli-common-sources.zip b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlinx-cli-common-sources.zip new file mode 100644 index 00000000000..3189a6a5448 Binary files /dev/null and b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlinx-cli-common-sources.zip differ diff --git a/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlinx-cli-native-sources.zip b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlinx-cli-native-sources.zip new file mode 100644 index 00000000000..f2f9a765f13 Binary files /dev/null and b/idea/testData/configuration/klib/kotlin-native-PLATFORM-VERSION/sources/kotlinx-cli-native-sources.zip differ diff --git a/konan/library-reader/build.gradle.kts b/konan/library-reader/build.gradle.kts index 1657758de3f..02717b4daa8 100644 --- a/konan/library-reader/build.gradle.kts +++ b/konan/library-reader/build.gradle.kts @@ -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() 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 deleted file mode 100644 index c51b7696044..00000000000 --- a/konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanLibrary.kt +++ /dev/null @@ -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 - 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 deleted file mode 100644 index 3c3e3094296..00000000000 --- a/konan/library-reader/src/org/jetbrains/kotlin/konan/library/lite/LiteKonanLibraryFacade.kt +++ /dev/null @@ -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? { - 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 { - 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 = emptyList() -} diff --git a/konan/library-reader/test/org/jetbrains/kotlin/konan/library/lite/LiteKonanLibraryFacadeTests.kt b/konan/library-reader/test/org/jetbrains/kotlin/konan/library/lite/LiteKonanLibraryFacadeTests.kt deleted file mode 100644 index 6351e26b1ce..00000000000 --- a/konan/library-reader/test/org/jetbrains/kotlin/konan/library/lite/LiteKonanLibraryFacadeTests.kt +++ /dev/null @@ -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 { - 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 = - getPotentialLibraryPathsOnLocalFS().mapNotNull { libraryProvider.getLibrary(it) }.toLibraryMap() - - private fun librariesExpectedInDistribution(): Map = 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 = listOf( - FakeLibraryForTest(externalLibsDir.resolve("correct")) - ).toLibraryMap() - - private fun compareLibraries(expected: Map, actual: Map, 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 List.toLibraryMap() = map { it.path to it }.toMap() - } -} - -private class FakeLibraryForTest( - override val path: File, - override val platform: String? = null -) : LiteKonanLibrary { - override val sourcePaths: Collection = emptyList() - override val name: String = path.name -} diff --git a/konan/library-reader/test/org/jetbrains/kotlin/konan/library/lite/utils.kt b/konan/library-reader/test/org/jetbrains/kotlin/konan/library/lite/utils.kt deleted file mode 100644 index 336525d30be..00000000000 --- a/konan/library-reader/test/org/jetbrains/kotlin/konan/library/lite/utils.kt +++ /dev/null @@ -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)