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:
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user