diff --git a/compiler/util/src/org/jetbrains/kotlin/utils/JsLibraryUtils.kt b/compiler/util/src/org/jetbrains/kotlin/utils/JsLibraryUtils.kt new file mode 100644 index 00000000000..57e8921060f --- /dev/null +++ b/compiler/util/src/org/jetbrains/kotlin/utils/JsLibraryUtils.kt @@ -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, 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, 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 -> + 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 + } +} diff --git a/compiler/util/src/org/jetbrains/kotlin/utils/KotlinJavascriptMetadataUtils.kt b/compiler/util/src/org/jetbrains/kotlin/utils/KotlinJavascriptMetadataUtils.kt index ef67da57227..49490a638fb 100644 --- a/compiler/util/src/org/jetbrains/kotlin/utils/KotlinJavascriptMetadataUtils.kt +++ b/compiler/util/src/org/jetbrains/kotlin/utils/KotlinJavascriptMetadataUtils.kt @@ -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 .kotlin_module_metadata(, , ) */ @@ -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 { - assert(file.exists()) { "Library " + file + " not found" } + assert(file.exists()) { "Library $file not found" } val metadataList = arrayListOf() - LibraryUtils.traverseJsLibrary(file) { content, relativePath -> - var path = file.path - - if (relativePath.isNotBlank()) { - path += "/$relativePath" - } - + JsLibraryUtils.traverseJsLibrary(file) { content, relativePath -> parseMetadata(content, metadataList) } diff --git a/compiler/util/src/org/jetbrains/kotlin/utils/LibraryUtils.kt b/compiler/util/src/org/jetbrains/kotlin/utils/LibraryUtils.kt index 94fa908173d..22c63e3e6a3 100644 --- a/compiler/util/src/org/jetbrains/kotlin/utils/LibraryUtils.kt +++ b/compiler/util/src/org/jetbrains/kotlin/utils/LibraryUtils.kt @@ -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, 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, 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 { - 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 diff --git a/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt b/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt index 71ca6e225b9..1fefd3dacc2 100644 --- a/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt +++ b/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt @@ -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() JpsJsModuleUtils.getLibraryFiles(representativeTarget, libraryFilesToCopy) - LibraryUtils.copyJsFilesFromLibraries(libraryFilesToCopy, outputLibraryRuntimeDirectory) + JsLibraryUtils.copyJsFilesFromLibraries(libraryFilesToCopy, outputLibraryRuntimeDirectory) } } diff --git a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionReader.kt b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionReader.kt index 086e031fe71..c8b77550a4d 100644 --- a/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionReader.kt +++ b/js/js.inliner/src/org/jetbrains/kotlin/js/inline/FunctionReader.kt @@ -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()) {