Separated Zipped and Unzipped libraries.

Picking up files right from the zip filesystem, if possible.
This commit is contained in:
Alexander Gorshenev
2017-07-03 12:54:08 +03:00
committed by alexander-gorshenev
parent 56c1f2b07c
commit 5b25613e23
11 changed files with 293 additions and 151 deletions
@@ -18,15 +18,15 @@ package org.jetbrains.kotlin.backend.konan
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.backend.konan.library.KonanLibraryReader import org.jetbrains.kotlin.backend.konan.library.KonanLibraryReader
import org.jetbrains.kotlin.backend.konan.library.impl.LibraryReaderImpl
import org.jetbrains.kotlin.backend.konan.library.KonanLibrarySearchPathResolver import org.jetbrains.kotlin.backend.konan.library.KonanLibrarySearchPathResolver
import org.jetbrains.kotlin.backend.konan.library.impl.LibraryReaderImpl
import org.jetbrains.kotlin.backend.konan.util.File
import org.jetbrains.kotlin.backend.konan.util.profile import org.jetbrains.kotlin.backend.konan.util.profile
import org.jetbrains.kotlin.backend.konan.util.suffixIfNot
import org.jetbrains.kotlin.backend.konan.util.removeSuffixIfPresent import org.jetbrains.kotlin.backend.konan.util.removeSuffixIfPresent
import org.jetbrains.kotlin.backend.konan.util.suffixIfNot
import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.backend.konan.util.File
import org.jetbrains.kotlin.konan.target.* import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.konan.target.TargetManager.* import org.jetbrains.kotlin.konan.target.TargetManager.*
import org.jetbrains.kotlin.konan.target.CompilerOutputKind.* import org.jetbrains.kotlin.konan.target.CompilerOutputKind.*
@@ -203,7 +203,7 @@ internal class LinkStage(val context: Context) {
val libraries = context.config.libraries val libraries = context.config.libraries
fun llvmLto(files: List<BitcodeFile>): ObjectFile { fun llvmLto(files: List<BitcodeFile>): ObjectFile {
val tmpCombined = File.createTempFile("combined", ".o") val tmpCombined = createTempFile("combined", ".o")
tmpCombined.deleteOnExit() tmpCombined.deleteOnExit()
val combined = tmpCombined.absolutePath val combined = tmpCombined.absolutePath
@@ -20,13 +20,11 @@ import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.backend.konan.util.File import org.jetbrains.kotlin.backend.konan.util.File
// This scheme describes the Konan Library (klib) layout. // This scheme describes the Konan Library (klib) layout.
interface KonanLibrary { interface KonanLibraryLayout {
val libDir: File val libDir: File
val target: KonanTarget? val target: KonanTarget?
// This is a default implementation. Can't make it an assignment. // This is a default implementation. Can't make it an assignment.
get() = null get() = null
val klibFile
get() = File("${libDir.path}.klib")
val manifestFile val manifestFile
get() = File(libDir, "manifest") get() = File(libDir, "manifest")
val resourcesDir val resourcesDir
@@ -47,3 +45,7 @@ interface KonanLibrary {
= File(linkdataDir, if (packageName == "") "root_package" else "package_$packageName") = File(linkdataDir, if (packageName == "") "root_package" else "package_$packageName")
} }
interface KonanLibrary: KonanLibraryLayout {
val libraryName: String
}
@@ -50,8 +50,7 @@ class KonanLibrarySearchPathResolver(repositories: List<String>,
val noSuffix = File(candidate.path.removeSuffixIfPresent(".klib")) val noSuffix = File(candidate.path.removeSuffixIfPresent(".klib"))
val withSuffix = File(candidate.path.suffixIfNot(".klib")) val withSuffix = File(candidate.path.suffixIfNot(".klib"))
if (withSuffix.exists) { if (withSuffix.exists) {
// We always returing the name without suffix here. return withSuffix
return noSuffix
} }
if (noSuffix.exists) { if (noSuffix.exists) {
return noSuffix return noSuffix
@@ -0,0 +1,111 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.backend.konan.library.impl
import org.jetbrains.kotlin.backend.konan.library.KonanLibrary
import org.jetbrains.kotlin.backend.konan.util.*
import org.jetbrains.kotlin.konan.target.KonanTarget
open class ZippedKonanLibrary(val klibFile: File, override val target: KonanTarget? = null): KonanLibrary {
init {
if (!klibFile.exists) {
error("Could not find $klibFile.")
}
if (!klibFile.isFile) {
error("Expected $klibFile to be a regular file.")
}
}
override val libraryName = klibFile.path.removeSuffixIfPresent(".klib")
override val libDir by lazy {
klibFile.asZipRoot
}
fun unpackTo(newDir: File) {
if (newDir.exists) {
if (newDir.isDirectory)
newDir.deleteRecursively()
else
newDir.delete()
}
libDir.recursiveCopyTo(newDir)
if (!newDir.exists) error("Could not unpack $klibFile as $newDir.")
}
}
// This class automatically extracts pieces of
// the library on first access. Use it if you need
// to pass extracted files to an external tool.
// Otherwise, stick to ZippedKonanLibrary.
class FileExtractor(zippedLibrary: KonanLibrary): KonanLibrary by zippedLibrary {
override val manifestFile: File by lazy {
extract(super.manifestFile)
}
override val resourcesDir: File by lazy {
extractDir(super.resourcesDir)
}
override val kotlinDir: File by lazy {
extractDir(super.kotlinDir)
}
override val nativeDir: File by lazy {
extractDir(super.nativeDir)
}
override val linkdataDir: File by lazy {
extractDir(super.linkdataDir)
}
fun extract(file: File): File {
val temporary = createTempFile(file.name)
file.copyTo(temporary)
temporary.deleteOnExit()
return temporary
}
fun extractDir(directory: File): File {
val temporary = createTempDir(directory.name)
directory.recursiveCopyTo(temporary)
temporary.deleteOnExitRecursively()
return temporary
}
}
class UnzippedKonanLibrary(override val libDir: File, override val target: KonanTarget? = null): KonanLibrary {
override val libraryName = libDir.path
val targetList: List<String> by lazy {
targetsDir.listFiles.map{it.name}
}
}
fun KonanLibrary(klib: File, target: KonanTarget? = null) =
if (klib.isFile) ZippedKonanLibrary(klib, target)
else UnzippedKonanLibrary(klib, target)
val KonanLibrary.realFiles
get() = when (this) {
is ZippedKonanLibrary -> FileExtractor(this)
// Unpacked library just provides its own files.
is UnzippedKonanLibrary -> this
else -> error("Provide an extractor for your container.")
}
@@ -16,66 +16,28 @@
package org.jetbrains.kotlin.backend.konan.library.impl package org.jetbrains.kotlin.backend.konan.library.impl
import org.jetbrains.kotlin.backend.konan.library.KonanLibrary
import org.jetbrains.kotlin.backend.konan.library.KonanLibraryReader import org.jetbrains.kotlin.backend.konan.library.KonanLibraryReader
import org.jetbrains.kotlin.backend.konan.library.MetadataReader
import org.jetbrains.kotlin.backend.konan.serialization.deserializeModule import org.jetbrains.kotlin.backend.konan.serialization.deserializeModule
import org.jetbrains.kotlin.backend.konan.util.* import org.jetbrains.kotlin.backend.konan.util.File
import org.jetbrains.kotlin.backend.konan.util.Properties
import org.jetbrains.kotlin.backend.konan.util.loadProperties
import org.jetbrains.kotlin.backend.konan.util.propertyList
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
abstract class FileBasedLibraryReader( class LibraryReaderImpl(var libraryFile: File, val currentAbiVersion: Int, val target: KonanTarget? = null) : KonanLibraryReader {
val file: File, val currentAbiVersion: Int,
val reader: MetadataReader): KonanLibraryReader {
override val libraryName: String // For the zipped libraries inPlace gives files from zip file system
get() = file.path // whereas realFiles extracts them to /tmp.
// For unzipped libraries inPlace and realFiles are the same
// providing files in the library directory.
private val inPlace = KonanLibrary(libraryFile, target)
private val realFiles = inPlace.realFiles
val moduleHeaderData: ByteArray by lazy { private val reader = MetadataReaderImpl(inPlace)
reader.loadSerializedModule()
}
fun packageMetadata(fqName: String): ByteArray =
reader.loadSerializedPackageFragment(fqName)
override fun moduleDescriptor(specifics: LanguageVersionSettings)
= deserializeModule(specifics, {packageMetadata(it)},
moduleHeaderData)
}
class LibraryReaderImpl(override val libDir: File, currentAbiVersion: Int,
override val target: KonanTarget?) :
FileBasedLibraryReader(libDir, currentAbiVersion, MetadataReaderImpl(libDir)),
KonanLibrary {
public constructor(path: String, currentAbiVersion: Int, target: KonanTarget?) :
this(File(path), currentAbiVersion, target)
init {
unpackIfNeeded()
}
// TODO: Search path processing is also goes somewhere around here.
fun unpackIfNeeded() {
// TODO: Clarify the policy here.
if (libDir.exists) {
if (libDir.isDirectory) return
}
if (!klibFile.exists) {
error("Could not find neither $libDir nor $klibFile.")
}
if (klibFile.isFile) {
klibFile.unzipAs(libDir)
if (!libDir.exists) error("Could not unpack $klibFile as $libDir.")
} else {
error("Expected $klibFile to be a regular file.")
}
}
val manifestProperties: Properties by lazy { val manifestProperties: Properties by lazy {
manifestFile.loadProperties() inPlace.manifestFile.loadProperties()
} }
val abiVersion: String val abiVersion: String
@@ -86,10 +48,26 @@ class LibraryReaderImpl(override val libDir: File, currentAbiVersion: Int,
return manifestAbiVersion return manifestAbiVersion
} }
val targetList = inPlace.targetsDir.listFiles.map{it.name}
override val libraryName
get() = inPlace.libraryName
override val bitcodePaths: List<String> override val bitcodePaths: List<String>
get() = (kotlinDir.listFiles + nativeDir.listFiles).map{it.absolutePath} get() = (realFiles.kotlinDir.listFiles + realFiles.nativeDir.listFiles).map{it.absolutePath}
override val linkerOpts: List<String> override val linkerOpts: List<String>
get() = manifestProperties.propertyList("linkerOpts", target!!.targetSuffix) get() = manifestProperties.propertyList("linkerOpts", target!!.targetSuffix)
val moduleHeaderData: ByteArray by lazy {
reader.loadSerializedModule()
}
fun packageMetadata(fqName: String): ByteArray =
reader.loadSerializedPackageFragment(fqName)
override fun moduleDescriptor(specifics: LanguageVersionSettings)
= deserializeModule(specifics, {packageMetadata(it)}, moduleHeaderData)
} }
@@ -36,6 +36,10 @@ class LibraryWriterImpl(override val libDir: File, currentAbiVersion: Int,
target:KonanTarget?, nopack: Boolean): target:KonanTarget?, nopack: Boolean):
this(File(path), currentAbiVersion, target, nopack) this(File(path), currentAbiVersion, target, nopack)
override val libraryName = libDir.path
val klibFile
get() = File("${libDir.path}.klib")
// TODO: Experiment with separate bitcode files. // TODO: Experiment with separate bitcode files.
// Per package or per class. // Per package or per class.
val mainBitcodeFile = File(kotlinDir, "program.kt.bc") val mainBitcodeFile = File(kotlinDir, "program.kt.bc")
@@ -63,7 +67,7 @@ class LibraryWriterImpl(override val libDir: File, currentAbiVersion: Int,
} }
override fun addLinkData(linkData: LinkData) { override fun addLinkData(linkData: LinkData) {
MetadataWriterImpl(libDir).addLinkData(linkData) MetadataWriterImpl(this).addLinkData(linkData)
} }
override fun addNativeBitcode(library: String) { override fun addNativeBitcode(library: String) {
@@ -18,9 +18,8 @@ package org.jetbrains.kotlin.backend.konan.library.impl
import org.jetbrains.kotlin.backend.konan.library.KonanLibrary import org.jetbrains.kotlin.backend.konan.library.KonanLibrary
import org.jetbrains.kotlin.backend.konan.library.MetadataReader import org.jetbrains.kotlin.backend.konan.library.MetadataReader
import org.jetbrains.kotlin.backend.konan.util.File
class MetadataReaderImpl(override val libDir: File) : MetadataReader, KonanLibrary { class MetadataReaderImpl(library: KonanLibrary) : MetadataReader, KonanLibrary by library {
override fun loadSerializedModule(): ByteArray { override fun loadSerializedModule(): ByteArray {
return moduleHeaderFile.readBytes() return moduleHeaderFile.readBytes()
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.backend.konan.library.KonanLibrary
import org.jetbrains.kotlin.backend.konan.library.LinkData import org.jetbrains.kotlin.backend.konan.library.LinkData
import org.jetbrains.kotlin.backend.konan.util.File import org.jetbrains.kotlin.backend.konan.util.File
internal class MetadataWriterImpl(override val libDir: File): KonanLibrary { internal class MetadataWriterImpl(library: KonanLibrary): KonanLibrary by library {
fun addLinkData(linkData: LinkData) { fun addLinkData(linkData: LinkData) {
@@ -20,53 +20,106 @@ import java.io.BufferedReader
import java.io.InputStream import java.io.InputStream
import java.io.InputStreamReader import java.io.InputStreamReader
import java.net.URI import java.net.URI
import java.nio.file.FileSystems import java.nio.file.*
import java.nio.file.Files import java.nio.file.attribute.BasicFileAttributes
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.StandardCopyOption
class File(val path: String) { class File constructor(internal val javaPath: Path) {
private constructor(file: java.io.File): this(file.path) constructor(parent: Path, child: String): this(parent.resolve(child))
constructor(parent: String, child: String): this(java.io.File(parent, child)) constructor(parent: File, child: String): this(parent.javaPath.resolve(child))
constructor(parent: File, child: String): this(java.io.File(parent.path, child)) constructor(path: String): this(Paths.get(path))
constructor(parent: String, child: String): this(Paths.get(parent, child))
private val javaFile = java.io.File(path) val path: String
get() = javaPath.toString()
val absolutePath: String val absolutePath: String
get() = javaFile.absolutePath get() = javaPath.toAbsolutePath().toString()
val absoluteFile: File val absoluteFile: File
get() = File(absolutePath) get() = File(absolutePath)
val name: String val name: String
get() = javaFile.name get() = javaPath.fileName.toString()
val parent: String val parent: String
get() = javaFile.parent get() = javaPath.parent.toString()
val exists val exists
get() = javaFile.exists() get() = Files.exists(javaPath)
val isDirectory val isDirectory
get() = javaFile.isDirectory() get() = Files.isDirectory(javaPath)
val isFile val isFile
get() = javaFile.isFile() get() = Files.isRegularFile(javaPath)
val isAbsolute val isAbsolute
get() = javaFile.isAbsolute() get() = javaPath.isAbsolute()
val listFiles val listFiles: List<File>
get() = javaFile.listFiles()!!.toList() get() {
val stream = Files.newDirectoryStream(javaPath)
val result = mutableListOf<File>()
for (entry in stream) {
result.add(File(entry))
}
return result
}
fun mkdirs() = javaFile.mkdirs() fun copyTo(destination: File, vararg options: StandardCopyOption) {
fun delete() = javaFile.delete() Files.copy(javaPath, destination.javaPath, StandardCopyOption.REPLACE_EXISTING)
fun deleteRecursively() = javaFile.deleteRecursively() }
fun deleteOnExit() = javaFile.deleteOnExit()
fun readText() = javaFile.readText() fun recursiveCopyTo(destination: File) {
fun readBytes() = javaFile.readBytes() val sourcePath = javaPath
fun writeText(text: String) = javaFile.writeText(text) val destPath = destination.javaPath
fun writeBytes(bytes: ByteArray) = javaFile.writeBytes(bytes) sourcePath.recursiveCopyTo(destPath)
fun forEachLine(action: (String) -> Unit) { javaFile.forEachLine { action(it) } } }
fun mkdirs() = Files.createDirectories(javaPath)
fun delete() = Files.deleteIfExists(javaPath)
fun deleteRecursively() = postorder{Files.delete(it)}
fun deleteOnExitRecursively() = preorder{File(it).deleteOnExit()}
fun preorder(task: (Path) -> Unit) {
if (!this.exists) return
Files.walkFileTree(javaPath, object: SimpleFileVisitor<Path>() {
override fun visitFile(file: Path?, attrs: BasicFileAttributes?): FileVisitResult {
task(file!!)
return FileVisitResult.CONTINUE
}
override fun preVisitDirectory(dir: Path?, attrs: BasicFileAttributes?): FileVisitResult {
task(dir!!)
return FileVisitResult.CONTINUE
}
})
}
fun postorder(task: (Path) -> Unit) {
if (!this.exists) return
Files.walkFileTree(javaPath, object: SimpleFileVisitor<Path>() {
override fun visitFile(file: Path?, attrs: BasicFileAttributes?): FileVisitResult {
task(file!!)
return FileVisitResult.CONTINUE
}
override fun postVisitDirectory(dir: Path?, exc: java.io.IOException?): FileVisitResult {
task(dir!!)
return FileVisitResult.CONTINUE
}
})
}
fun deleteOnExit() {
// Works only on the default file system,
// but that's okay for now.
javaPath.toFile().deleteOnExit()
}
fun readBytes() = Files.readAllBytes(javaPath)
fun writeBytes(bytes: ByteArray) = Files.write(javaPath, bytes)
fun forEachLine(action: (String) -> Unit) { Files.lines(javaPath).forEach { action(it) } }
override fun toString() = path override fun toString() = path
// TODO: Consider removeing these after konanazing java.util.Properties. // TODO: Consider removeing these after konanazing java.util.Properties.
fun bufferedReader() = javaFile.bufferedReader() fun bufferedReader() = Files.newBufferedReader(javaPath)
fun outputStream() = javaFile.outputStream() fun outputStream() = Files.newOutputStream(javaPath)
companion object { companion object {
val userDir val userDir
@@ -75,38 +128,44 @@ class File(val path: String) {
val userHome val userHome
get() = File(System.getProperty("user.home")) get() = File(System.getProperty("user.home"))
fun createTempFile(name: String, suffix: String? = null, directory: File? = null): File {
val javaDirectory = directory ?.let { java.io.File(directory.path) }
return java.io.File.createTempFile(name, suffix, javaDirectory).path.File()
}
} }
} }
fun String.File() = File(this) fun String.File(): File = File(this)
fun Path.File(): File = File(this)
fun createTempFile(name: String, suffix: String? = null)
= Files.createTempFile(name, suffix).File()
fun createTempDir(name: String): File
= Files.createTempDirectory(name).File()
private val File.zipUri: URI private val File.zipUri: URI
get() = URI.create("jar:${this.toPath().toUri()}") get() = URI.create("jar:${this.toPath().toUri()}")
private val File.zipRootPath: Path fun File.zipFileSystem(mutable: Boolean = false): FileSystem {
get() { val zipUri = this.zipUri
val zipUri = this.zipUri val allowCreation = if (mutable) "true" else "false"
val allowCreation = hashMapOf("create" to "true") val attributes = hashMapOf("create" to if (mutable) "true" else "false")
val zipfs = FileSystems.newFileSystem(zipUri, allowCreation, null) return FileSystems.newFileSystem(zipUri, attributes, null)
return zipfs.getPath("/") }
}
fun File.mutableZipFileSystem() = this.zipFileSystem(mutable = true)
fun File.zipPath(path: String): Path
= this.zipFileSystem().getPath(path)
val File.asZipRoot: File
get() = File(this.zipPath("/"))
val File.asWritableZipRoot: File
get() = File(this.mutableZipFileSystem().getPath("/"))
private fun File.toPath() = Paths.get(this.path) private fun File.toPath() = Paths.get(this.path)
fun File.zipDirAs(zipFile: File) { fun File.zipDirAs(unixFile: File) {
val zipPath = zipFile.zipRootPath val zipRoot = unixFile.asWritableZipRoot
this.toPath().recursiveCopyTo(zipPath) this.recursiveCopyTo(zipRoot)
zipPath.fileSystem.close() zipRoot.javaPath.fileSystem.close()
}
fun File.unzipAs(directory: File) {
val zipPath = this.zipRootPath
zipPath.recursiveCopyTo(directory.toPath())
zipPath.fileSystem.close()
} }
fun Path.recursiveCopyTo(destPath: Path) { fun Path.recursiveCopyTo(destPath: Path) {
@@ -126,8 +185,5 @@ fun Path.recursiveCopyTo(destPath: Path) {
} }
} }
fun File.copyTo(destination: File, vararg options: StandardCopyOption) { fun bufferedReader(errorStream: InputStream?) = BufferedReader(InputStreamReader(errorStream))
Files.copy(this.toPath(), destination.toPath(), *options)
}
fun bufferedReader(errorStream: InputStream?) = BufferedReader(InputStreamReader(errorStream))
@@ -19,10 +19,10 @@ package org.jetbrains.kotlin.cli.klib
import kotlin.system.exitProcess import kotlin.system.exitProcess
import java.util.Properties import java.util.Properties
// TODO: Extract these as a shared jar? // TODO: Extract these as a shared jar?
import org.jetbrains.kotlin.backend.konan.library.impl.LibraryReaderImpl import org.jetbrains.kotlin.backend.konan.library.impl.*
import org.jetbrains.kotlin.backend.konan.library.KonanLibrary
import org.jetbrains.kotlin.backend.konan.library.KonanLibrarySearchPathResolver import org.jetbrains.kotlin.backend.konan.library.KonanLibrarySearchPathResolver
import org.jetbrains.kotlin.backend.konan.util.File import org.jetbrains.kotlin.backend.konan.util.File
import org.jetbrains.kotlin.backend.konan.util.copyTo
import org.jetbrains.kotlin.konan.target.TargetManager import org.jetbrains.kotlin.konan.target.TargetManager
fun printUsage() { fun printUsage() {
@@ -83,53 +83,49 @@ class Library(val name: String, val requestedRepository: String?, val target: St
val repository = requestedRepository?.File() ?: defaultRepository val repository = requestedRepository?.File() ?: defaultRepository
fun info() { fun info() {
val library = libraryInRepoOrCurrentDir(repository, name) val library = libraryInRepoOrCurrentDir(repository, name)
val header = Properties() val reader = LibraryReaderImpl(library, currentAbiVersion)
val manifestFile = library.manifestFile val header = reader.manifestProperties
manifestFile.bufferedReader().use { reader -> val headerAbiVersion = reader.abiVersion
header.load(reader) val moduleName = ModuleDeserializer(reader.moduleHeaderData).moduleName
}
val headerAbiVersion = library.abiVersion
val moduleName = ModuleDeserializer(library.moduleHeaderData).moduleName
println("") println("")
println("Resolved to: ${library.libDir.absolutePath}") println("Resolved to: ${reader.libraryName.File().absolutePath}")
println("Module name: $moduleName") println("Module name: $moduleName")
println("ABI version: $headerAbiVersion") println("ABI version: $headerAbiVersion")
val targets = library.targetsDir.listFiles.map{it.name}.joinToString(", ") val targets = reader.targetList.joinToString(", ")
print("Available targets: $targets\n") print("Available targets: $targets\n")
} }
fun install() { fun install() {
remove(true) remove(true)
val klibFile = libraryInCurrentDir(name).klibFile val library = ZippedKonanLibrary(libraryInCurrentDir(name))
val newLocation = File(repository, "klib") val newLocation = File(repository, "klib")
newLocation.mkdirs() val newLibDir = File(newLocation, library.libraryName.File().name)
val newFile = File(newLocation, klibFile.name) newLibDir.mkdirs()
klibFile.copyTo(newFile) library.unpackTo(newLibDir)
} }
fun remove(blind: Boolean = false) { fun remove(blind: Boolean = false) {
if (!repository.exists) error("Repository does not exist: $repository") if (!repository.exists) error("Repository does not exist: $repository")
val library = try { val reader = try {
val library = libraryInRepo(repository, name) val library = libraryInRepo(repository, name)
if (blind) warn("Removing The previously installed $name from $repository.") if (blind) warn("Removing The previously installed $name from $repository.")
library UnzippedKonanLibrary(library)
} catch (e: Throwable) { } catch (e: Throwable) {
if (!blind) println(e.message) if (!blind) println(e.message)
null null
} }
library?.libDir?.deleteRecursively() reader?.libDir?.deleteRecursively()
library?.klibFile?.delete()
} }
fun contents() { fun contents() {
val library = libraryInRepoOrCurrentDir(repository, name) val reader = LibraryReaderImpl(libraryInRepoOrCurrentDir(repository, name), currentAbiVersion)
val printer = PrettyPrinter( val printer = PrettyPrinter(
library.moduleHeaderData, {name -> library.packageMetadata(name)}) reader.moduleHeaderData, {name -> reader.packageMetadata(name)})
printer.packageFragmentNameList.forEach{ printer.packageFragmentNameList.forEach{
printer.printPackageFragment(it) printer.printPackageFragment(it)
@@ -140,22 +136,19 @@ class Library(val name: String, val requestedRepository: String?, val target: St
// TODO: need to do something here. // TODO: need to do something here.
val currentAbiVersion = 1 val currentAbiVersion = 1
val File.konanLibrary fun libraryInRepo(repository: File, name: String): File {
get() = LibraryReaderImpl(this, currentAbiVersion, null)
fun libraryInRepo(repository: File, name: String): LibraryReaderImpl {
val resolver = KonanLibrarySearchPathResolver(listOf(repository.absolutePath), null, null, skipCurrentDir = true) val resolver = KonanLibrarySearchPathResolver(listOf(repository.absolutePath), null, null, skipCurrentDir = true)
return resolver.resolve(name).konanLibrary return resolver.resolve(name)
} }
fun libraryInCurrentDir(name: String): LibraryReaderImpl { fun libraryInCurrentDir(name: String): File {
val resolver = KonanLibrarySearchPathResolver(emptyList(), null, null) val resolver = KonanLibrarySearchPathResolver(emptyList(), null, null)
return resolver.resolve(name).konanLibrary return resolver.resolve(name)
} }
fun libraryInRepoOrCurrentDir(repository: File, name: String): LibraryReaderImpl { fun libraryInRepoOrCurrentDir(repository: File, name: String): File {
val resolver = KonanLibrarySearchPathResolver(listOf(repository.absolutePath), null, null) val resolver = KonanLibrarySearchPathResolver(listOf(repository.absolutePath), null, null)
return resolver.resolve(name).konanLibrary return resolver.resolve(name)
} }