[MPP] Implement TCS dependency resolver for non-hierarchical deps

Resolves legacy common metadata dependencies and special common
libraries like kotlin-stdlib-common.

KT-54974
This commit is contained in:
Pavel Kirpichenkov
2022-11-23 15:56:38 +02:00
committed by Space Team
parent 339b152390
commit cc93f3a87c
3 changed files with 147 additions and 7 deletions
@@ -27,6 +27,13 @@ fun IdeMultiplatformImport(extension: KotlinMultiplatformExtension): IdeMultipla
level = IdeMultiplatformImport.DependencyResolutionLevel.Default
)
registerDependencyResolver(
resolver = IdeOriginalMetadataDependencyResolver,
constraint = IdeMultiplatformImport.SourceSetConstraint.isMetadata,
phase = IdeMultiplatformImport.DependencyResolutionPhase.BinaryDependencyResolution,
level = IdeMultiplatformImport.DependencyResolutionLevel.Default,
)
registerDependencyResolver(
resolver = IdePlatformBinaryDependencyResolver(),
constraint = IdeMultiplatformImport.SourceSetConstraint.isPlatform,
@@ -5,30 +5,30 @@
package org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinBinaryCoordinates
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver
import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution
import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution.KeepOriginalDependency
import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution.ChooseVisibleSourceSets
import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution.ChooseVisibleSourceSets.MetadataProvider.ArtifactMetadataProvider
import org.jetbrains.kotlin.gradle.plugin.mpp.kotlinTransformedMetadataLibraryDirectoryForIde
import org.jetbrains.kotlin.gradle.plugin.mpp.read
import org.jetbrains.kotlin.gradle.plugin.mpp.resolvableMetadataConfiguration
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope.*
import org.jetbrains.kotlin.gradle.plugin.sources.internal
import org.jetbrains.kotlin.gradle.plugin.sources.project
import org.jetbrains.kotlin.tooling.core.mutableExtrasOf
internal object IdeTransformedMetadataDependencyResolver : IdeDependencyResolver {
override fun resolve(sourceSet: KotlinSourceSet): Set<IdeaKotlinDependency> {
if (sourceSet !is DefaultKotlinSourceSet) return emptySet()
return sourceSet.dependencyTransformations[API_SCOPE]?.metadataDependencyResolutions?.toList().orEmpty()
.plus(sourceSet.dependencyTransformations[IMPLEMENTATION_SCOPE]?.metadataDependencyResolutions?.toList().orEmpty())
.plus(sourceSet.dependencyTransformations[COMPILE_ONLY_SCOPE]?.metadataDependencyResolutions?.toList().orEmpty())
.filterIsInstance<ChooseVisibleSourceSets>()
override fun resolve(sourceSet: KotlinSourceSet): Set<IdeaKotlinDependency> =
collectMetadataDependencyResolutions<ChooseVisibleSourceSets>(sourceSet)
.flatMap { resolution -> resolve(sourceSet, resolution) }
.toSet()
}
private fun resolve(sourceSet: KotlinSourceSet, resolution: ChooseVisibleSourceSets): Iterable<IdeaKotlinDependency> {
val metadataProvider = resolution.metadataProvider as? ArtifactMetadataProvider ?: return emptySet()
@@ -62,3 +62,48 @@ internal object IdeTransformedMetadataDependencyResolver : IdeDependencyResolver
}
}
}
object IdeOriginalMetadataDependencyResolver : IdeDependencyResolver {
override fun resolve(sourceSet: KotlinSourceSet): Set<IdeaKotlinDependency> {
val metadataDependenciesConfiguration = resolvableMetadataConfiguration(
sourceSet.project,
listOf(sourceSet),
metadataDependencyScopes,
)
val keptOriginalDependencyResolutionIds = collectMetadataDependencyResolutions<KeepOriginalDependency>(sourceSet)
.map { it.dependency.id }.toSet()
val artifactsView = metadataDependenciesConfiguration.incoming.artifactView { view ->
view.componentFilter { id -> id in keptOriginalDependencyResolutionIds }
view.isLenient = true
}
return artifactsView.artifacts.map { artifact ->
val artifactId = artifact.variant.owner as ModuleComponentIdentifier
IdeaKotlinResolvedBinaryDependency(
binaryType = IdeaKotlinDependency.CLASSPATH_BINARY_TYPE,
binaryFile = artifact.file,
extras = mutableExtrasOf(),
coordinates = IdeaKotlinBinaryCoordinates(
group = artifactId.group,
module = artifactId.module,
version = artifactId.version,
)
)
}.toSet()
}
}
private inline fun <reified T : MetadataDependencyResolution> collectMetadataDependencyResolutions(sourceSet: KotlinSourceSet): List<T> {
if (sourceSet !is DefaultKotlinSourceSet) return emptyList()
return metadataDependencyScopes.flatMap { scope ->
sourceSet.dependencyTransformations[scope]?.metadataDependencyResolutions?.toList().orEmpty()
}.filterIsInstance<T>()
}
private val metadataDependencyScopes = listOf(
API_SCOPE,
IMPLEMENTATION_SCOPE,
COMPILE_ONLY_SCOPE,
)
@@ -0,0 +1,88 @@
/*
* Copyright 2010-2022 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.
*/
@file:Suppress("FunctionName")
package org.jetbrains.kotlin.gradle.ide
import org.jetbrains.kotlin.gradle.applyMultiplatformPlugin
import org.jetbrains.kotlin.gradle.buildProject
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.enableDefaultStdlibDependency
import org.jetbrains.kotlin.gradle.enableDependencyVerification
import org.jetbrains.kotlin.gradle.idea.testFixtures.tcs.assertMatches
import org.jetbrains.kotlin.gradle.idea.testFixtures.tcs.binaryCoordinates
import org.jetbrains.kotlin.gradle.kpm.idea.mavenCentralCacheRedirector
import org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers.IdeOriginalMetadataDependencyResolver
import org.junit.Test
class IdeOriginalMetadataDependencyResolverTest {
@Test
fun `test kotlin-stdlib-common`() {
val project = buildProject {
enableDependencyVerification(false)
enableDefaultStdlibDependency(true)
applyMultiplatformPlugin()
repositories.mavenLocal()
repositories.mavenCentralCacheRedirector()
}
val kotlin = project.multiplatformExtension
kotlin.jvm()
kotlin.linuxX64()
kotlin.linuxArm64()
kotlin.targetHierarchy.default()
project.evaluate()
val stdlibCommonSourceSets = listOf("commonMain", "commonTest").map(kotlin.sourceSets::getByName)
for (sourceSet in stdlibCommonSourceSets) {
IdeOriginalMetadataDependencyResolver.resolve(sourceSet).assertMatches(
binaryCoordinates("org.jetbrains.kotlin:kotlin-stdlib-common:${kotlin.coreLibrariesVersion}")
)
}
}
@Test
fun `test legacy metadata dependency`() {
val project = buildProject {
enableDependencyVerification(false)
enableDefaultStdlibDependency(false)
applyMultiplatformPlugin()
repositories.mavenLocal()
repositories.mavenCentralCacheRedirector()
}
val kotlin = project.multiplatformExtension
kotlin.jvm()
kotlin.linuxX64()
kotlin.targetHierarchy.default()
val commonMain = kotlin.sourceSets.getByName("commonMain")
commonMain.dependencies {
implementation("io.ktor:ktor-client-core:1.0.1")
}
project.evaluate()
IdeOriginalMetadataDependencyResolver.resolve(commonMain).assertMatches(
binaryCoordinates("io.ktor:ktor-client-core:1.0.1"),
binaryCoordinates("io.ktor:ktor-http:1.0.1"),
binaryCoordinates("io.ktor:ktor-utils:1.0.1"),
binaryCoordinates("org.jetbrains.kotlinx:kotlinx-coroutines-io:0.1.1"),
binaryCoordinates("org.jetbrains.kotlinx:kotlinx-io:0.1.1"),
binaryCoordinates("org.jetbrains.kotlinx:atomicfu-common:0.11.12"),
binaryCoordinates("org.jetbrains.kotlinx:kotlinx-coroutines-core-common:1.0.1"),
binaryCoordinates("org.jetbrains.kotlin:kotlin-stdlib-common:1.3.10"),
)
}
}