Get rid of DependencyDiscovery in favor of DependencyGraphResolver
This commit is contained in:
-122
@@ -60,90 +60,6 @@ class GradleModuleDependencyResolver(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GradleProjectDependencyDiscovery(
|
|
||||||
private val project: Project,
|
|
||||||
private val variantDependencyDiscovery: VariantDependencyDiscovery,
|
|
||||||
private val fragmentDependenciesDiscovery: FragmentDependenciesDiscovery
|
|
||||||
) : DependencyDiscovery {
|
|
||||||
override fun discoverDependencies(fragment: KotlinModuleFragment): Iterable<KotlinModuleDependency> {
|
|
||||||
require(fragment.containingModule.representsProject(project))
|
|
||||||
return when (fragment) {
|
|
||||||
is KotlinModuleVariant -> variantDependencyDiscovery.discoverDependencies(fragment)
|
|
||||||
else -> fragmentDependenciesDiscovery.discoverDependencies(fragment)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class FragmentDependenciesDiscovery(
|
|
||||||
private val project: Project,
|
|
||||||
private val moduleResolver: ModuleDependencyResolver,
|
|
||||||
private val fragmentsResolver: ModuleFragmentsResolver
|
|
||||||
) : DependencyDiscovery {
|
|
||||||
private val dependencyScopes = listOf(KotlinDependencyScope.API_SCOPE, KotlinDependencyScope.IMPLEMENTATION_SCOPE)
|
|
||||||
|
|
||||||
private fun KotlinModuleFragment.toSourceSet(): KotlinSourceSet = project.kotlinExtension.sourceSets.getByName(fragmentName)
|
|
||||||
|
|
||||||
// TODO: use the dependency graph resolution implementation?
|
|
||||||
override fun discoverDependencies(fragment: KotlinModuleFragment): Iterable<KotlinModuleDependency> {
|
|
||||||
require(fragment.containingModule.representsProject(project))
|
|
||||||
|
|
||||||
val fragmentsWhoseDependenciesAreVisible = fragment.refinesClosure
|
|
||||||
|
|
||||||
// FIXME use dependencyScopes, not just sets of declared module dependencies
|
|
||||||
val requestedDependencies = fragmentsWhoseDependenciesAreVisible.flatMap { it.declaredModuleDependencies }.toSet()
|
|
||||||
|
|
||||||
val configurationToResolve = resolvableMetadataConfiguration(
|
|
||||||
project,
|
|
||||||
fragmentsWhoseDependenciesAreVisible.map { it.toSourceSet() },
|
|
||||||
KotlinDependencyScope.compileScopes
|
|
||||||
)
|
|
||||||
val allComponents = configurationToResolve.incoming.resolutionResult.allComponents
|
|
||||||
|
|
||||||
val componentsByRequestedDependency =
|
|
||||||
allComponents.flatMap { component -> component.dependents.map { it to component } }.toMap()
|
|
||||||
.mapKeys { it.key.requested.toModuleDependency() }
|
|
||||||
|
|
||||||
val resolvedComponentQueue = ArrayDeque<ResolvedComponentResult>().apply {
|
|
||||||
addAll(componentsByRequestedDependency.filterKeys { it in requestedDependencies }.values)
|
|
||||||
}
|
|
||||||
|
|
||||||
val visited = mutableSetOf<ResolvedComponentResult>()
|
|
||||||
val excludeLegacyMetadataModulesFromResult = mutableSetOf<ResolvedComponentResult>()
|
|
||||||
|
|
||||||
while (resolvedComponentQueue.isNotEmpty()) {
|
|
||||||
val component = resolvedComponentQueue.removeFirst()
|
|
||||||
visited.add(component)
|
|
||||||
|
|
||||||
val module = moduleResolver.resolveDependency(fragment.containingModule, component.toModuleDependency())
|
|
||||||
.takeIf { component !in excludeLegacyMetadataModulesFromResult }
|
|
||||||
?: buildSyntheticModule(component, component.variants.singleOrNull()?.displayName ?: "default")
|
|
||||||
|
|
||||||
val transitiveDepsToVisit = when (val fragmentsResolution = fragmentsResolver.getChosenFragments(fragment, module)) {
|
|
||||||
is FragmentResolution.ChosenFragments ->
|
|
||||||
fragmentsResolution.visibleFragments.flatMap { it.declaredModuleDependencies }.mapNotNull { dependency ->
|
|
||||||
componentsByRequestedDependency[dependency]
|
|
||||||
}
|
|
||||||
else -> emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
val newTransitiveDeps = transitiveDepsToVisit.filterTo(mutableListOf()) { it !in visited }
|
|
||||||
|
|
||||||
// With legacy publication scheme, the root MPP module may have a single 'dependency' (available-at) to the metadata module
|
|
||||||
val isMetadataModulePublishedSeparately =
|
|
||||||
(module is ExternalImportedKotlinModule) && module.hasLegacyMetadataModule
|
|
||||||
val singleDependencyComponentOrNull = (component.dependencies.singleOrNull() as? ResolvedDependencyResult)?.selected
|
|
||||||
if (isMetadataModulePublishedSeparately && singleDependencyComponentOrNull != null) {
|
|
||||||
newTransitiveDeps.add(singleDependencyComponentOrNull)
|
|
||||||
excludeLegacyMetadataModulesFromResult.add(singleDependencyComponentOrNull)
|
|
||||||
}
|
|
||||||
|
|
||||||
resolvedComponentQueue.addAll(newTransitiveDeps)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (visited - excludeLegacyMetadataModulesFromResult).map { it.toModuleDependency() }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// refactor extract to a separate class/interface
|
// refactor extract to a separate class/interface
|
||||||
// TODO think about multi-variant stub modules for non-Kotlin modules which got more than one chosen variant
|
// TODO think about multi-variant stub modules for non-Kotlin modules which got more than one chosen variant
|
||||||
internal fun buildSyntheticModule(resolvedComponentResult: ResolvedComponentResult, singleVariantName: String): ExternalSyntheticKotlinModule {
|
internal fun buildSyntheticModule(resolvedComponentResult: ResolvedComponentResult, singleVariantName: String): ExternalSyntheticKotlinModule {
|
||||||
@@ -174,44 +90,6 @@ internal class ExternalImportedKotlinModule(
|
|||||||
override fun toString(): String = "imported $moduleData"
|
override fun toString(): String = "imported $moduleData"
|
||||||
}
|
}
|
||||||
|
|
||||||
class VariantDependencyDiscovery(
|
|
||||||
val project: Project
|
|
||||||
) : DependencyDiscovery {
|
|
||||||
|
|
||||||
private val kotlinExtension
|
|
||||||
get() = project.kotlinExtension
|
|
||||||
|
|
||||||
private fun resolvedComponentResults(fragment: KotlinModuleFragment): Iterable<ResolvedComponentResult> {
|
|
||||||
val compilation = kotlinExtension.targets.asSequence()
|
|
||||||
.flatMap { it.compilations.asSequence() }
|
|
||||||
.find { it.defaultSourceSetName == fragment.fragmentName }
|
|
||||||
requireNotNull(compilation)
|
|
||||||
|
|
||||||
// TODO distinguish between compile and runtime dependencies?
|
|
||||||
val configuration = project.configurations.getByName(compilation.compileDependencyConfigurationName)
|
|
||||||
return configuration.incoming.resolutionResult.allComponents
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun discoverDependencies(fragment: KotlinModuleFragment): Iterable<KotlinModuleDependency> {
|
|
||||||
require(fragment is KotlinModuleVariant)
|
|
||||||
require(fragment.containingModule.representsProject(project))
|
|
||||||
|
|
||||||
val components = resolvedComponentResults(fragment)
|
|
||||||
return components.flatMap { component ->
|
|
||||||
val classifiers = moduleClassifiersFromCapabilities(component.variants.flatMap { it.capabilities })
|
|
||||||
when (val id = component.id) {
|
|
||||||
is ProjectComponentIdentifier -> {
|
|
||||||
classifiers.map { LocalModuleIdentifier(id.build.name, id.projectPath, it) }
|
|
||||||
}
|
|
||||||
is ModuleComponentIdentifier -> {
|
|
||||||
classifiers.map { id.toSingleModuleIdentifier(it) }
|
|
||||||
}
|
|
||||||
else -> return@flatMap emptyList<KotlinModuleIdentifier>() // TODO check that no other options are possible, throw errors?
|
|
||||||
}
|
|
||||||
}.map(::KotlinModuleDependency)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun ModuleComponentIdentifier.toSingleModuleIdentifier(classifier: String? = null): MavenModuleIdentifier =
|
private fun ModuleComponentIdentifier.toSingleModuleIdentifier(classifier: String? = null): MavenModuleIdentifier =
|
||||||
MavenModuleIdentifier(moduleIdentifier.group, moduleIdentifier.name, classifier)
|
MavenModuleIdentifier(moduleIdentifier.group, moduleIdentifier.name, classifier)
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -17,8 +17,8 @@ import org.jetbrains.kotlin.utils.addToStdlib.flattenTo
|
|||||||
import java.util.ArrayDeque
|
import java.util.ArrayDeque
|
||||||
|
|
||||||
internal class FragmentGranularMetadataResolver(
|
internal class FragmentGranularMetadataResolver(
|
||||||
val requestingFragment: KotlinGradleFragment,
|
private val requestingFragment: KotlinGradleFragment,
|
||||||
val refinesParentResolvers: Lazy<Iterable<FragmentGranularMetadataResolver>>
|
private val refinesParentResolvers: Lazy<Iterable<FragmentGranularMetadataResolver>>
|
||||||
) {
|
) {
|
||||||
val resolutions: Iterable<MetadataDependencyResolution> by lazy {
|
val resolutions: Iterable<MetadataDependencyResolution> by lazy {
|
||||||
doResolveMetadataDependencies()
|
doResolveMetadataDependencies()
|
||||||
|
|||||||
@@ -12,14 +12,6 @@ interface ModuleDependencyResolver {
|
|||||||
fun resolveDependency(requestingModule: KotlinModule, moduleDependency: KotlinModuleDependency): KotlinModule?
|
fun resolveDependency(requestingModule: KotlinModule, moduleDependency: KotlinModuleDependency): KotlinModule?
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO merge with ModuleDependencyResolver?
|
|
||||||
// Semantically, they are close and may use shared caches and other shared state in the implementations
|
|
||||||
interface DependencyDiscovery {
|
|
||||||
// TODO return dependency graph rather than just iterable?
|
|
||||||
// TODO make this a partial function, too
|
|
||||||
fun discoverDependencies(fragment: KotlinModuleFragment): Iterable<KotlinModuleDependency>
|
|
||||||
}
|
|
||||||
|
|
||||||
interface KotlinDependencyGraphResolver {
|
interface KotlinDependencyGraphResolver {
|
||||||
// TODO add explicit dependency consistency scopes if we decide to keep non-production code in the same variant
|
// TODO add explicit dependency consistency scopes if we decide to keep non-production code in the same variant
|
||||||
fun resolveDependencyGraph(requestingModule: KotlinModule): DependencyGraphResolution
|
fun resolveDependencyGraph(requestingModule: KotlinModule): DependencyGraphResolution
|
||||||
|
|||||||
Reference in New Issue
Block a user