[Gradle] Replace usage of ResolvedConfiguration to ResolvedDependencyResult

ResolvedConfiguration is a legacy API that doesn't work with
Gradle Configuration Cache.
ResolvedDependencyResult is cacheable but lightweight.
This commit is contained in:
Anton Lakotka
2022-06-14 12:49:54 +02:00
committed by Space
parent ebe7544464
commit becdb84bbb
3 changed files with 70 additions and 48 deletions
@@ -637,7 +637,7 @@ constructor(
@get:Internal
internal abstract val konanPropertiesService: Property<KonanPropertiesBuildService>
private val compileDependencyFiles = FilesWithResolvedDependencyGraph(
private val resolvedDependencyGraph = ResolvedDependencyGraph(
project,
project.configurations.getByName(compilation.compileDependencyConfigurationName)
)
@@ -659,7 +659,7 @@ constructor(
executionContext = executionContext,
settings = cacheBuilderSettings,
konanPropertiesService = konanPropertiesService.get()
).buildCompilerArgs(compileDependencyFiles)
).buildCompilerArgs(resolvedDependencyGraph)
val buildArgs = buildKotlinNativeBinaryLinkerArgs(
output,
@@ -939,33 +939,47 @@ internal class CacheBuilder(
private val partialLinkage: Boolean
get() = PARTIAL_LINKAGE in settings.kotlinOptions.freeCompilerArgs
private fun getCacheDirectory(dependency: ResolvedDependency): File = getCacheDirectory(
private fun getCacheDirectory(
resolvedDependencyGraph: ResolvedDependencyGraph,
dependency: ResolvedDependencyResult
): File = getCacheDirectory(
rootCacheDirectory = rootCacheDirectory,
dependency = dependency,
artifact = null,
resolvedDependencyGraph = resolvedDependencyGraph,
partialLinkage = partialLinkage
)
private fun needCache(libraryPath: String) =
libraryPath.startsWith(settings.gradleUserHomeDir.absolutePath) && libraryPath.endsWith(".klib")
private fun ensureDependencyPrecached(dependency: ResolvedDependency, visitedDependencies: MutableSet<ResolvedDependency>) {
private fun ResolvedDependencyGraph.ensureDependencyPrecached(
dependency: ResolvedDependencyResult,
visitedDependencies: MutableSet<ResolvedDependencyResult>
) {
if (dependency in visitedDependencies)
return
visitedDependencies += dependency
dependency.children.forEach { ensureDependencyPrecached(it, visitedDependencies) }
val artifactsToAddToCache = dependency.moduleArtifacts.filter { needCache(it.file.absolutePath) }
visitedDependencies += dependency
dependency
.selected
.dependencies
.filterIsInstance<ResolvedDependencyResult>()
.forEach { ensureDependencyPrecached(it, visitedDependencies) }
val artifactsToAddToCache = dependencyArtifacts(dependency).filter { needCache(it.file.absolutePath) }
if (artifactsToAddToCache.isEmpty()) return
val dependenciesCacheDirectories = getDependenciesCacheDirectories(
rootCacheDirectory = rootCacheDirectory,
dependency = dependency,
considerArtifact = false,
resolvedDependencyGraph = this,
partialLinkage = partialLinkage
) ?: return
val cacheDirectory = getCacheDirectory(dependency)
val cacheDirectory = getCacheDirectory(this, dependency)
cacheDirectory.mkdirs()
val artifactsLibraries = artifactsToAddToCache
@@ -1017,7 +1031,7 @@ internal class CacheBuilder(
args += "-Xcache-directory=${it.absolutePath}"
}
getAllDependencies(dependency)
.flatMap { it.moduleArtifacts }
.flatMap { dependencyArtifacts(it) }
.map { it.file }
.filterKlibsPassedToCompiler()
.forEach {
@@ -1085,17 +1099,17 @@ internal class CacheBuilder(
ensureCompilerProvidedLibPrecached(platformLibName, platformLibs, visitedLibs)
}
fun buildCompilerArgs(compileDependencyFiles: FilesWithResolvedDependencyGraph): List<String> = mutableListOf<String>().apply {
fun buildCompilerArgs(resolvedDependencyGraph: ResolvedDependencyGraph): List<String> = mutableListOf<String>().apply {
if (konanCacheKind != NativeCacheKind.NONE && !optimized && konanPropertiesService.cacheWorksFor(konanTarget)) {
rootCacheDirectory.mkdirs()
ensureCompilerProvidedLibsPrecached()
add("-Xcache-directory=${rootCacheDirectory.absolutePath}")
val visitedDependencies = mutableSetOf<ResolvedDependency>()
val visitedDependencies = mutableSetOf<ResolvedDependencyResult>()
val allCacheDirectories = mutableSetOf<String>()
for (root in compileDependencyFiles.graphRoot.firstLevelModuleDependencies) {
ensureDependencyPrecached(root, visitedDependencies)
for (root in resolvedDependencyGraph.root.dependencies.filterIsInstance<ResolvedDependencyResult>()) {
resolvedDependencyGraph.ensureDependencyPrecached(root, visitedDependencies)
for (dependency in listOf(root) + getAllDependencies(root)) {
val cacheDirectory = getCacheDirectory(dependency)
val cacheDirectory = getCacheDirectory(resolvedDependencyGraph, dependency)
if (cacheDirectory.exists())
allCacheDirectories += cacheDirectory.absolutePath
}
@@ -5,8 +5,8 @@
package org.jetbrains.kotlin.gradle.utils
import org.gradle.api.artifacts.ResolvedArtifact
import org.gradle.api.artifacts.ResolvedDependency
import org.gradle.api.artifacts.result.ResolvedArtifactResult
import org.gradle.api.artifacts.result.ResolvedDependencyResult
import org.gradle.api.logging.Logger
import org.jetbrains.kotlin.library.resolveSingleFileKlib
import org.jetbrains.kotlin.library.uniqueName
@@ -14,14 +14,15 @@ import java.io.File
import java.nio.charset.StandardCharsets
import java.security.MessageDigest
fun getCacheDirectory(
internal fun getCacheDirectory(
rootCacheDirectory: File,
dependency: ResolvedDependency,
artifact: ResolvedArtifact?,
dependency: ResolvedDependencyResult,
artifact: ResolvedArtifactResult?,
resolvedDependencyGraph: ResolvedDependencyGraph,
partialLinkage: Boolean
): File {
val moduleCacheDirectory = File(rootCacheDirectory, dependency.moduleName)
val versionCacheDirectory = File(moduleCacheDirectory, dependency.moduleVersion)
val moduleCacheDirectory = File(rootCacheDirectory, dependency.selected.moduleVersion?.name ?: "undefined")
val versionCacheDirectory = File(moduleCacheDirectory, dependency.selected.moduleVersion?.version ?: "undefined")
val uniqueName = artifact
?.let {
if (libraryFilter(it))
@@ -40,16 +41,17 @@ fun getCacheDirectory(
versionCacheDirectory.resolve(hash)
} else versionCacheDirectory
return File(cacheDirectory, computeDependenciesHash(dependency, partialLinkage))
return File(cacheDirectory, computeDependenciesHash(dependency, resolvedDependencyGraph, partialLinkage))
}
internal fun ByteArray.toHexString() = joinToString("") { (0xFF and it.toInt()).toString(16).padStart(2, '0') }
private fun computeDependenciesHash(dependency: ResolvedDependency, partialLinkage: Boolean): String {
private fun computeDependenciesHash(dependency: ResolvedDependencyResult, resolvedDependencyGraph: ResolvedDependencyGraph, partialLinkage: Boolean): String {
val hashedValue = buildString {
if (partialLinkage) append("#__PL__#")
(dependency.moduleArtifacts + getAllDependencies(dependency).flatMap { it.moduleArtifacts })
(listOf(dependency) + getAllDependencies(dependency))
.flatMap { resolvedDependencyGraph.dependencyArtifacts(it) }
.map { it.file.absolutePath }
.distinct()
.sortedBy { it }
@@ -61,20 +63,22 @@ private fun computeDependenciesHash(dependency: ResolvedDependency, partialLinka
return hash.toHexString()
}
fun getDependenciesCacheDirectories(
internal fun getDependenciesCacheDirectories(
rootCacheDirectory: File,
dependency: ResolvedDependency,
dependency: ResolvedDependencyResult,
resolvedDependencyGraph: ResolvedDependencyGraph,
considerArtifact: Boolean,
partialLinkage: Boolean
): List<File>? {
return getAllDependencies(dependency)
.flatMap { childDependency ->
childDependency.moduleArtifacts.map {
resolvedDependencyGraph.dependencyArtifacts(childDependency).map {
if (libraryFilter(it)) {
val cacheDirectory = getCacheDirectory(
rootCacheDirectory = rootCacheDirectory,
dependency = childDependency,
artifact = if (considerArtifact) it else null,
resolvedDependencyGraph = resolvedDependencyGraph,
partialLinkage = partialLinkage
)
if (!cacheDirectory.exists()) return null
@@ -88,17 +92,17 @@ fun getDependenciesCacheDirectories(
.filter { it.exists() }
}
fun getAllDependencies(dependency: ResolvedDependency): Set<ResolvedDependency> {
val allDependencies = mutableSetOf<ResolvedDependency>()
internal fun getAllDependencies(dependency: ResolvedDependencyResult): Set<ResolvedDependencyResult> {
val allDependencies = mutableSetOf<ResolvedDependencyResult>()
fun traverseAllDependencies(dependency: ResolvedDependency) {
fun traverseAllDependencies(dependency: ResolvedDependencyResult) {
if (dependency in allDependencies)
return
allDependencies.add(dependency)
dependency.children.forEach { traverseAllDependencies(it) }
dependency.selected.dependencies.filterIsInstance<ResolvedDependencyResult>().forEach { traverseAllDependencies(it) }
}
dependency.children.forEach { traverseAllDependencies(it) }
dependency.selected.dependencies.filterIsInstance<ResolvedDependencyResult>().forEach { traverseAllDependencies(it) }
return allDependencies
}
@@ -109,4 +113,4 @@ internal class GradleLoggerAdapter(private val gradleLogger: Logger) : org.jetbr
override fun fatal(message: String): Nothing = kotlin.error(message)
}
private fun libraryFilter(artifact: ResolvedArtifact): Boolean = artifact.file.absolutePath.endsWith(".klib")
private fun libraryFilter(artifact: ResolvedArtifactResult): Boolean = artifact.file.absolutePath.endsWith(".klib")
@@ -7,9 +7,9 @@ package org.jetbrains.kotlin.gradle.utils
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ResolvedConfiguration
import org.gradle.api.artifacts.ResolvedDependency
import org.gradle.api.artifacts.result.ResolvedArtifactResult
import org.gradle.api.artifacts.result.ResolvedComponentResult
import org.gradle.api.artifacts.result.ResolvedDependencyResult
import org.gradle.api.file.FileCollection
import org.gradle.api.provider.Provider
@@ -22,25 +22,29 @@ const val RUNTIME = "runtime"
internal const val INTRANSITIVE = "intransitive"
/**
* Gradle Configuration Cache-friendly holder of resolved Configuration
* Gradle Configuration Cache-friendly representation of resolved Configuration
*/
class FilesWithResolvedDependencyGraph
internal class ResolvedDependencyGraph
private constructor (
val files: FileCollection,
val graphRootProvider: Provider<ResolvedComponentResult>
private val graphRootProvider: Provider<ResolvedComponentResult>,
private val artifactsProvider: Provider<Set<ResolvedArtifactResult>>
) {
val graphRoot get() = graphRootProvider.get()
val root get() = graphRootProvider.get()
val artifacts get() = artifactsProvider.get()
val artifactsByComponentId by lazy { artifacts.groupBy { it.id.componentIdentifier } }
fun dependencyArtifacts(dependency: ResolvedDependencyResult): List<ResolvedArtifactResult> {
val componentId = dependency.selected.id
return artifactsByComponentId[componentId] ?: emptyList()
}
companion object {
operator fun invoke(project: Project, configuration: Configuration) = FilesWithResolvedDependencyGraph(
operator fun invoke(project: Project, configuration: Configuration) = ResolvedDependencyGraph(
files = project.files(configuration),
graphRootProvider = configuration.incoming.resolutionResult.let { rr -> project.provider { rr.root } }
graphRootProvider = configuration.incoming.resolutionResult.let { rr -> project.provider { rr.root } },
artifactsProvider = configuration.incoming.artifacts.let { collection -> project.provider { collection.artifacts } }
)
}
}
/**
* Configuration Cache-friendly alternative of [ResolvedConfiguration.getFirstLevelModuleDependencies]
*/
internal val ResolvedComponentResult.firstLevelModuleDependencies: Set<ResolvedDependency> get() =
dependencies.filterIsInstance<ResolvedDependency>().toSet()
}