[Gradle] Remove ResolvedMppVariantsProvider and all related code in KPM

Mark places where ResolvedMppVariantsProvide were used with TODOs

^KT-49933
This commit is contained in:
Anton Lakotka
2023-01-18 11:03:03 +01:00
committed by Space Team
parent 25dbfb10b8
commit 674e7aa480
5 changed files with 10 additions and 317 deletions
@@ -269,6 +269,7 @@ class KpmCachingModuleVariantResolver(private val actualResolver: KpmModuleVaria
} }
} }
@Suppress("UNREACHABLE_CODE", "UNUSED_VARIABLE")
class KpmGradleModuleVariantResolver : KpmModuleVariantResolver { class KpmGradleModuleVariantResolver : KpmModuleVariantResolver {
override fun getChosenVariant(requestingVariant: KpmVariant, dependencyModule: KpmModule): KpmVariantResolution { override fun getChosenVariant(requestingVariant: KpmVariant, dependencyModule: KpmModule): KpmVariantResolution {
// TODO maybe improve this behavior? Currently it contradicts dependency resolution in that it may return a chosen variant for an // TODO maybe improve this behavior? Currently it contradicts dependency resolution in that it may return a chosen variant for an
@@ -288,7 +289,6 @@ class KpmGradleModuleVariantResolver : KpmModuleVariantResolver {
val module = requestingVariant.containingModule val module = requestingVariant.containingModule
val project = module.project val project = module.project
val resolvedVariantProvider = ResolvedMppVariantsProvider.get(project)
// This implementation can only resolve variants for the current project's KotlinModule // This implementation can only resolve variants for the current project's KotlinModule
require(module.representsProject(project)) require(module.representsProject(project))
@@ -296,8 +296,8 @@ class KpmGradleModuleVariantResolver : KpmModuleVariantResolver {
val compileClasspath = getCompileDependenciesConfigurationForVariant(project, requestingVariant) val compileClasspath = getCompileDependenciesConfigurationForVariant(project, requestingVariant)
val dependencyModuleId = dependencyModule.moduleIdentifier val dependencyModuleId = dependencyModule.moduleIdentifier
// FIXME check composite builds, it's likely that resolvedVariantProvider fails on them? /** @see SourceSetVisibilityProvider.PlatformCompilationData */
val resolvedGradleVariantName = resolvedVariantProvider.getResolvedVariantName(dependencyModuleId, compileClasspath) val resolvedGradleVariantName: String = TODO("Implement Resolved Gradle Variant finder as it done in TCS")
val kotlinVariantName = when (dependencyModule) { val kotlinVariantName = when (dependencyModule) {
is GradleKpmModule -> { is GradleKpmModule -> {
dependencyModule.variants.singleOrNull { resolvedGradleVariantName in it.gradleVariantNames }?.name dependencyModule.variants.singleOrNull { resolvedGradleVariantName in it.gradleVariantNames }?.name
@@ -57,79 +57,3 @@ internal class MppDependencyProjectStructureMetadataExtractorFactory(
} }
} }
} }
internal fun MppDependencyProjectStructureMetadataExtractor.Factory.create(
project: Project,
resolvedComponentResult: ResolvedComponentResult,
configuration: Configuration,
resolveViaAvailableAt: Boolean
): MppDependencyProjectStructureMetadataExtractor? {
return create(
resolvedMppVariantsProvider = ResolvedMppVariantsProvider.get(project),
/*
FIXME this loses information about auxiliary module deps
TODO check how this code works with multi-capability resolutions,
*/
moduleIdentifier = resolvedComponentResult.toSingleKpmModuleIdentifier(),
configuration = configuration,
resolveViaAvailableAt = resolveViaAvailableAt,
resolvedComponentResult = resolvedComponentResult,
project = project
)
}
internal fun MppDependencyProjectStructureMetadataExtractor.Factory.create(
project: Project,
resolvedComponentResult: ResolvedComponentResult,
moduleIdentifier: KpmModuleIdentifier,
configuration: Configuration
): MppDependencyProjectStructureMetadataExtractor? {
return create(
resolvedMppVariantsProvider = ResolvedMppVariantsProvider.get(project),
moduleIdentifier = moduleIdentifier,
configuration = configuration,
resolveViaAvailableAt = true,
resolvedComponentResult = resolvedComponentResult,
project = project
)
}
private fun MppDependencyProjectStructureMetadataExtractor.Factory.create(
resolvedMppVariantsProvider: ResolvedMppVariantsProvider,
moduleIdentifier: KpmModuleIdentifier,
configuration: Configuration,
resolveViaAvailableAt: Boolean,
resolvedComponentResult: ResolvedComponentResult,
project: Project
): MppDependencyProjectStructureMetadataExtractor? {
var resolvedViaAvailableAt = false
val metadataArtifact = resolvedMppVariantsProvider.getResolvedArtifactByPlatformModule(
moduleIdentifier,
configuration
) ?: if (resolveViaAvailableAt) {
resolvedMppVariantsProvider.getHostSpecificMetadataArtifactByRootModule(
moduleIdentifier, configuration
)?.also {
resolvedViaAvailableAt = true
}
} else null
val actualComponent = if (resolvedViaAvailableAt) {
resolvedComponentResult.dependencies.filterIsInstance<ResolvedDependencyResult>().singleOrNull()?.selected
?: resolvedComponentResult
} else resolvedComponentResult
val moduleId = actualComponent.id
return when {
moduleId is ProjectComponentIdentifier -> when {
moduleId.build.isCurrentBuild ->
ProjectMppDependencyProjectStructureMetadataExtractor(moduleIdentifier, project.project(moduleId.projectPath))
metadataArtifact != null ->
IncludedBuildMppDependencyProjectStructureMetadataExtractor(project, actualComponent, metadataArtifact)
else -> null
}
metadataArtifact != null -> JarMppDependencyProjectStructureMetadataExtractor(metadataArtifact)
else -> null
}
}
@@ -1,221 +0,0 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
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.artifacts.result.ResolvedVariantResult
import org.gradle.api.attributes.Usage
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.toKpmModuleIdentifiers
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.toSingleKpmModuleIdentifier
import org.jetbrains.kotlin.gradle.plugin.usageByName
import org.jetbrains.kotlin.gradle.utils.getOrPut
import org.jetbrains.kotlin.project.model.KpmModuleIdentifier
import java.io.File
internal class ResolvedMppVariantsProvider private constructor(private val project: Project) {
companion object {
fun get(project: Project): ResolvedMppVariantsProvider {
val propertyName = "kotlin.mpp.internal.resolvedModuleVariantsProvider"
return project.extensions.extraProperties.getOrPut(propertyName) {
ResolvedMppVariantsProvider(project)
}
}
}
/** Gets the name of the variant that the module specified by the [moduleIdentifier] resolved to in the given [configuration].
* The [moduleIdentifier] may be either the root module or a platform-specific module, the result is the same for the two cases. */
fun getResolvedVariantName(moduleIdentifier: KpmModuleIdentifier, configuration: Configuration): String? =
getEntryForModule(moduleIdentifier).run {
if (configuration !in resolvedVariantsByConfiguration) {
resolveConfigurationAndSaveVariants(configuration, artifactResolutionMode = ArtifactResolutionMode.NONE)
}
val variants = resolvedVariantsByConfiguration.getOrPut(configuration) { null }
variants?.singleOrNull()?.displayName
}
/** Gets the artifact that contains the common code metadata for the given [rootModuleIdentifier], which can only denote the root
* module of a multiplatform project, not one of its platform-specific modules, as seen in the given [configuration].
* If the [configuration] requests platform artifacts and not the common code metadata, then this function will resolve its
* dependencies to metadata separately. */
fun getHostSpecificMetadataArtifactByRootModule(rootModuleIdentifier: KpmModuleIdentifier, configuration: Configuration): File? {
val rootModuleEntry = getEntryForModule(rootModuleIdentifier)
val platformModuleEntry = rootModuleEntry.run {
if (configuration !in chosenPlatformModuleByConfiguration) {
resolveConfigurationAndSaveVariants(configuration, artifactResolutionMode = ArtifactResolutionMode.METADATA)
}
// At this point the map should contain the result if calculation above succeeded. If not, put null to avoid recalculation.
chosenPlatformModuleByConfiguration.getOrPut(configuration) { null }
}
return platformModuleEntry?.run {
// The condition might be true if the configuration has only been resolved with resolution mode NORMAL
if (configuration !in resolvedMetadataArtifactByConfiguration) {
resolveConfigurationAndSaveVariants(configuration, artifactResolutionMode = ArtifactResolutionMode.METADATA)
}
// At this point the map should contain the result if calculation above succeeded. If not, put null to avoid recalculation.
resolvedMetadataArtifactByConfiguration.getOrPut(configuration) { null }
}
}
/** Gets the artifact of a particular MPP platform-specific [moduleIdentifier] as resolved in the [configuration]. */
fun getResolvedArtifactByPlatformModule(moduleIdentifier: KpmModuleIdentifier, configuration: Configuration): File? =
getEntryForModule(moduleIdentifier).run {
if (configuration !in resolvedArtifactByConfiguration) {
resolveConfigurationAndSaveVariants(configuration, artifactResolutionMode = ArtifactResolutionMode.NORMAL)
}
// At this point the map should contain the result if the calculation above succeeded. If not, put null to avoid recalculation.
resolvedArtifactByConfiguration.getOrPut(configuration) { null }
}
private fun getEntryForModule(moduleIdentifier: KpmModuleIdentifier) =
entriesCache.getOrPut(moduleIdentifier, { ModuleEntry(moduleIdentifier) })
private val entriesCache: MutableMap<KpmModuleIdentifier, ModuleEntry> = mutableMapOf()
private val mppComponentsByConfiguration: MutableMap<Configuration, Set<ResolvedComponentResult>> = mutableMapOf()
private enum class ArtifactResolutionMode {
NONE, NORMAL, METADATA
}
private fun resolveConfigurationAndSaveVariants(
configuration: Configuration,
artifactResolutionMode: ArtifactResolutionMode
) {
val mppComponentIds: Set<ResolvedComponentResult> = mppComponentsByConfiguration.getOrPut(configuration) {
resolveMppComponents(configuration)
}
if (artifactResolutionMode != ArtifactResolutionMode.NONE) {
val artifacts = resolveArtifacts(artifactResolutionMode, configuration, mppComponentIds)
matchMppComponentsWithResolvedArtifacts(mppComponentIds, artifacts, configuration, artifactResolutionMode)
}
}
private fun resolveMppComponents(configuration: Configuration): Set<ResolvedComponentResult> {
val result = mutableListOf<ResolvedComponentResult>()
configuration.incoming.resolutionResult.allComponents { component ->
val isMpp = component.dependents.isNotEmpty() && // filter out the root of the dependency graph, we are not interested in it
component.variants.any { variant -> variant.attributes.keySet().any { it.name == KotlinPlatformType.attribute.name } }
if (isMpp) {
result.add(component)
component.dependents.forEach { dependent ->
dependent.selected.toKpmModuleIdentifiers().forEach { moduleId ->
val moduleEntry = getEntryForModule(moduleId)
moduleEntry.resolvedVariantsByConfiguration[configuration] = listOf(dependent.resolvedVariant)
moduleEntry.dependenciesByConfiguration[configuration] = component.dependencies
.filterIsInstance<ResolvedDependencyResult>()
.map { dependency -> dependency.selected.toSingleKpmModuleIdentifier() }
if (component.id is ProjectComponentIdentifier) {
// Then the platform variant chosen for this module is definitely inside the module itself:
moduleEntry.chosenPlatformModuleByConfiguration[configuration] = moduleEntry
}
}
}
}
}
return result.toSet()
}
private fun resolveArtifacts(
artifactResolutionMode: ArtifactResolutionMode,
configuration: Configuration,
mppComponents: Set<ResolvedComponentResult>
): Map<ResolvedComponentResult, ResolvedArtifactResult> {
val mppComponentById = mppComponents.associateBy { it.id }
val artifactsConfiguration =
if (
artifactResolutionMode == ArtifactResolutionMode.NORMAL ||
configuration.attributes.getAttribute(Usage.USAGE_ATTRIBUTE)?.name == KotlinUsages.KOTLIN_METADATA
) {
configuration
} else {
configuration.copyRecursive().apply {
attributes.attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(KotlinUsages.KOTLIN_METADATA))
}
}
return artifactsConfiguration.incoming.artifactView { view ->
view.componentFilter { it in mppComponentById }
view.attributes { attrs -> attrs.attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(KotlinUsages.KOTLIN_METADATA)) }
view.lenient(true)
}.artifacts.associateBy { mppComponentById.getValue(it.id.componentIdentifier) }
}
private fun matchMppComponentsWithResolvedArtifacts(
mppComponentIds: Set<ResolvedComponentResult>,
artifacts: Map<ResolvedComponentResult, ResolvedArtifactResult>,
configuration: Configuration,
artifactResolutionMode: ArtifactResolutionMode
) {
val mppModuleIds = mppComponentIds.flatMapTo(mutableSetOf()) { componentId ->
componentId.toKpmModuleIdentifiers()
}
mppComponentIds.forEach { componentId ->
componentId.toKpmModuleIdentifiers().forEach { moduleId ->
val moduleEntry = getEntryForModule(moduleId)
val artifact = artifacts[componentId]
when {
// With project dependencies, we don't need the host-specific metadata artifacts, as we have the compilation outputs:
componentId is ProjectComponentIdentifier -> {
moduleEntry.resolvedMetadataArtifactByConfiguration[configuration] = null
}
// We found a requested artifact of the MPP; it is one of: platform artifact, root metadata, host-specific metadata
artifact != null -> {
val resolvedArtifactMap = when (artifactResolutionMode) {
ArtifactResolutionMode.NORMAL -> moduleEntry.resolvedArtifactByConfiguration
ArtifactResolutionMode.METADATA -> moduleEntry.resolvedMetadataArtifactByConfiguration
else -> error("unexpected $artifactResolutionMode")
}
resolvedArtifactMap[configuration] = artifact.file
}
// Otherwise, this may be a root module of some MPP that resolved to a variant in another module. Take a note of that.
else -> {
// TODO: there's an assumption that resolving a root MPP module to a host-specific metadata artifact and to a platform
// artifact will choose variants that are published within the same Maven module; change this code if that's not
// true anymore.
val singleDependencyId = moduleEntry.dependenciesByConfiguration.getValue(configuration).singleOrNull()
if (singleDependencyId != null && singleDependencyId in mppModuleIds) {
moduleEntry.chosenPlatformModuleByConfiguration[configuration] =
getEntryForModule(singleDependencyId)
}
}
}
}
}
}
/**
* Stores resolution results of the module denoted by [moduleIdentifier] in different configurations of the project.
* The [moduleIdentifier] may point to a root module of a multiplatform project (then it has meaningful
* [chosenPlatformModuleByConfiguration]) or to a platform module.
*/
private class ModuleEntry(
@Suppress("unused") // simplify debugging
val moduleIdentifier: KpmModuleIdentifier
) {
val dependenciesByConfiguration: MutableMap<Configuration, List<KpmModuleIdentifier>> = HashMap()
val resolvedVariantsByConfiguration: MutableMap<Configuration, List<ResolvedVariantResult?>?> = HashMap()
val resolvedArtifactByConfiguration: MutableMap<Configuration, File?> = HashMap()
val resolvedMetadataArtifactByConfiguration: MutableMap<Configuration, File?> = HashMap()
val chosenPlatformModuleByConfiguration: MutableMap<Configuration, ModuleEntry?> = HashMap()
}
}
@@ -34,6 +34,7 @@ internal class GradleKpmFragmentGranularMetadataResolver(
private val fragmentResolver = KpmDefaultFragmentsResolver(variantResolver) private val fragmentResolver = KpmDefaultFragmentsResolver(variantResolver)
private val dependencyGraphResolver = GradleKpmDependencyGraphResolver(moduleResolver) private val dependencyGraphResolver = GradleKpmDependencyGraphResolver(moduleResolver)
@Suppress("UNREACHABLE_CODE", "UNUSED_VARIABLE")
private fun doResolveMetadataDependencies(): Iterable<MetadataDependencyResolution> { private fun doResolveMetadataDependencies(): Iterable<MetadataDependencyResolution> {
val configurationToResolve = configurationToResolveMetadataDependencies(requestingFragment.containingModule) val configurationToResolve = configurationToResolveMetadataDependencies(requestingFragment.containingModule)
val resolvedComponentsByModuleId = val resolvedComponentsByModuleId =
@@ -91,12 +92,8 @@ internal class GradleKpmFragmentGranularMetadataResolver(
We can safely assume that a metadata extractor can be created, because the project structure metadata already We can safely assume that a metadata extractor can be created, because the project structure metadata already
had to be read in order to create the Kotlin module and infer fragment visibility. had to be read in order to create the Kotlin module and infer fragment visibility.
*/ */
val projectStructureMetadataExtractor = MppDependencyProjectStructureMetadataExtractor.create( val projectStructureMetadataExtractor: MppDependencyProjectStructureMetadataExtractor =
project, resolvedComponentResult, configurationToResolve, true TODO("Implement for KPM. As it done for TCS")
) ?: error(
"Failed to create 'MppDependencyProjectStructureMetadataExtractor' for ${resolvedComponentResult.id} despite " +
"the presence of a proper Kotlin Module"
)
val projectStructureMetadata = (dependencyModule as? GradleKpmExternalImportedModule)?.projectStructureMetadata val projectStructureMetadata = (dependencyModule as? GradleKpmExternalImportedModule)?.projectStructureMetadata
?: checkNotNull(projectStructureMetadataExtractor.getProjectStructureMetadata()) ?: checkNotNull(projectStructureMetadataExtractor.getProjectStructureMetadata())
@@ -160,14 +157,11 @@ internal class GradleKpmFragmentGranularMetadataResolver(
// find some of our variants that resolved a dependency's variant containing the fragment // find some of our variants that resolved a dependency's variant containing the fragment
.find { hostSpecificFragment in it.chosenVariant.withRefinesClosure } .find { hostSpecificFragment in it.chosenVariant.withRefinesClosure }
// resolve the dependencies of that variant getting the host-specific metadata artifact // resolve the dependencies of that variant getting the host-specific metadata artifact
@Suppress("UNREACHABLE_CODE", "UNUSED_VARIABLE")
relevantVariantResolution?.let { resolution -> relevantVariantResolution?.let { resolution ->
val configurationResolvingPlatformVariant = val configurationResolvingPlatformVariant =
(resolution.requestingVariant as GradleKpmVariant).compileDependenciesConfiguration (resolution.requestingVariant as GradleKpmVariant).compileDependenciesConfiguration
val hostSpecificArtifact = ResolvedMppVariantsProvider.get(project) val hostSpecificArtifact: File? = TODO("Implement host-specific lookup for KPM as it done for TCS")
.getHostSpecificMetadataArtifactByRootModule(
dependencyModule.moduleIdentifier,
configurationResolvingPlatformVariant
)
hostSpecificArtifact?.let { hostSpecificFragment.fragmentName to it } hostSpecificArtifact?.let { hostSpecificFragment.fragmentName to it }
} }
}.toMap() }.toMap()
@@ -183,16 +183,12 @@ internal fun ComponentIdentifier.matchesModuleIdentifier(id: KpmModuleIdentifier
else -> false else -> false
} }
@Suppress("UNUSED_PARAMETER")
private fun getProjectStructureMetadata( private fun getProjectStructureMetadata(
project: Project, project: Project,
module: ResolvedComponentResult, module: ResolvedComponentResult,
configuration: Configuration, configuration: Configuration,
moduleIdentifier: KpmModuleIdentifier? = null moduleIdentifier: KpmModuleIdentifier? = null
): KotlinProjectStructureMetadata? { ): KotlinProjectStructureMetadata? {
val extractor = if (moduleIdentifier != null) TODO("Implement project structure metadata extractor for KPM")
MppDependencyProjectStructureMetadataExtractor.create(project, module, moduleIdentifier, configuration)
else
MppDependencyProjectStructureMetadataExtractor.create(project, module, configuration, resolveViaAvailableAt = true)
return extractor?.getProjectStructureMetadata()
} }