From cc93f3a87cf3edcb7699b6d94283218305b26bca Mon Sep 17 00:00:00 2001 From: Pavel Kirpichenkov Date: Wed, 23 Nov 2022 15:56:38 +0200 Subject: [PATCH] [MPP] Implement TCS dependency resolver for non-hierarchical deps Resolves legacy common metadata dependencies and special common libraries like kotlin-stdlib-common. KT-54974 --- .../ide/IdeMultiplatformImportFactory.kt | 7 ++ ...r.kt => IdeMetadataDependencyResolvers.kt} | 59 +++++++++++-- ...eOriginalMetadataDependencyResolverTest.kt | 88 +++++++++++++++++++ 3 files changed, 147 insertions(+), 7 deletions(-) rename libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/{IdeTransformedMetadataDependencyResolver.kt => IdeMetadataDependencyResolvers.kt} (58%) create mode 100644 libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/ide/IdeOriginalMetadataDependencyResolverTest.kt diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImportFactory.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImportFactory.kt index ebb3fd6e3dc..d1595e9e6dd 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImportFactory.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImportFactory.kt @@ -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, diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeTransformedMetadataDependencyResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeMetadataDependencyResolvers.kt similarity index 58% rename from libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeTransformedMetadataDependencyResolver.kt rename to libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeMetadataDependencyResolvers.kt index a51fd3f25a8..1d4f6f5ae7d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeTransformedMetadataDependencyResolver.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/dependencyResolvers/IdeMetadataDependencyResolvers.kt @@ -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 { - 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() + override fun resolve(sourceSet: KotlinSourceSet): Set = + collectMetadataDependencyResolutions(sourceSet) .flatMap { resolution -> resolve(sourceSet, resolution) } .toSet() - } private fun resolve(sourceSet: KotlinSourceSet, resolution: ChooseVisibleSourceSets): Iterable { 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 { + val metadataDependenciesConfiguration = resolvableMetadataConfiguration( + sourceSet.project, + listOf(sourceSet), + metadataDependencyScopes, + ) + + val keptOriginalDependencyResolutionIds = collectMetadataDependencyResolutions(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 collectMetadataDependencyResolutions(sourceSet: KotlinSourceSet): List { + if (sourceSet !is DefaultKotlinSourceSet) return emptyList() + return metadataDependencyScopes.flatMap { scope -> + sourceSet.dependencyTransformations[scope]?.metadataDependencyResolutions?.toList().orEmpty() + }.filterIsInstance() +} + +private val metadataDependencyScopes = listOf( + API_SCOPE, + IMPLEMENTATION_SCOPE, + COMPILE_ONLY_SCOPE, +) diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/ide/IdeOriginalMetadataDependencyResolverTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/ide/IdeOriginalMetadataDependencyResolverTest.kt new file mode 100644 index 00000000000..8ec68bac34f --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/ide/IdeOriginalMetadataDependencyResolverTest.kt @@ -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"), + ) + } +}