[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 org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinDependency
|
||||||
import kotlin.test.fail
|
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 thisList = toList()
|
||||||
val matchers = notation.flatMap { buildIdeaKotlinDependencyMatchers(it) }
|
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.IdeaKotlinDependencyMatcher
|
||||||
import org.jetbrains.kotlin.gradle.idea.testFixtures.tcs.assertMatches
|
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.binaryCoordinates
|
||||||
|
import org.jetbrains.kotlin.gradle.idea.testFixtures.tcs.getOrFail
|
||||||
import org.jetbrains.kotlin.gradle.testbase.*
|
import org.jetbrains.kotlin.gradle.testbase.*
|
||||||
import org.jetbrains.kotlin.gradle.util.kotlinNativeDistributionDependencies
|
import org.jetbrains.kotlin.gradle.util.*
|
||||||
import org.jetbrains.kotlin.gradle.util.replaceText
|
|
||||||
import org.jetbrains.kotlin.gradle.util.resolveIdeDependencies
|
|
||||||
import org.jetbrains.kotlin.konan.target.HostManager
|
import org.jetbrains.kotlin.konan.target.HostManager
|
||||||
import org.jetbrains.kotlin.konan.target.KonanTarget.*
|
import org.jetbrains.kotlin.konan.target.KonanTarget.*
|
||||||
import org.junit.AssumptionViolatedException
|
import org.junit.AssumptionViolatedException
|
||||||
import org.junit.jupiter.api.DisplayName
|
import org.junit.jupiter.api.DisplayName
|
||||||
import org.junit.jupiter.api.io.TempDir
|
import org.junit.jupiter.api.io.TempDir
|
||||||
|
import java.io.File
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
import java.util.*
|
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() =
|
private fun Iterable<IdeaKotlinDependency>.cinteropDependencies() =
|
||||||
this.filterIsInstance<IdeaKotlinBinaryDependency>().filter {
|
this.filterIsInstance<IdeaKotlinBinaryDependency>().filter {
|
||||||
it.klibExtra?.isInterop == true && !it.isNativeStdlib && !it.isNativeDistribution
|
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.jvm.JvmLibrary
|
||||||
import org.gradle.language.base.artifact.SourcesArtifact
|
import org.gradle.language.base.artifact.SourcesArtifact
|
||||||
import org.gradle.language.java.artifact.JavadocArtifact
|
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.IdeaKotlinDependency
|
||||||
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency
|
import org.jetbrains.kotlin.gradle.idea.tcs.IdeaKotlinResolvedBinaryDependency
|
||||||
import org.jetbrains.kotlin.gradle.idea.tcs.extras.documentationClasspath
|
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.KotlinPlatformType
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||||
import org.jetbrains.kotlin.gradle.plugin.ide.IdeAdditionalArtifactResolver
|
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.internal
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.resolvableMetadataConfiguration
|
import org.jetbrains.kotlin.gradle.plugin.mpp.resolvableMetadataConfiguration
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.internal
|
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
|
* cc Anton Lakotka, Sebastian Sellmair
|
||||||
*/
|
*/
|
||||||
internal object IdeArtifactResolutionQuerySourcesAndDocumentationResolver : IdeAdditionalArtifactResolver {
|
internal object IdeArtifactResolutionQuerySourcesAndDocumentationResolver : IdeAdditionalArtifactResolver {
|
||||||
|
|
||||||
override fun resolve(sourceSet: KotlinSourceSet, dependencies: Set<IdeaKotlinDependency>) {
|
override fun resolve(sourceSet: KotlinSourceSet, dependencies: Set<IdeaKotlinDependency>) {
|
||||||
val binaryDependencies = dependencies.filterIsInstance<IdeaKotlinResolvedBinaryDependency>()
|
val binaryDependencies = dependencies.filterIsInstance<IdeaKotlinResolvedBinaryDependency>()
|
||||||
.filter { dependency -> dependency.isKotlinCompileBinaryType }
|
.filter { dependency -> dependency.isKotlinCompileBinaryType }
|
||||||
.groupBy { dependency -> dependency.coordinates?.copy(sourceSetName = null) }
|
.groupBy { dependency -> Coordinates(dependency.coordinates ?: return@groupBy null) }
|
||||||
|
|
||||||
val project = sourceSet.project
|
val project = sourceSet.project
|
||||||
val configuration = selectConfiguration(sourceSet)
|
val configuration = selectConfiguration(sourceSet)
|
||||||
@@ -50,9 +51,7 @@ internal object IdeArtifactResolutionQuerySourcesAndDocumentationResolver : IdeA
|
|||||||
}
|
}
|
||||||
|
|
||||||
sourcesArtifacts.forEach { artifact ->
|
sourcesArtifacts.forEach { artifact ->
|
||||||
val artifactId = artifact.id.componentIdentifier as? ModuleComponentIdentifier ?: return@forEach
|
binaryDependencies[Coordinates(artifact)]?.forEach { dependency ->
|
||||||
val artifactCoordinates = IdeaKotlinBinaryCoordinates(artifactId)
|
|
||||||
binaryDependencies[artifactCoordinates]?.forEach { dependency ->
|
|
||||||
dependency.sourcesClasspath.add(artifact.file)
|
dependency.sourcesClasspath.add(artifact.file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,9 +61,7 @@ internal object IdeArtifactResolutionQuerySourcesAndDocumentationResolver : IdeA
|
|||||||
}
|
}
|
||||||
|
|
||||||
javadocArtifacts.forEach { artifact ->
|
javadocArtifacts.forEach { artifact ->
|
||||||
val artifactId = artifact.id.componentIdentifier as? ModuleComponentIdentifier ?: return@forEach
|
binaryDependencies[Coordinates(artifact)]?.forEach { dependency ->
|
||||||
val artifactCoordinates = IdeaKotlinBinaryCoordinates(artifactId)
|
|
||||||
binaryDependencies[artifactCoordinates]?.forEach { dependency ->
|
|
||||||
dependency.documentationClasspath.add(artifact.file)
|
dependency.documentationClasspath.add(artifact.file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,4 +72,26 @@ internal object IdeArtifactResolutionQuerySourcesAndDocumentationResolver : IdeA
|
|||||||
return platformCompilation?.internal?.configurations?.compileDependencyConfiguration
|
return platformCompilation?.internal?.configurations?.compileDependencyConfiguration
|
||||||
?: sourceSet.internal.resolvableMetadataConfiguration
|
?: 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.ExternalKotlinTargetApi
|
||||||
import org.jetbrains.kotlin.gradle.idea.tcs.*
|
import org.jetbrains.kotlin.gradle.idea.tcs.*
|
||||||
import org.jetbrains.kotlin.gradle.idea.tcs.extras.artifactsClasspath
|
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.KotlinCompilation
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||||
import org.jetbrains.kotlin.gradle.plugin.ide.IdeDependencyResolver
|
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.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.IdeaKotlinBinaryCoordinates
|
||||||
import org.jetbrains.kotlin.gradle.plugin.ide.IdeaKotlinProjectCoordinates
|
import org.jetbrains.kotlin.gradle.plugin.ide.IdeaKotlinProjectCoordinates
|
||||||
import org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers.IdeBinaryDependencyResolver.ArtifactResolutionStrategy
|
import org.jetbrains.kotlin.gradle.plugin.ide.dependencyResolvers.IdeBinaryDependencyResolver.ArtifactResolutionStrategy
|
||||||
@@ -124,6 +126,7 @@ class IdeBinaryDependencyResolver @JvmOverloads constructor(
|
|||||||
val unresolvedDependencies = artifacts.failures
|
val unresolvedDependencies = artifacts.failures
|
||||||
.onEach { reason -> sourceSet.project.logger.info("Failed to resolve platform dependency on ${sourceSet.name}", reason) }
|
.onEach { reason -> sourceSet.project.logger.info("Failed to resolve platform dependency on ${sourceSet.name}", reason) }
|
||||||
.map { reason ->
|
.map { reason ->
|
||||||
|
|
||||||
val selector = (reason as? ModuleVersionResolveException)?.selector as? ModuleComponentSelector
|
val selector = (reason as? ModuleVersionResolveException)?.selector as? ModuleComponentSelector
|
||||||
/* Can't figure out the dependency here :( */
|
/* Can't figure out the dependency here :( */
|
||||||
?: return@map IdeaKotlinUnresolvedBinaryDependency(
|
?: return@map IdeaKotlinUnresolvedBinaryDependency(
|
||||||
@@ -141,7 +144,8 @@ class IdeBinaryDependencyResolver @JvmOverloads constructor(
|
|||||||
when (val componentId = artifact.id.componentIdentifier) {
|
when (val componentId = artifact.id.componentIdentifier) {
|
||||||
is ProjectComponentIdentifier -> {
|
is ProjectComponentIdentifier -> {
|
||||||
IdeaKotlinProjectArtifactDependency(
|
IdeaKotlinProjectArtifactDependency(
|
||||||
type = IdeaKotlinSourceDependency.Type.Regular, coordinates = IdeaKotlinProjectCoordinates(componentId)
|
type = IdeaKotlinSourceDependency.Type.Regular,
|
||||||
|
coordinates = IdeaKotlinProjectCoordinates(componentId)
|
||||||
).apply {
|
).apply {
|
||||||
artifactsClasspath.add(artifact.file)
|
artifactsClasspath.add(artifact.file)
|
||||||
}
|
}
|
||||||
@@ -149,7 +153,7 @@ class IdeBinaryDependencyResolver @JvmOverloads constructor(
|
|||||||
|
|
||||||
is ModuleComponentIdentifier -> {
|
is ModuleComponentIdentifier -> {
|
||||||
IdeaKotlinResolvedBinaryDependency(
|
IdeaKotlinResolvedBinaryDependency(
|
||||||
coordinates = IdeaKotlinBinaryCoordinates(componentId),
|
coordinates = IdeaKotlinBinaryCoordinates(componentId, artifact.variant.capabilities),
|
||||||
binaryType = binaryType,
|
binaryType = binaryType,
|
||||||
classpath = IdeaKotlinClasspath(artifact.file),
|
classpath = IdeaKotlinClasspath(artifact.file),
|
||||||
)
|
)
|
||||||
@@ -161,7 +165,8 @@ class IdeBinaryDependencyResolver @JvmOverloads constructor(
|
|||||||
group = componentId.projectPath + "(${componentId.variant})",
|
group = componentId.projectPath + "(${componentId.variant})",
|
||||||
module = componentId.libraryName,
|
module = componentId.libraryName,
|
||||||
version = null,
|
version = null,
|
||||||
sourceSetName = null
|
sourceSetName = null,
|
||||||
|
capabilities = artifact.variant.capabilities.map(::IdeaKotlinBinaryCapability).toSet()
|
||||||
), classpath = IdeaKotlinClasspath(artifact.file)
|
), classpath = IdeaKotlinClasspath(artifact.file)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -53,4 +53,4 @@ internal object IdeTransformedMetadataDependencyResolver : IdeDependencyResolver
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user