Extract JS-related LibraryUtils utilities to JsLibraryUtils
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.utils
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.util.Processor
|
||||
import org.jetbrains.kotlin.utils.fileUtils.withReplacedExtensionOrNull
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
object JsLibraryUtils {
|
||||
private val LOG = Logger.getInstance(LibraryUtils::class.java)
|
||||
|
||||
private val META_INF_RESOURCES = "${LibraryUtils.META_INF}resources/"
|
||||
|
||||
@JvmStatic fun copyJsFilesFromLibraries(libraries: List<String>, outputLibraryJsPath: String) {
|
||||
for (library in libraries) {
|
||||
val file = File(library)
|
||||
assert(file.exists()) { "Library $library not found" }
|
||||
|
||||
if (file.isDirectory) {
|
||||
copyJsFilesFromDirectory(file, outputLibraryJsPath)
|
||||
}
|
||||
else {
|
||||
copyJsFilesFromZip(file, outputLibraryJsPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic fun traverseJsLibraries(libs: List<File>, action: (content: String, path: String) -> Unit) {
|
||||
libs.forEach { traverseJsLibrary(it, action) }
|
||||
}
|
||||
|
||||
@JvmStatic fun traverseJsLibrary(lib: File, action: (content: String, path: String) -> Unit) {
|
||||
when {
|
||||
lib.isDirectory -> traverseDirectory(lib, action)
|
||||
FileUtil.isJarOrZip(lib) -> traverseArchive(lib, action)
|
||||
lib.name.endsWith(KotlinJavascriptMetadataUtils.JS_EXT) -> {
|
||||
lib.runIfFileExists(action)
|
||||
val jsFile = lib.withReplacedExtensionOrNull(
|
||||
KotlinJavascriptMetadataUtils.META_JS_SUFFIX, KotlinJavascriptMetadataUtils.JS_EXT
|
||||
)
|
||||
jsFile?.runIfFileExists(action)
|
||||
}
|
||||
else -> throw IllegalArgumentException("Unknown library format (directory, zip or js file expected): $lib")
|
||||
}
|
||||
}
|
||||
|
||||
private fun File.runIfFileExists(action: (content: String, path: String) -> Unit) {
|
||||
if (isFile) {
|
||||
action(FileUtil.loadFile(this), "")
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyJsFilesFromDirectory(dir: File, outputLibraryJsPath: String) {
|
||||
traverseDirectory(dir) { content, relativePath ->
|
||||
FileUtil.writeToFile(File(outputLibraryJsPath, relativePath), content)
|
||||
}
|
||||
}
|
||||
|
||||
private fun processDirectory(dir: File, action: (content: String, relativePath: String) -> Unit) {
|
||||
FileUtil.processFilesRecursively(dir, Processor<File> { file ->
|
||||
val relativePath = FileUtil.getRelativePath(dir, file)
|
||||
?: throw IllegalArgumentException("relativePath should not be null $dir $file")
|
||||
if (file.isFile && relativePath.endsWith(KotlinJavascriptMetadataUtils.JS_EXT)) {
|
||||
val suggestedRelativePath = getSuggestedPath(relativePath) ?: return@Processor true
|
||||
action(FileUtil.loadFile(file), suggestedRelativePath)
|
||||
}
|
||||
true
|
||||
})
|
||||
}
|
||||
|
||||
private fun traverseDirectory(dir: File, action: (content: String, relativePath: String) -> Unit) {
|
||||
try {
|
||||
processDirectory(dir, action)
|
||||
}
|
||||
catch (ex: IOException) {
|
||||
LOG.error("Could not read files from directory ${dir.name}: ${ex.message}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyJsFilesFromZip(file: File, outputLibraryJsPath: String) {
|
||||
traverseArchive(file) { content, relativePath ->
|
||||
FileUtil.writeToFile(File(outputLibraryJsPath, relativePath), content)
|
||||
}
|
||||
}
|
||||
|
||||
private fun traverseArchive(file: File, action: (content: String, relativePath: String) -> Unit) {
|
||||
val zipFile = ZipFile(file.path)
|
||||
try {
|
||||
val zipEntries = zipFile.entries()
|
||||
while (zipEntries.hasMoreElements()) {
|
||||
val entry = zipEntries.nextElement()
|
||||
val entryName = entry.name
|
||||
if (!entry.isDirectory && entryName.endsWith(KotlinJavascriptMetadataUtils.JS_EXT)) {
|
||||
val relativePath = getSuggestedPath(entryName) ?: continue
|
||||
|
||||
val stream = zipFile.getInputStream(entry)
|
||||
val content = FileUtil.loadTextAndClose(stream)
|
||||
action(content, relativePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ex: IOException) {
|
||||
LOG.error("Could not extract files from archive ${file.name}: ${ex.message}")
|
||||
}
|
||||
finally {
|
||||
zipFile.close()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSuggestedPath(path: String): String? {
|
||||
val systemIndependentPath = FileUtil.toSystemIndependentName(path)
|
||||
if (systemIndependentPath.startsWith(LibraryUtils.META_INF)) {
|
||||
if (systemIndependentPath.startsWith(META_INF_RESOURCES)) {
|
||||
return path.substring(META_INF_RESOURCES.length)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ object KotlinJavascriptMetadataUtils {
|
||||
const val VFS_PROTOCOL: String = "kotlin-js-meta"
|
||||
private val KOTLIN_JAVASCRIPT_METHOD_NAME = "kotlin_module_metadata"
|
||||
private val KOTLIN_JAVASCRIPT_METHOD_NAME_PATTERN = "\\.kotlin_module_metadata\\(".toPattern()
|
||||
|
||||
/**
|
||||
* Matches string like <name>.kotlin_module_metadata(<abi version>, <module name>, <base64 data>)
|
||||
*/
|
||||
@@ -44,28 +45,13 @@ object KotlinJavascriptMetadataUtils {
|
||||
@JvmStatic fun hasMetadata(text: String): Boolean =
|
||||
KOTLIN_JAVASCRIPT_METHOD_NAME_PATTERN.matcher(text).find() && METADATA_PATTERN.matcher(text).find()
|
||||
|
||||
fun hasMetadataWithIncompatibleAbiVersion(text: String): Boolean {
|
||||
val matcher = METADATA_PATTERN.matcher(text)
|
||||
while (matcher.find()) {
|
||||
var abiVersion = matcher.group(1).toInt()
|
||||
if (abiVersion != ABI_VERSION) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
fun formatMetadataAsString(moduleName: String, content: ByteArray): String =
|
||||
"// Kotlin.$KOTLIN_JAVASCRIPT_METHOD_NAME($ABI_VERSION, \"$moduleName\", \"${printBase64Binary(content)}\");\n"
|
||||
|
||||
@JvmStatic fun loadMetadata(file: File): List<KotlinJavascriptMetadata> {
|
||||
assert(file.exists()) { "Library " + file + " not found" }
|
||||
assert(file.exists()) { "Library $file not found" }
|
||||
val metadataList = arrayListOf<KotlinJavascriptMetadata>()
|
||||
LibraryUtils.traverseJsLibrary(file) { content, relativePath ->
|
||||
var path = file.path
|
||||
|
||||
if (relativePath.isNotBlank()) {
|
||||
path += "/$relativePath"
|
||||
}
|
||||
|
||||
JsLibraryUtils.traverseJsLibrary(file) { content, relativePath ->
|
||||
parseMetadata(content, metadataList)
|
||||
}
|
||||
|
||||
|
||||
@@ -17,16 +17,12 @@
|
||||
package org.jetbrains.kotlin.utils
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.util.Processor
|
||||
import org.jetbrains.kotlin.utils.fileUtils.withReplacedExtensionOrNull
|
||||
import java.io.*
|
||||
import java.util.Properties
|
||||
import java.util.*
|
||||
import java.util.jar.Attributes
|
||||
import java.util.jar.JarFile
|
||||
import java.util.jar.Manifest
|
||||
import java.util.zip.ZipFile
|
||||
|
||||
object LibraryUtils {
|
||||
private val LOG = Logger.getInstance(LibraryUtils::class.java)
|
||||
@@ -34,9 +30,9 @@ object LibraryUtils {
|
||||
val KOTLIN_JS_MODULE_NAME: String = "Kotlin-JS-Module-Name"
|
||||
private var TITLE_KOTLIN_JAVASCRIPT_STDLIB: String
|
||||
private var TITLE_KOTLIN_JAVASCRIPT_LIB: String
|
||||
private val METAINF = "META-INF/"
|
||||
private val MANIFEST_PATH = "${METAINF}MANIFEST.MF"
|
||||
private val METAINF_RESOURCES = "${METAINF}resources/"
|
||||
|
||||
val META_INF = "META-INF/"
|
||||
private val MANIFEST_PATH = "${META_INF}MANIFEST.MF"
|
||||
private val KOTLIN_JS_MODULE_ATTRIBUTE_NAME = Attributes.Name(KOTLIN_JS_MODULE_NAME)
|
||||
|
||||
init {
|
||||
@@ -73,10 +69,13 @@ object LibraryUtils {
|
||||
}
|
||||
|
||||
@JvmStatic fun isOldKotlinJavascriptLibrary(library: File): Boolean =
|
||||
checkAttributeValue(library, TITLE_KOTLIN_JAVASCRIPT_LIB, Attributes.Name.SPECIFICATION_TITLE) && getKotlinJsModuleName(library) != null
|
||||
checkAttributeValue(library, TITLE_KOTLIN_JAVASCRIPT_LIB, Attributes.Name.SPECIFICATION_TITLE) &&
|
||||
getKotlinJsModuleName(library) != null
|
||||
|
||||
@JvmStatic fun isKotlinJavascriptLibraryWithMetadata(library: File): Boolean = KotlinJavascriptMetadataUtils.loadMetadata(library).isNotEmpty()
|
||||
@JvmStatic fun isKotlinJavascriptLibraryWithMetadata(library: File): Boolean =
|
||||
KotlinJavascriptMetadataUtils.loadMetadata(library).isNotEmpty()
|
||||
|
||||
@Suppress("unused") // used in K2JSCompilerMojo
|
||||
@JvmStatic fun isKotlinJavascriptLibrary(library: File): Boolean =
|
||||
isOldKotlinJavascriptLibrary(library) || isKotlinJavascriptLibraryWithMetadata(library)
|
||||
|
||||
@@ -84,117 +83,6 @@ object LibraryUtils {
|
||||
return checkAttributeValue(library, TITLE_KOTLIN_JAVASCRIPT_STDLIB, Attributes.Name.IMPLEMENTATION_TITLE)
|
||||
}
|
||||
|
||||
@JvmStatic fun copyJsFilesFromLibraries(libraries: List<String>, outputLibraryJsPath: String) {
|
||||
for (library in libraries) {
|
||||
val file = File(library)
|
||||
assert(file.exists()) { "Library " + library + " not found" }
|
||||
|
||||
if (file.isDirectory) {
|
||||
copyJsFilesFromDirectory(file, outputLibraryJsPath)
|
||||
}
|
||||
else {
|
||||
copyJsFilesFromZip(file, outputLibraryJsPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic fun traverseJsLibraries(libs: List<File>, action: (content: String, path: String)->Unit) {
|
||||
libs.forEach { traverseJsLibrary(it, action) }
|
||||
}
|
||||
|
||||
@JvmStatic fun traverseJsLibrary(lib: File, action: (content: String, path: String)->Unit) {
|
||||
when {
|
||||
lib.isDirectory -> traverseDirectory(lib, action)
|
||||
FileUtil.isJarOrZip(lib) -> traverseArchive(lib, action)
|
||||
lib.name.endsWith(KotlinJavascriptMetadataUtils.JS_EXT) -> {
|
||||
lib.runIfFileExists(action)
|
||||
val jsFile = lib.withReplacedExtensionOrNull(KotlinJavascriptMetadataUtils.META_JS_SUFFIX, KotlinJavascriptMetadataUtils.JS_EXT)
|
||||
jsFile?.runIfFileExists(action)
|
||||
}
|
||||
else ->
|
||||
throw IllegalArgumentException("Unknown library format (directory, zip or js file expected): $lib")
|
||||
}
|
||||
}
|
||||
|
||||
private fun File.runIfFileExists(action: (content: String, path: String)->Unit) {
|
||||
if (isFile) {
|
||||
action(FileUtil.loadFile(this), "")
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyJsFilesFromDirectory(dir: File, outputLibraryJsPath: String) {
|
||||
traverseDirectory(dir) {
|
||||
content, relativePath -> FileUtil.writeToFile(File(outputLibraryJsPath, relativePath), content)
|
||||
}
|
||||
}
|
||||
|
||||
private fun processDirectory(dir: File, action: (content: String, relativePath: String) -> Unit) {
|
||||
FileUtil.processFilesRecursively(dir, object : Processor<File> {
|
||||
override fun process(file: File): Boolean {
|
||||
val relativePath = FileUtil.getRelativePath(dir, file) ?: throw IllegalArgumentException("relativePath should not be null " + dir + " " + file)
|
||||
if (file.isFile && relativePath.endsWith(KotlinJavascriptMetadataUtils.JS_EXT)) {
|
||||
val suggestedRelativePath = getSuggestedPath(relativePath)
|
||||
if (suggestedRelativePath == null) return true
|
||||
|
||||
action(FileUtil.loadFile(file), suggestedRelativePath)
|
||||
}
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun traverseDirectory(dir: File, action: (content: String, relativePath: String) -> Unit) {
|
||||
try {
|
||||
processDirectory(dir, action)
|
||||
}
|
||||
catch (ex: IOException) {
|
||||
LOG.error("Could not read files from directory ${dir.name}: ${ex.message}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyJsFilesFromZip(file: File, outputLibraryJsPath: String) {
|
||||
traverseArchive(file) { content, relativePath ->
|
||||
FileUtil.writeToFile(File(outputLibraryJsPath, relativePath), content)
|
||||
}
|
||||
}
|
||||
|
||||
fun traverseArchive(file: File, action: (content: String, relativePath: String) -> Unit) {
|
||||
val zipFile = ZipFile(file.path)
|
||||
try {
|
||||
val zipEntries = zipFile.entries()
|
||||
while (zipEntries.hasMoreElements()) {
|
||||
val entry = zipEntries.nextElement()
|
||||
val entryName = entry.name
|
||||
if (!entry.isDirectory && entryName.endsWith(KotlinJavascriptMetadataUtils.JS_EXT)) {
|
||||
val relativePath = getSuggestedPath(entryName)
|
||||
if (relativePath == null) continue
|
||||
|
||||
val stream = zipFile.getInputStream(entry)
|
||||
val content = FileUtil.loadTextAndClose(stream)
|
||||
action(content, relativePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (ex: IOException) {
|
||||
LOG.error("Could not extract files from archive ${file.name}: ${ex.message}")
|
||||
}
|
||||
finally {
|
||||
zipFile.close()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSuggestedPath(path: String): String? {
|
||||
val systemIndependentPath = FileUtil.toSystemIndependentName(path)
|
||||
if (systemIndependentPath.startsWith(METAINF)) {
|
||||
if (systemIndependentPath.startsWith(METAINF_RESOURCES)) {
|
||||
return path.substring(METAINF_RESOURCES.length)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
private fun getManifestFromJar(library: File): Manifest? {
|
||||
if (!library.canRead()) return null
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@ import org.jetbrains.kotlin.modules.TargetId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.progress.CompilationCanceledException
|
||||
import org.jetbrains.kotlin.progress.CompilationCanceledStatus
|
||||
import org.jetbrains.kotlin.utils.LibraryUtils
|
||||
import org.jetbrains.kotlin.utils.JsLibraryUtils
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import org.jetbrains.kotlin.utils.keysToMap
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
@@ -592,7 +592,7 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) {
|
||||
val outputLibraryRuntimeDirectory = File(outputDir, compilerSettings.outputDirectoryForJsLibraryFiles).absolutePath
|
||||
val libraryFilesToCopy = arrayListOf<String>()
|
||||
JpsJsModuleUtils.getLibraryFiles(representativeTarget, libraryFilesToCopy)
|
||||
LibraryUtils.copyJsFilesFromLibraries(libraryFilesToCopy, outputLibraryRuntimeDirectory)
|
||||
JsLibraryUtils.copyJsFilesFromLibraries(libraryFilesToCopy, outputLibraryRuntimeDirectory)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.js.inline
|
||||
import com.google.dart.compiler.backend.js.ast.*
|
||||
import com.google.dart.compiler.backend.js.ast.metadata.inlineStrategy
|
||||
import com.google.gwt.dev.js.ThrowExceptionOnErrorReporter
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.util.containers.SLRUCache
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
@@ -33,8 +32,7 @@ import org.jetbrains.kotlin.js.translate.reference.CallExpressionTranslator
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsDescriptorUtils.getExternalModuleName
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineStrategy
|
||||
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils
|
||||
import org.jetbrains.kotlin.utils.LibraryUtils
|
||||
import org.jetbrains.kotlin.utils.JsLibraryUtils
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
import java.io.File
|
||||
|
||||
@@ -68,7 +66,7 @@ class FunctionReader(private val context: TranslationContext) {
|
||||
val config = context.config as LibrarySourcesConfig
|
||||
val libs = config.libraries.map { File(it) }
|
||||
|
||||
LibraryUtils.traverseJsLibraries(libs) { fileContent, path ->
|
||||
JsLibraryUtils.traverseJsLibraries(libs) { fileContent, path ->
|
||||
val matcher = DEFINE_MODULE_PATTERN.toPattern().matcher(fileContent)
|
||||
|
||||
while (matcher.find()) {
|
||||
|
||||
Reference in New Issue
Block a user