[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 @get:Internal
internal abstract val konanPropertiesService: Property<KonanPropertiesBuildService> internal abstract val konanPropertiesService: Property<KonanPropertiesBuildService>
private val compileDependencyFiles = FilesWithResolvedDependencyGraph( private val resolvedDependencyGraph = ResolvedDependencyGraph(
project, project,
project.configurations.getByName(compilation.compileDependencyConfigurationName) project.configurations.getByName(compilation.compileDependencyConfigurationName)
) )
@@ -659,7 +659,7 @@ constructor(
executionContext = executionContext, executionContext = executionContext,
settings = cacheBuilderSettings, settings = cacheBuilderSettings,
konanPropertiesService = konanPropertiesService.get() konanPropertiesService = konanPropertiesService.get()
).buildCompilerArgs(compileDependencyFiles) ).buildCompilerArgs(resolvedDependencyGraph)
val buildArgs = buildKotlinNativeBinaryLinkerArgs( val buildArgs = buildKotlinNativeBinaryLinkerArgs(
output, output,
@@ -939,33 +939,47 @@ internal class CacheBuilder(
private val partialLinkage: Boolean private val partialLinkage: Boolean
get() = PARTIAL_LINKAGE in settings.kotlinOptions.freeCompilerArgs 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, rootCacheDirectory = rootCacheDirectory,
dependency = dependency, dependency = dependency,
artifact = null, artifact = null,
resolvedDependencyGraph = resolvedDependencyGraph,
partialLinkage = partialLinkage partialLinkage = partialLinkage
) )
private fun needCache(libraryPath: String) = private fun needCache(libraryPath: String) =
libraryPath.startsWith(settings.gradleUserHomeDir.absolutePath) && libraryPath.endsWith(".klib") 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) if (dependency in visitedDependencies)
return 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 if (artifactsToAddToCache.isEmpty()) return
val dependenciesCacheDirectories = getDependenciesCacheDirectories( val dependenciesCacheDirectories = getDependenciesCacheDirectories(
rootCacheDirectory = rootCacheDirectory, rootCacheDirectory = rootCacheDirectory,
dependency = dependency, dependency = dependency,
considerArtifact = false, considerArtifact = false,
resolvedDependencyGraph = this,
partialLinkage = partialLinkage partialLinkage = partialLinkage
) ?: return ) ?: return
val cacheDirectory = getCacheDirectory(dependency) val cacheDirectory = getCacheDirectory(this, dependency)
cacheDirectory.mkdirs() cacheDirectory.mkdirs()
val artifactsLibraries = artifactsToAddToCache val artifactsLibraries = artifactsToAddToCache
@@ -1017,7 +1031,7 @@ internal class CacheBuilder(
args += "-Xcache-directory=${it.absolutePath}" args += "-Xcache-directory=${it.absolutePath}"
} }
getAllDependencies(dependency) getAllDependencies(dependency)
.flatMap { it.moduleArtifacts } .flatMap { dependencyArtifacts(it) }
.map { it.file } .map { it.file }
.filterKlibsPassedToCompiler() .filterKlibsPassedToCompiler()
.forEach { .forEach {
@@ -1085,17 +1099,17 @@ internal class CacheBuilder(
ensureCompilerProvidedLibPrecached(platformLibName, platformLibs, visitedLibs) 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)) { if (konanCacheKind != NativeCacheKind.NONE && !optimized && konanPropertiesService.cacheWorksFor(konanTarget)) {
rootCacheDirectory.mkdirs() rootCacheDirectory.mkdirs()
ensureCompilerProvidedLibsPrecached() ensureCompilerProvidedLibsPrecached()
add("-Xcache-directory=${rootCacheDirectory.absolutePath}") add("-Xcache-directory=${rootCacheDirectory.absolutePath}")
val visitedDependencies = mutableSetOf<ResolvedDependency>() val visitedDependencies = mutableSetOf<ResolvedDependencyResult>()
val allCacheDirectories = mutableSetOf<String>() val allCacheDirectories = mutableSetOf<String>()
for (root in compileDependencyFiles.graphRoot.firstLevelModuleDependencies) { for (root in resolvedDependencyGraph.root.dependencies.filterIsInstance<ResolvedDependencyResult>()) {
ensureDependencyPrecached(root, visitedDependencies) resolvedDependencyGraph.ensureDependencyPrecached(root, visitedDependencies)
for (dependency in listOf(root) + getAllDependencies(root)) { for (dependency in listOf(root) + getAllDependencies(root)) {
val cacheDirectory = getCacheDirectory(dependency) val cacheDirectory = getCacheDirectory(resolvedDependencyGraph, dependency)
if (cacheDirectory.exists()) if (cacheDirectory.exists())
allCacheDirectories += cacheDirectory.absolutePath allCacheDirectories += cacheDirectory.absolutePath
} }
@@ -5,8 +5,8 @@
package org.jetbrains.kotlin.gradle.utils package org.jetbrains.kotlin.gradle.utils
import org.gradle.api.artifacts.ResolvedArtifact import org.gradle.api.artifacts.result.ResolvedArtifactResult
import org.gradle.api.artifacts.ResolvedDependency import org.gradle.api.artifacts.result.ResolvedDependencyResult
import org.gradle.api.logging.Logger import org.gradle.api.logging.Logger
import org.jetbrains.kotlin.library.resolveSingleFileKlib import org.jetbrains.kotlin.library.resolveSingleFileKlib
import org.jetbrains.kotlin.library.uniqueName import org.jetbrains.kotlin.library.uniqueName
@@ -14,14 +14,15 @@ import java.io.File
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
import java.security.MessageDigest import java.security.MessageDigest
fun getCacheDirectory( internal fun getCacheDirectory(
rootCacheDirectory: File, rootCacheDirectory: File,
dependency: ResolvedDependency, dependency: ResolvedDependencyResult,
artifact: ResolvedArtifact?, artifact: ResolvedArtifactResult?,
resolvedDependencyGraph: ResolvedDependencyGraph,
partialLinkage: Boolean partialLinkage: Boolean
): File { ): File {
val moduleCacheDirectory = File(rootCacheDirectory, dependency.moduleName) val moduleCacheDirectory = File(rootCacheDirectory, dependency.selected.moduleVersion?.name ?: "undefined")
val versionCacheDirectory = File(moduleCacheDirectory, dependency.moduleVersion) val versionCacheDirectory = File(moduleCacheDirectory, dependency.selected.moduleVersion?.version ?: "undefined")
val uniqueName = artifact val uniqueName = artifact
?.let { ?.let {
if (libraryFilter(it)) if (libraryFilter(it))
@@ -40,16 +41,17 @@ fun getCacheDirectory(
versionCacheDirectory.resolve(hash) versionCacheDirectory.resolve(hash)
} else versionCacheDirectory } 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') } 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 { val hashedValue = buildString {
if (partialLinkage) append("#__PL__#") if (partialLinkage) append("#__PL__#")
(dependency.moduleArtifacts + getAllDependencies(dependency).flatMap { it.moduleArtifacts }) (listOf(dependency) + getAllDependencies(dependency))
.flatMap { resolvedDependencyGraph.dependencyArtifacts(it) }
.map { it.file.absolutePath } .map { it.file.absolutePath }
.distinct() .distinct()
.sortedBy { it } .sortedBy { it }
@@ -61,20 +63,22 @@ private fun computeDependenciesHash(dependency: ResolvedDependency, partialLinka
return hash.toHexString() return hash.toHexString()
} }
fun getDependenciesCacheDirectories( internal fun getDependenciesCacheDirectories(
rootCacheDirectory: File, rootCacheDirectory: File,
dependency: ResolvedDependency, dependency: ResolvedDependencyResult,
resolvedDependencyGraph: ResolvedDependencyGraph,
considerArtifact: Boolean, considerArtifact: Boolean,
partialLinkage: Boolean partialLinkage: Boolean
): List<File>? { ): List<File>? {
return getAllDependencies(dependency) return getAllDependencies(dependency)
.flatMap { childDependency -> .flatMap { childDependency ->
childDependency.moduleArtifacts.map { resolvedDependencyGraph.dependencyArtifacts(childDependency).map {
if (libraryFilter(it)) { if (libraryFilter(it)) {
val cacheDirectory = getCacheDirectory( val cacheDirectory = getCacheDirectory(
rootCacheDirectory = rootCacheDirectory, rootCacheDirectory = rootCacheDirectory,
dependency = childDependency, dependency = childDependency,
artifact = if (considerArtifact) it else null, artifact = if (considerArtifact) it else null,
resolvedDependencyGraph = resolvedDependencyGraph,
partialLinkage = partialLinkage partialLinkage = partialLinkage
) )
if (!cacheDirectory.exists()) return null if (!cacheDirectory.exists()) return null
@@ -88,17 +92,17 @@ fun getDependenciesCacheDirectories(
.filter { it.exists() } .filter { it.exists() }
} }
fun getAllDependencies(dependency: ResolvedDependency): Set<ResolvedDependency> { internal fun getAllDependencies(dependency: ResolvedDependencyResult): Set<ResolvedDependencyResult> {
val allDependencies = mutableSetOf<ResolvedDependency>() val allDependencies = mutableSetOf<ResolvedDependencyResult>()
fun traverseAllDependencies(dependency: ResolvedDependency) { fun traverseAllDependencies(dependency: ResolvedDependencyResult) {
if (dependency in allDependencies) if (dependency in allDependencies)
return return
allDependencies.add(dependency) 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 return allDependencies
} }
@@ -109,4 +113,4 @@ internal class GradleLoggerAdapter(private val gradleLogger: Logger) : org.jetbr
override fun fatal(message: String): Nothing = kotlin.error(message) 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.Project
import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ResolvedConfiguration import org.gradle.api.artifacts.result.ResolvedArtifactResult
import org.gradle.api.artifacts.ResolvedDependency
import org.gradle.api.artifacts.result.ResolvedComponentResult import org.gradle.api.artifacts.result.ResolvedComponentResult
import org.gradle.api.artifacts.result.ResolvedDependencyResult
import org.gradle.api.file.FileCollection import org.gradle.api.file.FileCollection
import org.gradle.api.provider.Provider import org.gradle.api.provider.Provider
@@ -22,25 +22,29 @@ const val RUNTIME = "runtime"
internal const val INTRANSITIVE = "intransitive" 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 ( private constructor (
val files: FileCollection, 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 { companion object {
operator fun invoke(project: Project, configuration: Configuration) = FilesWithResolvedDependencyGraph( operator fun invoke(project: Project, configuration: Configuration) = ResolvedDependencyGraph(
files = project.files(configuration), 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()