Do not use zipTree in CollisionDetector task

This avoids unpacking all the dependency jars and significantly speeds up the task.
This commit is contained in:
Ilya Gorbunov
2019-12-27 20:52:27 +03:00
committed by ilya-g
parent edd619ef70
commit 3363c95c23
2 changed files with 33 additions and 42 deletions
@@ -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 <K, V> Map<K, V>.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<Configuration>()
@Input
val ignoredFiles = mutableListOf<String>()
@Input
val resolvingRules = mutableMapOf<String, String>()
@Input
val resolvingRulesWithRegexes = mutableMapOf<Regex, String>()
@@ -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
}
}
}
-1
View File
@@ -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"