Separated Zipped and Unzipped libraries.
Picking up files right from the zip filesystem, if possible.
This commit is contained in:
committed by
alexander-gorshenev
parent
56c1f2b07c
commit
5b25613e23
+3
-3
@@ -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.*
|
||||||
|
|||||||
+1
-1
@@ -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
|
||||||
|
|
||||||
|
|||||||
+5
-3
@@ -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
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -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
|
||||||
|
|||||||
+111
@@ -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.")
|
||||||
|
}
|
||||||
|
|
||||||
+30
-52
@@ -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)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
-1
@@ -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) {
|
||||||
|
|||||||
+1
-2
@@ -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()
|
||||||
|
|||||||
+1
-1
@@ -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) {
|
||||||
|
|
||||||
|
|||||||
+112
-56
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user