[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 {
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
@@ -288,7 +289,6 @@ class KpmGradleModuleVariantResolver : KpmModuleVariantResolver {
val module = requestingVariant.containingModule
val project = module.project
val resolvedVariantProvider = ResolvedMppVariantsProvider.get(project)
// This implementation can only resolve variants for the current project's KotlinModule
require(module.representsProject(project))
@@ -296,8 +296,8 @@ class KpmGradleModuleVariantResolver : KpmModuleVariantResolver {
val compileClasspath = getCompileDependenciesConfigurationForVariant(project, requestingVariant)
val dependencyModuleId = dependencyModule.moduleIdentifier
// FIXME check composite builds, it's likely that resolvedVariantProvider fails on them?
val resolvedGradleVariantName = resolvedVariantProvider.getResolvedVariantName(dependencyModuleId, compileClasspath)
/** @see SourceSetVisibilityProvider.PlatformCompilationData */
val resolvedGradleVariantName: String = TODO("Implement Resolved Gradle Variant finder as it done in TCS")
val kotlinVariantName = when (dependencyModule) {
is GradleKpmModule -> {
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 dependencyGraphResolver = GradleKpmDependencyGraphResolver(moduleResolver)
@Suppress("UNREACHABLE_CODE", "UNUSED_VARIABLE")
private fun doResolveMetadataDependencies(): Iterable<MetadataDependencyResolution> {
val configurationToResolve = configurationToResolveMetadataDependencies(requestingFragment.containingModule)
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
had to be read in order to create the Kotlin module and infer fragment visibility.
*/
val projectStructureMetadataExtractor = MppDependencyProjectStructureMetadataExtractor.create(
project, resolvedComponentResult, configurationToResolve, true
) ?: error(
"Failed to create 'MppDependencyProjectStructureMetadataExtractor' for ${resolvedComponentResult.id} despite " +
"the presence of a proper Kotlin Module"
)
val projectStructureMetadataExtractor: MppDependencyProjectStructureMetadataExtractor =
TODO("Implement for KPM. As it done for TCS")
val projectStructureMetadata = (dependencyModule as? GradleKpmExternalImportedModule)?.projectStructureMetadata
?: 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 { hostSpecificFragment in it.chosenVariant.withRefinesClosure }
// resolve the dependencies of that variant getting the host-specific metadata artifact
@Suppress("UNREACHABLE_CODE", "UNUSED_VARIABLE")
relevantVariantResolution?.let { resolution ->
val configurationResolvingPlatformVariant =
(resolution.requestingVariant as GradleKpmVariant).compileDependenciesConfiguration
val hostSpecificArtifact = ResolvedMppVariantsProvider.get(project)
.getHostSpecificMetadataArtifactByRootModule(
dependencyModule.moduleIdentifier,
configurationResolvingPlatformVariant
)
val hostSpecificArtifact: File? = TODO("Implement host-specific lookup for KPM as it done for TCS")
hostSpecificArtifact?.let { hostSpecificFragment.fragmentName to it }
}
}.toMap()
@@ -183,16 +183,12 @@ internal fun ComponentIdentifier.matchesModuleIdentifier(id: KpmModuleIdentifier
else -> false
}
@Suppress("UNUSED_PARAMETER")
private fun getProjectStructureMetadata(
project: Project,
module: ResolvedComponentResult,
configuration: Configuration,
moduleIdentifier: KpmModuleIdentifier? = null
): KotlinProjectStructureMetadata? {
val extractor = if (moduleIdentifier != null)
MppDependencyProjectStructureMetadataExtractor.create(project, module, moduleIdentifier, configuration)
else
MppDependencyProjectStructureMetadataExtractor.create(project, module, configuration, resolveViaAvailableAt = true)
return extractor?.getProjectStructureMetadata()
TODO("Implement project structure metadata extractor for KPM")
}