[Gradle, JS] Fix case with multiple artifacts in module

This commit is contained in:
Ilya Goncharov
2022-01-18 13:41:18 +03:00
committed by Space
parent bea2bc3980
commit 443c0bf74f
3 changed files with 101 additions and 21 deletions
@@ -0,0 +1 @@
kotlin.incremental.js.ir=false
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.gradle.targets.js.ir package org.jetbrains.kotlin.gradle.targets.js.ir
import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ResolvedArtifact
import org.gradle.api.artifacts.ResolvedDependency import org.gradle.api.artifacts.ResolvedDependency
import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.DirectoryProperty
@@ -42,6 +43,9 @@ import org.jetbrains.kotlin.gradle.utils.getAllDependencies
import org.jetbrains.kotlin.gradle.utils.getCacheDirectory import org.jetbrains.kotlin.gradle.utils.getCacheDirectory
import org.jetbrains.kotlin.gradle.utils.getDependenciesCacheDirectories import org.jetbrains.kotlin.gradle.utils.getDependenciesCacheDirectories
import org.jetbrains.kotlin.gradle.utils.getValue import org.jetbrains.kotlin.gradle.utils.getValue
import org.jetbrains.kotlin.library.resolveSingleFileKlib
import org.jetbrains.kotlin.library.uniqueName
import org.jetbrains.kotlin.library.unresolvedDependencies
import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics
import org.jetbrains.kotlin.statistics.metrics.StringMetrics import org.jetbrains.kotlin.statistics.metrics.StringMetrics
import java.io.File import java.io.File
@@ -260,10 +264,12 @@ internal class CacheBuilder(
.filter { it !in visitedDependenciesForCache } .filter { it !in visitedDependenciesForCache }
.forEach { dependencyForCache -> .forEach { dependencyForCache ->
visitedDependenciesForCache.add(dependencyForCache) visitedDependenciesForCache.add(dependencyForCache)
val cacheDirectory = getCacheDirectory(rootCacheDirectory, dependencyForCache) dependencyForCache.moduleArtifacts
if (cacheDirectory.exists()) { .map {
allCacheDirectories.add(cacheDirectory) getCacheDirectory(rootCacheDirectory, dependencyForCache, it, { libraryFilter(it.file) })
} }
.filter { it.exists() }
.forEach { allCacheDirectories.add(it) }
} }
} }
} }
@@ -301,20 +307,65 @@ internal class CacheBuilder(
val dependenciesCacheDirectories = getDependenciesCacheDirectories( val dependenciesCacheDirectories = getDependenciesCacheDirectories(
rootCacheDirectory, rootCacheDirectory,
dependency dependency,
libraryFilter = { libraryFilter(it.file) }
) ?: return ) ?: return
val cacheDirectory = getCacheDirectory(rootCacheDirectory, dependency) val nameMap: MutableMap<String, ResolvedArtifact> = mutableMapOf()
cacheDirectory.mkdirs() val depsMap: MutableMap<ResolvedArtifact, MutableList<ResolvedArtifact>> = mutableMapOf()
val cacheMap: MutableMap<ResolvedArtifact, File> = mutableMapOf()
var newOrderArtifactsToAddToCache = mutableListOf<ResolvedArtifact>()
for (library in artifactsToAddToCache) { if (artifactsToAddToCache.size > 1) {
artifactsToAddToCache.forEach {
val klib = resolveSingleFileKlib(org.jetbrains.kotlin.konan.file.File(it.file.absolutePath))
nameMap[klib.uniqueName] = it
}
artifactsToAddToCache.forEach { artifact ->
val klib = resolveSingleFileKlib(org.jetbrains.kotlin.konan.file.File(artifact.file.absolutePath))
klib.unresolvedDependencies
.forEach { depLib ->
val depName = depLib.path.substringAfterLast("/")
nameMap[depName]?.let {
val depsSet = depsMap.getOrPut(artifact) {
mutableListOf()
}
depsSet.add(it)
}
}
}
fun traverseDependency(library: ResolvedArtifact) {
depsMap[library]?.let {
it.forEach {
traverseDependency(it)
}
}
if (library !in newOrderArtifactsToAddToCache) {
newOrderArtifactsToAddToCache.add(library)
}
}
depsMap.forEach { key, deps ->
traverseDependency(key)
}
} else {
newOrderArtifactsToAddToCache = artifactsToAddToCache.toMutableList()
}
for (library in newOrderArtifactsToAddToCache) {
val cacheDirectory = getCacheDirectory(rootCacheDirectory, dependency, library, { libraryFilter(it.file) })
cacheDirectory.mkdirs()
cacheMap[library] = cacheDirectory
val additionalDependencies = depsMap[library] ?: emptyList()
val additionalCacheDirectories = if (additionalDependencies.isNotEmpty()) {
additionalDependencies.map { cacheMap.getValue(it) }
} else emptyList()
runCompiler( runCompiler(
library.file, library.file,
getAllDependencies(dependency) (getAllDependencies(dependency)
.flatMap { it.moduleArtifacts } .flatMap { it.moduleArtifacts } + additionalDependencies)
.map { it.file }, .map { it.file },
cacheDirectory, cacheDirectory,
dependenciesCacheDirectories dependenciesCacheDirectories + additionalCacheDirectories
) )
} }
} }
@@ -5,19 +5,42 @@
package org.jetbrains.kotlin.gradle.utils package org.jetbrains.kotlin.gradle.utils
import org.gradle.api.artifacts.ResolvedArtifact
import org.gradle.api.artifacts.ResolvedDependency import org.gradle.api.artifacts.ResolvedDependency
import org.gradle.api.logging.Logger import org.gradle.api.logging.Logger
import org.jetbrains.kotlin.library.resolveSingleFileKlib
import org.jetbrains.kotlin.library.uniqueName
import java.io.File import java.io.File
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
import java.security.MessageDigest import java.security.MessageDigest
fun getCacheDirectory( fun getCacheDirectory(
rootCacheDirectory: File, rootCacheDirectory: File,
dependency: ResolvedDependency dependency: ResolvedDependency,
artifact: ResolvedArtifact? = null,
libraryFilter: (ResolvedArtifact) -> Boolean = { it.file.absolutePath.endsWith(".klib") }
): File { ): File {
val moduleCacheDirectory = File(rootCacheDirectory, dependency.moduleName) val moduleCacheDirectory = File(rootCacheDirectory, dependency.moduleName)
val versionCacheDirectory = File(moduleCacheDirectory, dependency.moduleVersion) val versionCacheDirectory = File(moduleCacheDirectory, dependency.moduleVersion)
return File(versionCacheDirectory, computeDependenciesHash(dependency)) val uniqueName = artifact
?.let {
if (libraryFilter(it))
it.file
else
null
}
?.let {
resolveSingleFileKlib(org.jetbrains.kotlin.konan.file.File(it.absolutePath))
}
?.uniqueName
val cacheDirectory = if (uniqueName != null) {
val digest = MessageDigest.getInstance("SHA-256")
val hash = digest.digest(uniqueName.toByteArray(StandardCharsets.UTF_8)).toHexString()
versionCacheDirectory.resolve(hash)
} else versionCacheDirectory
return File(cacheDirectory, computeDependenciesHash(dependency))
} }
private fun ByteArray.toHexString() = joinToString("") { (0xFF and it.toInt()).toString(16).padStart(2, '0') } private fun ByteArray.toHexString() = joinToString("") { (0xFF and it.toInt()).toString(16).padStart(2, '0') }
@@ -36,17 +59,22 @@ private fun computeDependenciesHash(dependency: ResolvedDependency): String {
fun getDependenciesCacheDirectories( fun getDependenciesCacheDirectories(
rootCacheDirectory: File, rootCacheDirectory: File,
dependency: ResolvedDependency dependency: ResolvedDependency,
libraryFilter: (ResolvedArtifact) -> Boolean = { it.file.absolutePath.endsWith(".klib") }
): List<File>? { ): List<File>? {
return getAllDependencies(dependency) return getAllDependencies(dependency)
.map { childDependency -> .flatMap { childDependency ->
val hasKlibs = childDependency.moduleArtifacts.any { it.file.absolutePath.endsWith(".klib") } childDependency.moduleArtifacts.map {
val cacheDirectory = getCacheDirectory(rootCacheDirectory, childDependency) if (libraryFilter(it)) {
// We can only compile klib to cache if all of its dependencies are also cached. val cacheDirectory = getCacheDirectory(rootCacheDirectory, childDependency, it, libraryFilter)
if (hasKlibs && !cacheDirectory.exists()) if (!cacheDirectory.exists()) return null
return null cacheDirectory
cacheDirectory } else {
null
}
}
} }
.filterNotNull()
.filter { it.exists() } .filter { it.exists() }
} }