[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 =
|
val allModuleDependencies =
|
||||||
configurationToResolve.incoming.resolutionResult.allDependencies.filterIsInstance<ResolvedDependencyResult>()
|
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()) {
|
val requestedModules: Set<ModuleDependencyIdentifier> = allRequestedDependencies.mapTo(mutableSetOf()) {
|
||||||
ModuleIds.fromDependency(it)
|
ModuleIds.fromDependency(it)
|
||||||
}
|
}
|
||||||
@@ -140,14 +140,14 @@ internal class GranularMetadataTransformation(
|
|||||||
resolutionResult.root.dependencies
|
resolutionResult.root.dependencies
|
||||||
.filter { ModuleIds.fromComponentSelector(project, it.requested) in requestedModules }
|
.filter { ModuleIds.fromComponentSelector(project, it.requested) in requestedModules }
|
||||||
.filterIsInstance<ResolvedDependencyResult>()
|
.filterIsInstance<ResolvedDependencyResult>()
|
||||||
.map { it.selected }
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val visitedDependencies = mutableSetOf<ResolvedComponentResult>()
|
val visitedDependencies = mutableSetOf<ResolvedDependencyResult>()
|
||||||
|
|
||||||
while (resolvedDependencyQueue.isNotEmpty()) {
|
while (resolvedDependencyQueue.isNotEmpty()) {
|
||||||
val resolvedDependency: ResolvedComponentResult = resolvedDependencyQueue.poll()
|
val resolvedDependency: ResolvedDependencyResult = resolvedDependencyQueue.poll()
|
||||||
|
val selectedComponent = resolvedDependency.selected
|
||||||
|
|
||||||
if (!visitedDependencies.add(resolvedDependency)) {
|
if (!visitedDependencies.add(resolvedDependency)) {
|
||||||
/* Already processed this dependency */
|
/* Already processed this dependency */
|
||||||
@@ -156,14 +156,14 @@ internal class GranularMetadataTransformation(
|
|||||||
|
|
||||||
val dependencyResult = processDependency(
|
val dependencyResult = processDependency(
|
||||||
resolvedDependency,
|
resolvedDependency,
|
||||||
parentVisibleSourceSets[resolvedDependency.id.uniqueKey].orEmpty()
|
parentVisibleSourceSets[selectedComponent.id.uniqueKey].orEmpty()
|
||||||
)
|
)
|
||||||
|
|
||||||
result.add(dependencyResult)
|
result.add(dependencyResult)
|
||||||
|
|
||||||
val transitiveDependenciesToVisit = when (dependencyResult) {
|
val transitiveDependenciesToVisit = when (dependencyResult) {
|
||||||
is MetadataDependencyResolution.KeepOriginalDependency ->
|
is MetadataDependencyResolution.KeepOriginalDependency ->
|
||||||
resolvedDependency.dependencies.filterIsInstance<ResolvedDependencyResult>()
|
selectedComponent.dependencies.filterIsInstance<ResolvedDependencyResult>()
|
||||||
|
|
||||||
is MetadataDependencyResolution.ChooseVisibleSourceSets -> dependencyResult.visibleTransitiveDependencies
|
is MetadataDependencyResolution.ChooseVisibleSourceSets -> dependencyResult.visibleTransitiveDependencies
|
||||||
is MetadataDependencyResolution.Exclude.PublishedPlatformSourceSetDependency -> dependencyResult.visibleTransitiveDependencies
|
is MetadataDependencyResolution.Exclude.PublishedPlatformSourceSetDependency -> dependencyResult.visibleTransitiveDependencies
|
||||||
@@ -171,13 +171,12 @@ internal class GranularMetadataTransformation(
|
|||||||
}
|
}
|
||||||
|
|
||||||
resolvedDependencyQueue.addAll(
|
resolvedDependencyQueue.addAll(
|
||||||
transitiveDependenciesToVisit.filter { it.selected !in visitedDependencies }
|
transitiveDependenciesToVisit.filter { it !in visitedDependencies }
|
||||||
.map { it.selected }
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
allModuleDependencies.forEach { resolvedDependency ->
|
allModuleDependencies.forEach { resolvedDependency ->
|
||||||
if (resolvedDependency.selected !in visitedDependencies) {
|
if (resolvedDependency !in visitedDependencies) {
|
||||||
// val files = resolvedDependency.moduleArtifacts.map { it.file }
|
// val files = resolvedDependency.moduleArtifacts.map { it.file }
|
||||||
result.add(
|
result.add(
|
||||||
MetadataDependencyResolution.Exclude.Unrequested(
|
MetadataDependencyResolution.Exclude.Unrequested(
|
||||||
@@ -205,9 +204,10 @@ internal class GranularMetadataTransformation(
|
|||||||
* source sets in *S*, then consider only these transitive dependencies, ignore the others;
|
* source sets in *S*, then consider only these transitive dependencies, ignore the others;
|
||||||
*/
|
*/
|
||||||
private fun processDependency(
|
private fun processDependency(
|
||||||
module: ResolvedComponentResult,
|
dependency: ResolvedDependencyResult,
|
||||||
sourceSetsVisibleInParents: Set<String>,
|
sourceSetsVisibleInParents: Set<String>,
|
||||||
): MetadataDependencyResolution {
|
): MetadataDependencyResolution {
|
||||||
|
val module = dependency.selected
|
||||||
val mppDependencyMetadataExtractor = MppDependencyProjectStructureMetadataExtractor.create(
|
val mppDependencyMetadataExtractor = MppDependencyProjectStructureMetadataExtractor.create(
|
||||||
project, module, configurationToResolve,
|
project, module, configurationToResolve,
|
||||||
resolveViaAvailableAt = false // we will process the available-at module as a dependency later in the queue
|
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 =
|
val sourceSetVisibility =
|
||||||
SourceSetVisibilityProvider(project).getVisibleSourceSets(
|
SourceSetVisibilityProvider(project).getVisibleSourceSets(
|
||||||
kotlinSourceSet,
|
kotlinSourceSet.name,
|
||||||
module,
|
dependency,
|
||||||
projectStructureMetadata,
|
projectStructureMetadata,
|
||||||
resolvedToProject != null
|
resolvedToProject != null
|
||||||
)
|
)
|
||||||
|
|||||||
+71
-30
@@ -6,17 +6,17 @@
|
|||||||
package org.jetbrains.kotlin.gradle.plugin.mpp
|
package org.jetbrains.kotlin.gradle.plugin.mpp
|
||||||
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.artifacts.Configuration
|
import org.gradle.api.artifacts.result.ResolvedDependencyResult
|
||||||
import org.gradle.api.artifacts.result.ResolvedComponentResult
|
import org.gradle.api.attributes.Usage
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationToRunnableFiles
|
import org.jetbrains.kotlin.gradle.plugin.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
import org.jetbrains.kotlin.gradle.utils.LazyResolvedConfiguration
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
import org.jetbrains.kotlin.gradle.utils.allResolvedDependencies
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.toSingleKpmModuleIdentifier
|
import org.jetbrains.kotlin.gradle.utils.dependencyArtifactsOrNull
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.internal
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
private typealias KotlinSourceSetName = String
|
||||||
|
|
||||||
internal data class SourceSetVisibilityResult(
|
internal data class SourceSetVisibilityResult(
|
||||||
/**
|
/**
|
||||||
* Names of source sets that the consumer sees from the requested dependency.
|
* 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>
|
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(
|
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.
|
* [resolvedRootMppDependency] got resolved to for those compilations.
|
||||||
*
|
*
|
||||||
* Once the variants are known, they are checked against the [dependencyProjectStructureMetadata], and the
|
* 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.
|
* the Gradle API for dependency variants behaves differently for project dependencies and published ones.
|
||||||
*/
|
*/
|
||||||
fun getVisibleSourceSets(
|
fun getVisibleSourceSets(
|
||||||
visibleFrom: KotlinSourceSet,
|
visibleFromSourceSet: KotlinSourceSetName,
|
||||||
resolvedRootMppDependency: ResolvedComponentResult,
|
resolvedRootMppDependency: ResolvedDependencyResult,
|
||||||
dependencyProjectStructureMetadata: KotlinProjectStructureMetadata,
|
dependencyProjectStructureMetadata: KotlinProjectStructureMetadata,
|
||||||
resolvedToOtherProject: Boolean
|
resolvedToOtherProject: Boolean
|
||||||
): SourceSetVisibilityResult {
|
): SourceSetVisibilityResult {
|
||||||
val compilations = visibleFrom.internal.compilations
|
val component = resolvedRootMppDependency.selected
|
||||||
|
val componentId = component.id
|
||||||
|
|
||||||
val component = resolvedRootMppDependency
|
val firstConfigurationByVariant = mutableMapOf<String, PlatformCompilationData>()
|
||||||
val mppModuleIdentifier = component.toSingleKpmModuleIdentifier()
|
|
||||||
|
|
||||||
val firstConfigurationByVariant = mutableMapOf<String, Configuration>()
|
|
||||||
|
|
||||||
val visiblePlatformVariantNames: Set<String?> =
|
val visiblePlatformVariantNames: Set<String?> =
|
||||||
compilations
|
platformCompilations
|
||||||
.filter { it.target.platformType != KotlinPlatformType.common }
|
.filter { visibleFromSourceSet in it.sourceSets }
|
||||||
.map { compilation -> project.configurations.getByName(compilation.compileDependencyConfigurationName) }
|
.mapTo(mutableSetOf()) { resolvedConfiguration ->
|
||||||
.mapTo(mutableSetOf()) { configuration ->
|
val resolvedVariant = resolvedConfiguration
|
||||||
val resolvedVariant = resolvedVariantsProvider.getResolvedVariantName(mppModuleIdentifier, configuration)
|
.resolvedDependenciesConfiguration
|
||||||
?.let { kotlinVariantNameFromPublishedVariantName(it) }
|
.allResolvedDependencies
|
||||||
|
.find { it.selected.id == componentId }
|
||||||
|
?.let { kotlinVariantNameFromPublishedVariantName(it.resolvedVariant.displayName) }
|
||||||
?: return@mapTo null
|
?: return@mapTo null
|
||||||
|
|
||||||
firstConfigurationByVariant.putIfAbsent(resolvedVariant, configuration)
|
firstConfigurationByVariant.putIfAbsent(resolvedVariant, resolvedConfiguration)
|
||||||
resolvedVariant
|
resolvedVariant
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,9 +133,24 @@ internal class SourceSetVisibilityProvider(
|
|||||||
}
|
}
|
||||||
|
|
||||||
someVariantByHostSpecificSourceSet.entries.mapNotNull { (sourceSetName, variantName) ->
|
someVariantByHostSpecificSourceSet.entries.mapNotNull { (sourceSetName, variantName) ->
|
||||||
val configuration = firstConfigurationByVariant.getValue(variantName)
|
val resolvedHostSpecificMetadataConfiguration = firstConfigurationByVariant
|
||||||
resolvedVariantsProvider.getHostSpecificMetadataArtifactByRootModule(mppModuleIdentifier, configuration)
|
.getValue(variantName)
|
||||||
?.let { sourceSetName to it }
|
.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()
|
}.toMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user