[Gradle] Decouple SourceSetVisibilityProvider from Gradle Project
And related ResolvedMppVariantsProvider. * Introduce PlatformCompilationData that is Configuration Cache friendly And contain all needed data to infer visible source sets * Add factory-methods that can collect PlatformCompilationData from project that has Multiplatform Extension. * hostSpecificMetadataConfiguration collection has parity with related ResolvedMppVariantsProvider.resolveArtifacts() part where attributes are changed to KOTLIN_METADATA. ResolvedMppVariantsProvider will be deprecated and removed shortly ^KT-49933
This commit is contained in:
committed by
Space Team
parent
504ee1fbb1
commit
6b2111c2a5
+12
-12
@@ -131,7 +131,7 @@ internal class GranularMetadataTransformation(
|
||||
val allModuleDependencies =
|
||||
configurationToResolve.incoming.resolutionResult.allDependencies.filterIsInstance<ResolvedDependencyResult>()
|
||||
|
||||
val resolvedDependencyQueue: Queue<ResolvedComponentResult> = ArrayDeque<ResolvedComponentResult>().apply {
|
||||
val resolvedDependencyQueue: Queue<ResolvedDependencyResult> = ArrayDeque<ResolvedDependencyResult>().apply {
|
||||
val requestedModules: Set<ModuleDependencyIdentifier> = allRequestedDependencies.mapTo(mutableSetOf()) {
|
||||
ModuleIds.fromDependency(it)
|
||||
}
|
||||
@@ -140,14 +140,14 @@ internal class GranularMetadataTransformation(
|
||||
resolutionResult.root.dependencies
|
||||
.filter { ModuleIds.fromComponentSelector(project, it.requested) in requestedModules }
|
||||
.filterIsInstance<ResolvedDependencyResult>()
|
||||
.map { it.selected }
|
||||
)
|
||||
}
|
||||
|
||||
val visitedDependencies = mutableSetOf<ResolvedComponentResult>()
|
||||
val visitedDependencies = mutableSetOf<ResolvedDependencyResult>()
|
||||
|
||||
while (resolvedDependencyQueue.isNotEmpty()) {
|
||||
val resolvedDependency: ResolvedComponentResult = resolvedDependencyQueue.poll()
|
||||
val resolvedDependency: ResolvedDependencyResult = resolvedDependencyQueue.poll()
|
||||
val selectedComponent = resolvedDependency.selected
|
||||
|
||||
if (!visitedDependencies.add(resolvedDependency)) {
|
||||
/* Already processed this dependency */
|
||||
@@ -156,14 +156,14 @@ internal class GranularMetadataTransformation(
|
||||
|
||||
val dependencyResult = processDependency(
|
||||
resolvedDependency,
|
||||
parentVisibleSourceSets[resolvedDependency.id.uniqueKey].orEmpty()
|
||||
parentVisibleSourceSets[selectedComponent.id.uniqueKey].orEmpty()
|
||||
)
|
||||
|
||||
result.add(dependencyResult)
|
||||
|
||||
val transitiveDependenciesToVisit = when (dependencyResult) {
|
||||
is MetadataDependencyResolution.KeepOriginalDependency ->
|
||||
resolvedDependency.dependencies.filterIsInstance<ResolvedDependencyResult>()
|
||||
selectedComponent.dependencies.filterIsInstance<ResolvedDependencyResult>()
|
||||
|
||||
is MetadataDependencyResolution.ChooseVisibleSourceSets -> dependencyResult.visibleTransitiveDependencies
|
||||
is MetadataDependencyResolution.Exclude.PublishedPlatformSourceSetDependency -> dependencyResult.visibleTransitiveDependencies
|
||||
@@ -171,13 +171,12 @@ internal class GranularMetadataTransformation(
|
||||
}
|
||||
|
||||
resolvedDependencyQueue.addAll(
|
||||
transitiveDependenciesToVisit.filter { it.selected !in visitedDependencies }
|
||||
.map { it.selected }
|
||||
transitiveDependenciesToVisit.filter { it !in visitedDependencies }
|
||||
)
|
||||
}
|
||||
|
||||
allModuleDependencies.forEach { resolvedDependency ->
|
||||
if (resolvedDependency.selected !in visitedDependencies) {
|
||||
if (resolvedDependency !in visitedDependencies) {
|
||||
// val files = resolvedDependency.moduleArtifacts.map { it.file }
|
||||
result.add(
|
||||
MetadataDependencyResolution.Exclude.Unrequested(
|
||||
@@ -205,9 +204,10 @@ internal class GranularMetadataTransformation(
|
||||
* source sets in *S*, then consider only these transitive dependencies, ignore the others;
|
||||
*/
|
||||
private fun processDependency(
|
||||
module: ResolvedComponentResult,
|
||||
dependency: ResolvedDependencyResult,
|
||||
sourceSetsVisibleInParents: Set<String>,
|
||||
): MetadataDependencyResolution {
|
||||
val module = dependency.selected
|
||||
val mppDependencyMetadataExtractor = MppDependencyProjectStructureMetadataExtractor.create(
|
||||
project, module, configurationToResolve,
|
||||
resolveViaAvailableAt = false // we will process the available-at module as a dependency later in the queue
|
||||
@@ -224,8 +224,8 @@ internal class GranularMetadataTransformation(
|
||||
|
||||
val sourceSetVisibility =
|
||||
SourceSetVisibilityProvider(project).getVisibleSourceSets(
|
||||
kotlinSourceSet,
|
||||
module,
|
||||
kotlinSourceSet.name,
|
||||
dependency,
|
||||
projectStructureMetadata,
|
||||
resolvedToProject != null
|
||||
)
|
||||
|
||||
+71
-30
@@ -6,17 +6,17 @@
|
||||
package org.jetbrains.kotlin.gradle.plugin.mpp
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.result.ResolvedComponentResult
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationToRunnableFiles
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.toSingleKpmModuleIdentifier
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.internal
|
||||
import org.gradle.api.artifacts.result.ResolvedDependencyResult
|
||||
import org.gradle.api.attributes.Usage
|
||||
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
|
||||
import org.jetbrains.kotlin.gradle.plugin.*
|
||||
import org.jetbrains.kotlin.gradle.utils.LazyResolvedConfiguration
|
||||
import org.jetbrains.kotlin.gradle.utils.allResolvedDependencies
|
||||
import org.jetbrains.kotlin.gradle.utils.dependencyArtifactsOrNull
|
||||
import java.io.File
|
||||
|
||||
private typealias KotlinSourceSetName = String
|
||||
|
||||
internal data class SourceSetVisibilityResult(
|
||||
/**
|
||||
* Names of source sets that the consumer sees from the requested dependency.
|
||||
@@ -30,15 +30,41 @@ internal data class SourceSetVisibilityResult(
|
||||
val hostSpecificMetadataArtifactBySourceSet: Map<String, File>
|
||||
)
|
||||
|
||||
private fun Project.collectAllPlatformCompilationData(): List<SourceSetVisibilityProvider.PlatformCompilationData> {
|
||||
val multiplatformExtension = multiplatformExtensionOrNull ?: return emptyList()
|
||||
return multiplatformExtension
|
||||
.targets
|
||||
.filter { it.platformType != KotlinPlatformType.common }
|
||||
.flatMap { target -> target.compilations.map { it.toPlatformCompilationData() } }
|
||||
}
|
||||
|
||||
private fun KotlinCompilation<*>.toPlatformCompilationData() = SourceSetVisibilityProvider.PlatformCompilationData(
|
||||
sourceSets = allKotlinSourceSets.map { it.name }.toSet(),
|
||||
resolvedDependenciesConfiguration = LazyResolvedConfiguration(project.configurations.getByName(compileDependencyConfigurationName)),
|
||||
hostSpecificMetadataConfiguration = project
|
||||
.configurations
|
||||
.getByName(compileDependencyConfigurationName)
|
||||
.copyRecursive().apply { attributes.attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(KotlinUsages.KOTLIN_METADATA)) }
|
||||
.let(::LazyResolvedConfiguration)
|
||||
)
|
||||
|
||||
internal class SourceSetVisibilityProvider(
|
||||
private val project: Project
|
||||
private val platformCompilations: List<PlatformCompilationData>,
|
||||
) {
|
||||
private val resolvedVariantsProvider = ResolvedMppVariantsProvider.get(project)
|
||||
constructor(project: Project) : this(
|
||||
platformCompilations = project.collectAllPlatformCompilationData()
|
||||
)
|
||||
|
||||
class PlatformCompilationData(
|
||||
val sourceSets: Set<KotlinSourceSetName>,
|
||||
val resolvedDependenciesConfiguration: LazyResolvedConfiguration,
|
||||
val hostSpecificMetadataConfiguration: LazyResolvedConfiguration?
|
||||
)
|
||||
|
||||
/**
|
||||
* Determine which source sets of the [resolvedRootMppDependency] are visible in the [visibleFrom] source set.
|
||||
* Determine which source sets of the [resolvedRootMppDependency] are visible in the [visibleFromSourceSet] source set.
|
||||
*
|
||||
* This requires resolving dependencies of the compilations which [visibleFrom] takes part in, in order to find which variants the
|
||||
* This requires resolving dependencies of the compilations which [visibleFromSourceSet] takes part in, in order to find which variants the
|
||||
* [resolvedRootMppDependency] got resolved to for those compilations.
|
||||
*
|
||||
* Once the variants are known, they are checked against the [dependencyProjectStructureMetadata], and the
|
||||
@@ -48,28 +74,28 @@ internal class SourceSetVisibilityProvider(
|
||||
* the Gradle API for dependency variants behaves differently for project dependencies and published ones.
|
||||
*/
|
||||
fun getVisibleSourceSets(
|
||||
visibleFrom: KotlinSourceSet,
|
||||
resolvedRootMppDependency: ResolvedComponentResult,
|
||||
visibleFromSourceSet: KotlinSourceSetName,
|
||||
resolvedRootMppDependency: ResolvedDependencyResult,
|
||||
dependencyProjectStructureMetadata: KotlinProjectStructureMetadata,
|
||||
resolvedToOtherProject: Boolean
|
||||
): SourceSetVisibilityResult {
|
||||
val compilations = visibleFrom.internal.compilations
|
||||
val component = resolvedRootMppDependency.selected
|
||||
val componentId = component.id
|
||||
|
||||
val component = resolvedRootMppDependency
|
||||
val mppModuleIdentifier = component.toSingleKpmModuleIdentifier()
|
||||
|
||||
val firstConfigurationByVariant = mutableMapOf<String, Configuration>()
|
||||
val firstConfigurationByVariant = mutableMapOf<String, PlatformCompilationData>()
|
||||
|
||||
val visiblePlatformVariantNames: Set<String?> =
|
||||
compilations
|
||||
.filter { it.target.platformType != KotlinPlatformType.common }
|
||||
.map { compilation -> project.configurations.getByName(compilation.compileDependencyConfigurationName) }
|
||||
.mapTo(mutableSetOf()) { configuration ->
|
||||
val resolvedVariant = resolvedVariantsProvider.getResolvedVariantName(mppModuleIdentifier, configuration)
|
||||
?.let { kotlinVariantNameFromPublishedVariantName(it) }
|
||||
platformCompilations
|
||||
.filter { visibleFromSourceSet in it.sourceSets }
|
||||
.mapTo(mutableSetOf()) { resolvedConfiguration ->
|
||||
val resolvedVariant = resolvedConfiguration
|
||||
.resolvedDependenciesConfiguration
|
||||
.allResolvedDependencies
|
||||
.find { it.selected.id == componentId }
|
||||
?.let { kotlinVariantNameFromPublishedVariantName(it.resolvedVariant.displayName) }
|
||||
?: return@mapTo null
|
||||
|
||||
firstConfigurationByVariant.putIfAbsent(resolvedVariant, configuration)
|
||||
firstConfigurationByVariant.putIfAbsent(resolvedVariant, resolvedConfiguration)
|
||||
resolvedVariant
|
||||
}
|
||||
|
||||
@@ -107,9 +133,24 @@ internal class SourceSetVisibilityProvider(
|
||||
}
|
||||
|
||||
someVariantByHostSpecificSourceSet.entries.mapNotNull { (sourceSetName, variantName) ->
|
||||
val configuration = firstConfigurationByVariant.getValue(variantName)
|
||||
resolvedVariantsProvider.getHostSpecificMetadataArtifactByRootModule(mppModuleIdentifier, configuration)
|
||||
?.let { sourceSetName to it }
|
||||
val resolvedHostSpecificMetadataConfiguration = firstConfigurationByVariant
|
||||
.getValue(variantName)
|
||||
.hostSpecificMetadataConfiguration
|
||||
?: return@mapNotNull null
|
||||
|
||||
val dependency = resolvedHostSpecificMetadataConfiguration
|
||||
.allResolvedDependencies
|
||||
.find { it.selected.id == componentId }
|
||||
?: return@mapNotNull null
|
||||
|
||||
val metadataArtifact = resolvedHostSpecificMetadataConfiguration
|
||||
// it can happen that related host-specific metadata artifact doesn't exist
|
||||
// for example on linux machines, then just gracefully return null
|
||||
.dependencyArtifactsOrNull(dependency)
|
||||
?.singleOrNull()
|
||||
?: return@mapNotNull null
|
||||
|
||||
sourceSetName to metadataArtifact.file
|
||||
}.toMap()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user