From 3363c95c234b570e70ba605ce8b86f7e3f9969b1 Mon Sep 17 00:00:00 2001 From: Ilya Gorbunov Date: Fri, 27 Dec 2019 20:52:27 +0300 Subject: [PATCH] Do not use zipTree in CollisionDetector task This avoids unpacking all the dependency jars and significantly speeds up the task. --- .../org/jetbrains/kotlin/CollisionDetector.kt | 74 +++++++++---------- build.gradle | 1 - 2 files changed, 33 insertions(+), 42 deletions(-) diff --git a/build-tools/src/main/kotlin/org/jetbrains/kotlin/CollisionDetector.kt b/build-tools/src/main/kotlin/org/jetbrains/kotlin/CollisionDetector.kt index 1687def49b8..07af788a0b1 100644 --- a/build-tools/src/main/kotlin/org/jetbrains/kotlin/CollisionDetector.kt +++ b/build-tools/src/main/kotlin/org/jetbrains/kotlin/CollisionDetector.kt @@ -11,24 +11,12 @@ import org.gradle.api.artifacts.Configuration import org.gradle.api.tasks.Input import org.gradle.api.tasks.InputFiles import java.io.File - -fun Map.firstOrNull(predicate:(K, V) -> Boolean): V? { - var foundValue: V? = null - forEach { - if (predicate(it.key, it.value)) { - foundValue = it.value - return@forEach - } - } - return foundValue -} - +import java.util.zip.ZipFile /** * Task to find out collisions before producing fat jar. * * @property configurations added to fat jar configurations - * @property ignoredFiles excluded from analysis files * @property resolvingRules a map containing rules to resolve conflicts. Key - conflicting file, value - a jar to copy the file from * @property resolvingRulesWithRegexes a map containing rules to resolve conflicts. Key - regular expression describing conflicting file, value - a jar to copy the file from * @property librariesWithIgnoredClassCollisions libraries which collision in class files are ignored @@ -37,8 +25,6 @@ open class CollisionDetector : DefaultTask() { @InputFiles var configurations = listOf() @Input - val ignoredFiles = mutableListOf() - @Input val resolvingRules = mutableMapOf() @Input val resolvingRulesWithRegexes = mutableMapOf() @@ -53,37 +39,43 @@ open class CollisionDetector : DefaultTask() { fun run() { configurations.forEach { configuration -> configuration.files.filter { it.name.endsWith(".jar") }.forEach { processedFile -> - project.zipTree(processedFile.absolutePath).matching { it.exclude(ignoredFiles) }.forEach { - val outputPath = it.absolutePath.substringAfter(processedFile.name).substringAfter("/") - if (outputPath in filesInfo.keys) { - val rule = resolvingRules.getOrElse(outputPath) { - resolvingRulesWithRegexes.firstOrNull { key, _ -> key.matches(outputPath) } - } - var ignoreJar = false - if (rule != null && processedFile.name.startsWith(rule)) { - resolvedConflicts[outputPath] = processedFile - } else { - // Skip class files from ignored libraries if version of libraries had collision are the same. - val versionRegex = "\\d+\\.\\d+(\\.\\d+)?(-\\w+(-\\d+)?)?".toRegex() - val currentVersion = versionRegex.find(processedFile.name)?.groupValues?.get(0) - val collisionLibVersion = versionRegex.find(filesInfo.getValue(outputPath))?.groupValues?.get(0) - if (outputPath.endsWith(".class") && currentVersion == collisionLibVersion) { - if (processedFile.name == filesInfo[outputPath]) { - ignoreJar = true - } else { - librariesWithIgnoredClassCollisions.forEach { - if (processedFile.name.startsWith(it)) { - ignoreJar = true + ZipFile(processedFile).use { zip -> + zip.entries().asSequence().filterNot { + it.isDirectory || + it.name.equals("META-INF/MANIFEST.MF", ignoreCase = true) || + it.name.startsWith("META-INF/services/", ignoreCase = true) + }.forEach { + val outputPath = it.name + if (outputPath in filesInfo.keys) { + val rule = resolvingRules.getOrElse(outputPath) { + resolvingRulesWithRegexes.entries.firstOrNull { (key, _) -> key.matches(outputPath) }?.value + } + var ignoreJar = false + if (rule != null && processedFile.name.startsWith(rule)) { + resolvedConflicts[outputPath] = processedFile + } else { + // Skip class files from ignored libraries if version of libraries had collision are the same. + val versionRegex = "\\d+\\.\\d+(\\.\\d+)?(-\\w+(-\\d+)?)?".toRegex() + val currentVersion = versionRegex.find(processedFile.name)?.groupValues?.get(0) + val collisionLibVersion = versionRegex.find(filesInfo.getValue(outputPath))?.groupValues?.get(0) + if (outputPath.endsWith(".class") && currentVersion == collisionLibVersion) { + if (processedFile.name == filesInfo[outputPath]) { + ignoreJar = true + } else { + librariesWithIgnoredClassCollisions.forEach { + if (processedFile.name.startsWith(it)) { + ignoreJar = true + } } } } } + if (rule == null && !ignoreJar) { + error("Collision is detected. File $outputPath is found in ${filesInfo[outputPath]} and ${processedFile.name}") + } + } else { + filesInfo[outputPath] = processedFile.name } - if (rule == null && !ignoreJar) { - error("Collision is detected. File $outputPath is found in ${filesInfo[outputPath]} and ${processedFile.name}") - } - } else { - filesInfo[outputPath] = processedFile.name } } } diff --git a/build.gradle b/build.gradle index d70f2d9a0dd..3ea6581d877 100644 --- a/build.gradle +++ b/build.gradle @@ -263,7 +263,6 @@ task distSources { } task detectJarCollision(type: CollisionDetector) { - ignoredFiles.addAll(["META-INF/MANIFEST.MF", "META-INF/services/**"]) configurations = [project.configurations.distPack] resolvingRules["META-INF/kotlin-util-klib.kotlin_module"] = "kotlin-compiler" resolvingRules["META-INF/kotlin-util-io.kotlin_module"] = "kotlin-compiler"