IDE: Fix ToolingSingleFileKlibResolveStrategy to recongnize klib archives

Issue #KT-36213
This commit is contained in:
Dmitriy Dolovov
2020-02-01 12:57:28 +07:00
parent ef199f8e45
commit 80eb148092
@@ -6,8 +6,11 @@
package org.jetbrains.kotlin.library package org.jetbrains.kotlin.library
import org.jetbrains.kotlin.konan.file.File import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.file.file
import org.jetbrains.kotlin.konan.file.withZipFileSystem
import org.jetbrains.kotlin.library.impl.createKotlinLibrary import org.jetbrains.kotlin.library.impl.createKotlinLibrary
import org.jetbrains.kotlin.util.Logger import org.jetbrains.kotlin.util.Logger
import java.io.IOException
/** /**
* Resolves KLIB library by making sure that the library has 1.4+ layout with exactly one component. * Resolves KLIB library by making sure that the library has 1.4+ layout with exactly one component.
@@ -23,32 +26,61 @@ import org.jetbrains.kotlin.util.Logger
* Typical usage scenario: IDE. * Typical usage scenario: IDE.
*/ */
object ToolingSingleFileKlibResolveStrategy : SingleFileKlibResolveStrategy { object ToolingSingleFileKlibResolveStrategy : SingleFileKlibResolveStrategy {
override fun resolve(libraryFile: File, logger: Logger): KotlinLibrary { override fun resolve(libraryFile: File, logger: Logger): KotlinLibrary =
if (checkComponent(libraryFile)) { withSafeAccess(libraryFile) { localRoot ->
// old style library if (localRoot.looksLikeKlibComponent) {
return fakeLibrary(libraryFile) // old style library
} null
} else {
val components = localRoot.listFiles.filter { it.looksLikeKlibComponent }
when (components.size) {
0 -> null
1 -> {
// single component library
createKotlinLibrary(libraryFile, components.single().name)
}
else -> { // TODO: choose the best fit among all available candidates
// mimic as old style library and warn
logger.warning("Library $libraryFile can not be read. Multiple components found: ${components.map {
it.path.substringAfter(localRoot.path)
}}")
val componentFiles = libraryFile.listFiles.filter(::checkComponent) null
componentFiles.singleOrNull()?.let { componentFile -> }
// single component library }
return createKotlinLibrary(libraryFile, componentFile.name) }
} } ?: fakeLibrary(libraryFile)
// otherwise mimic as old style library and warn
if (componentFiles.isNotEmpty()) {
// TODO: choose the best fit among all available candidates
logger.warning("Library $libraryFile can not be read. Multiple components found: ${componentFiles.map {
it.path.substringAfter(libraryFile.path)
}}")
}
return fakeLibrary(libraryFile)
}
private const val NONEXISTENT_COMPONENT_NAME = "__nonexistent_component_name__" private const val NONEXISTENT_COMPONENT_NAME = "__nonexistent_component_name__"
private fun checkComponent(componentFile: File) = componentFile.child(KLIB_MANIFEST_FILE_NAME).isFile private fun fakeLibrary(libraryFile: File): KotlinLibrary = createKotlinLibrary(libraryFile, NONEXISTENT_COMPONENT_NAME)
private fun fakeLibrary(libraryFile: File) = createKotlinLibrary(libraryFile, NONEXISTENT_COMPONENT_NAME)
private fun <T : Any> withSafeAccess(libraryFile: File, action: (localRoot: File) -> T?): T? {
val extension = libraryFile.extension
val wrappedAction: () -> T? = when {
extension == KLIB_FILE_EXTENSION -> {
if (!libraryFile.isFile) return null
{ libraryFile.withZipFileSystem { fs -> action(fs.file("/")) } }
}
extension.isNotEmpty() -> return null
else -> {
if (!libraryFile.isDirectory) return null
{ action(libraryFile) }
}
}
return try {
wrappedAction()
} catch (_: IOException) {
null
}
}
private val File.looksLikeKlibComponent: Boolean
get() = child(KLIB_MANIFEST_FILE_NAME).isFile
} }