[Gradle] Ide Dependency Resolution: Provide capabilities for binary coordinates
^KT-60053 Verification Pending
This commit is contained in:
committed by
Space Team
parent
7af254fbf2
commit
041b424bab
+8
-1
@@ -8,7 +8,7 @@ package org.jetbrains.kotlin.gradle.idea.testFixtures.tcs
|
||||
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency
|
||||
import kotlin.test.fail
|
||||
|
||||
fun Iterable<IdeaKotlinDependency>.assertMatches(vararg notation: Any?): Iterable<IdeaKotlinDependency> {
|
||||
fun <T : IdeaKotlinDependency> Iterable<T>.assertMatches(vararg notation: Any?): Iterable<T> {
|
||||
val thisList = toList()
|
||||
val matchers = notation.flatMap { buildIdeaKotlinDependencyMatchers(it) }
|
||||
|
||||
@@ -51,3 +51,10 @@ fun Iterable<IdeaKotlinDependency>.assertMatches(vararg notation: Any?): Iterabl
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fun <T : IdeaKotlinDependency> Iterable<T>.getOrFail(matcher: IdeaKotlinDependencyMatcher): T {
|
||||
val candidates = filter { matcher.matches(it) }
|
||||
if (candidates.isEmpty()) fail("No dependency matching '$matcher' found")
|
||||
if (candidates.size > 1) fail("Multiple dependencies matching '$matcher' found: ${candidates.map { it.coordinates }}")
|
||||
return candidates.single()
|
||||
}
|
||||
|
||||
+41
-3
@@ -16,15 +16,15 @@ import org.jetbrains.kotlin.gradle.idea.tcs.extras.*
|
||||
import org.jetbrains.kotlin.gradle.idea.testFixtures.tcs.IdeaKotlinDependencyMatcher
|
||||
import org.jetbrains.kotlin.gradle.idea.testFixtures.tcs.assertMatches
|
||||
import org.jetbrains.kotlin.gradle.idea.testFixtures.tcs.binaryCoordinates
|
||||
import org.jetbrains.kotlin.gradle.idea.testFixtures.tcs.getOrFail
|
||||
import org.jetbrains.kotlin.gradle.testbase.*
|
||||
import org.jetbrains.kotlin.gradle.util.kotlinNativeDistributionDependencies
|
||||
import org.jetbrains.kotlin.gradle.util.replaceText
|
||||
import org.jetbrains.kotlin.gradle.util.resolveIdeDependencies
|
||||
import org.jetbrains.kotlin.gradle.util.*
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget.*
|
||||
import org.junit.AssumptionViolatedException
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
import java.io.File
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.file.Path
|
||||
import java.util.*
|
||||
@@ -277,8 +277,46 @@ class MppIdeDependencyResolutionIT : KGPBaseTest() {
|
||||
}
|
||||
}
|
||||
|
||||
@GradleTestVersions(minVersion = TestVersions.Gradle.G_7_6)
|
||||
@GradleTest
|
||||
fun `test dependency on java testFixtures and feature source sets`(gradleVersion: GradleVersion) {
|
||||
project("kt-60053-dependencyOn-testFixtures", gradleVersion) {
|
||||
build("publish")
|
||||
|
||||
resolveIdeDependencies(":consumer") { dependencies ->
|
||||
val jvmMainDependencies = dependencies["jvmMain"].filterIsInstance<IdeaKotlinBinaryDependency>().assertMatches(
|
||||
kotlinStdlibDependencies,
|
||||
jetbrainsAnnotationDependencies,
|
||||
binaryCoordinates("org.jetbrains.sample:producer:1.0.0"),
|
||||
binaryCoordinates("org.jetbrains.sample:producer-foo:1.0.0"),
|
||||
)
|
||||
|
||||
val jvmTestDependencies = dependencies["jvmTest"].filterIsInstance<IdeaKotlinBinaryDependency>().assertMatches(
|
||||
kotlinStdlibDependencies,
|
||||
jetbrainsAnnotationDependencies,
|
||||
binaryCoordinates("org.jetbrains.sample:producer:1.0.0"),
|
||||
binaryCoordinates("org.jetbrains.sample:producer-foo:1.0.0"),
|
||||
binaryCoordinates("org.jetbrains.sample:producer-test-fixtures:1.0.0"),
|
||||
)
|
||||
|
||||
jvmMainDependencies.getOrFail(binaryCoordinates("org.jetbrains.sample:producer:1.0.0")).assertSingleSourcesJar()
|
||||
jvmTestDependencies.getOrFail(binaryCoordinates("org.jetbrains.sample:producer:1.0.0")).assertSingleSourcesJar()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Iterable<IdeaKotlinDependency>.cinteropDependencies() =
|
||||
this.filterIsInstance<IdeaKotlinBinaryDependency>().filter {
|
||||
it.klibExtra?.isInterop == true && !it.isNativeStdlib && !it.isNativeDistribution
|
||||
}
|
||||
|
||||
private fun IdeaKotlinBinaryDependency.assertSingleSourcesJar(): File {
|
||||
val sources = sourcesClasspath.toList()
|
||||
if (sources.isEmpty()) fail("Missing -sources.jar")
|
||||
if (sources.size > 1) fail("Multiple -sources.jar: $sources")
|
||||
|
||||
return sources.single().also { sourcesFile ->
|
||||
if (!sourcesFile.name.endsWith("-sources.jar")) fail("-sources.jar suffix expected. Found: ${sourcesFile.name}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven(rootDir.resolve("repo"))
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm()
|
||||
|
||||
sourceSets.jvmMain.dependencies {
|
||||
implementation("org.jetbrains.sample:producer:1.0.0")
|
||||
implementation("org.jetbrains.sample:producer:1.0.0") {
|
||||
capabilities {
|
||||
requireCapability("org.jetbrains.sample:producer-foo")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets.jvmTest.dependencies {
|
||||
implementation(project.dependencies.testFixtures("org.jetbrains.sample:producer:1.0.0"))
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
plugins {
|
||||
`java-library`
|
||||
`java-test-fixtures`
|
||||
`maven-publish`
|
||||
}
|
||||
|
||||
group = "org.jetbrains.sample"
|
||||
version = "1.0.0"
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
create("myLibrary", MavenPublication::class.java) {
|
||||
from(components["java"])
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven(rootDir.resolve("repo"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
java {
|
||||
withSourcesJar()
|
||||
registerFeature("foo") {
|
||||
usingSourceSet(sourceSets.create("foo"))
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
public class Foo {
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
public class Main {
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
public class TestFixtures {
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
|
||||
include(":producer")
|
||||
include(":consumer")
|
||||
+27
-8
@@ -11,6 +11,7 @@ import org.gradle.api.artifacts.result.ResolvedArtifactResult
|
||||
import org.gradle.jvm.JvmLibrary
|
||||
import org.gradle.language.base.artifact.SourcesArtifact
|
||||
import org.gradle.language.java.artifact.JavadocArtifact
|
||||
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.idea.tcs.extras.documentationClasspath
|
||||
@@ -19,7 +20,6 @@ import org.jetbrains.kotlin.gradle.idea.tcs.isKotlinCompileBinaryType
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.ide.IdeAdditionalArtifactResolver
|
||||
import org.jetbrains.kotlin.gradle.plugin.ide.IdeaKotlinBinaryCoordinates
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.internal
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.resolvableMetadataConfiguration
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.internal
|
||||
@@ -33,10 +33,11 @@ import org.jetbrains.kotlin.gradle.plugin.sources.internal
|
||||
* cc Anton Lakotka, Sebastian Sellmair
|
||||
*/
|
||||
internal object IdeArtifactResolutionQuerySourcesAndDocumentationResolver : IdeAdditionalArtifactResolver {
|
||||
|
||||
override fun resolve(sourceSet: KotlinSourceSet, dependencies: Set<IdeaKotlinDependency>) {
|
||||
val binaryDependencies = dependencies.filterIsInstance<IdeaKotlinResolvedBinaryDependency>()
|
||||
.filter { dependency -> dependency.isKotlinCompileBinaryType }
|
||||
.groupBy { dependency -> dependency.coordinates?.copy(sourceSetName = null) }
|
||||
.groupBy { dependency -> Coordinates(dependency.coordinates ?: return@groupBy null) }
|
||||
|
||||
val project = sourceSet.project
|
||||
val configuration = selectConfiguration(sourceSet)
|
||||
@@ -50,9 +51,7 @@ internal object IdeArtifactResolutionQuerySourcesAndDocumentationResolver : IdeA
|
||||
}
|
||||
|
||||
sourcesArtifacts.forEach { artifact ->
|
||||
val artifactId = artifact.id.componentIdentifier as? ModuleComponentIdentifier ?: return@forEach
|
||||
val artifactCoordinates = IdeaKotlinBinaryCoordinates(artifactId)
|
||||
binaryDependencies[artifactCoordinates]?.forEach { dependency ->
|
||||
binaryDependencies[Coordinates(artifact)]?.forEach { dependency ->
|
||||
dependency.sourcesClasspath.add(artifact.file)
|
||||
}
|
||||
}
|
||||
@@ -62,9 +61,7 @@ internal object IdeArtifactResolutionQuerySourcesAndDocumentationResolver : IdeA
|
||||
}
|
||||
|
||||
javadocArtifacts.forEach { artifact ->
|
||||
val artifactId = artifact.id.componentIdentifier as? ModuleComponentIdentifier ?: return@forEach
|
||||
val artifactCoordinates = IdeaKotlinBinaryCoordinates(artifactId)
|
||||
binaryDependencies[artifactCoordinates]?.forEach { dependency ->
|
||||
binaryDependencies[Coordinates(artifact)]?.forEach { dependency ->
|
||||
dependency.documentationClasspath.add(artifact.file)
|
||||
}
|
||||
}
|
||||
@@ -75,4 +72,26 @@ internal object IdeArtifactResolutionQuerySourcesAndDocumentationResolver : IdeA
|
||||
return platformCompilation?.internal?.configurations?.compileDependencyConfiguration
|
||||
?: sourceSet.internal.resolvableMetadataConfiguration
|
||||
}
|
||||
|
||||
/**
|
||||
* Specific 'Coordinates' type used to match previously resolved dependencies with their
|
||||
* sources and javadoc artifact counterparts
|
||||
*/
|
||||
private data class Coordinates(private val coordinates: String)
|
||||
|
||||
private fun Coordinates(coordinates: IdeaKotlinBinaryCoordinates): Coordinates? = when {
|
||||
coordinates.capabilities.isEmpty() -> Coordinates("${coordinates.group}:${coordinates.module}:${coordinates.version}")
|
||||
coordinates.capabilities.size == 1 -> coordinates.capabilities.single().run { Coordinates("$group:$name:$version") }
|
||||
|
||||
/*
|
||||
We do have a dependency that declares multiple capabilities. In this case we cannot use this resolver
|
||||
to find the sources as we can only specify the componentId and not the explicit artifact
|
||||
*/
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun Coordinates(artifact: ResolvedArtifactResult): Coordinates? {
|
||||
val id = artifact.id.componentIdentifier as? ModuleComponentIdentifier ?: return null
|
||||
return Coordinates("${id.group}:${id.module}:${id.version}")
|
||||
}
|
||||
}
|
||||
|
||||
+8
-3
@@ -15,11 +15,13 @@ import org.gradle.internal.resolve.ModuleVersionResolveException
|
||||
import org.jetbrains.kotlin.gradle.ExternalKotlinTargetApi
|
||||
import org.jetbrains.kotlin.gradle.idea.tcs.*
|
||||
import org.jetbrains.kotlin.gradle.idea.tcs.extras.artifactsClasspath
|
||||
import org.jetbrains.kotlin.gradle.idea.tcs.extras.isIdeaProjectLevel
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver
|
||||
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver.Companion.gradleArtifact
|
||||
import org.jetbrains.kotlin.gradle.plugin.ide.IdeaKotlinBinaryCapability
|
||||
import org.jetbrains.kotlin.gradle.plugin.ide.IdeaKotlinBinaryCoordinates
|
||||
import org.jetbrains.kotlin.gradle.plugin.ide.IdeaKotlinProjectCoordinates
|
||||
import org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers.IdeBinaryDependencyResolver.ArtifactResolutionStrategy
|
||||
@@ -124,6 +126,7 @@ class IdeBinaryDependencyResolver @JvmOverloads constructor(
|
||||
val unresolvedDependencies = artifacts.failures
|
||||
.onEach { reason -> sourceSet.project.logger.info("Failed to resolve platform dependency on ${sourceSet.name}", reason) }
|
||||
.map { reason ->
|
||||
|
||||
val selector = (reason as? ModuleVersionResolveException)?.selector as? ModuleComponentSelector
|
||||
/* Can't figure out the dependency here :( */
|
||||
?: return@map IdeaKotlinUnresolvedBinaryDependency(
|
||||
@@ -141,7 +144,8 @@ class IdeBinaryDependencyResolver @JvmOverloads constructor(
|
||||
when (val componentId = artifact.id.componentIdentifier) {
|
||||
is ProjectComponentIdentifier -> {
|
||||
IdeaKotlinProjectArtifactDependency(
|
||||
type = IdeaKotlinSourceDependency.Type.Regular, coordinates = IdeaKotlinProjectCoordinates(componentId)
|
||||
type = IdeaKotlinSourceDependency.Type.Regular,
|
||||
coordinates = IdeaKotlinProjectCoordinates(componentId)
|
||||
).apply {
|
||||
artifactsClasspath.add(artifact.file)
|
||||
}
|
||||
@@ -149,7 +153,7 @@ class IdeBinaryDependencyResolver @JvmOverloads constructor(
|
||||
|
||||
is ModuleComponentIdentifier -> {
|
||||
IdeaKotlinResolvedBinaryDependency(
|
||||
coordinates = IdeaKotlinBinaryCoordinates(componentId),
|
||||
coordinates = IdeaKotlinBinaryCoordinates(componentId, artifact.variant.capabilities),
|
||||
binaryType = binaryType,
|
||||
classpath = IdeaKotlinClasspath(artifact.file),
|
||||
)
|
||||
@@ -161,7 +165,8 @@ class IdeBinaryDependencyResolver @JvmOverloads constructor(
|
||||
group = componentId.projectPath + "(${componentId.variant})",
|
||||
module = componentId.libraryName,
|
||||
version = null,
|
||||
sourceSetName = null
|
||||
sourceSetName = null,
|
||||
capabilities = artifact.variant.capabilities.map(::IdeaKotlinBinaryCapability).toSet()
|
||||
), classpath = IdeaKotlinClasspath(artifact.file)
|
||||
)
|
||||
}
|
||||
|
||||
+1
-1
@@ -53,4 +53,4 @@ internal object IdeTransformedMetadataDependencyResolver : IdeDependencyResolver
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user