Fix runtime elements configuration resolved for compile classpath
The existing disambiguation rule for the Usage attribute lead to
runtime variants being resolved even for compile-scoped input
configurations, because Gradle runs disambiguation rules even if the
consumer value is present in the candidates list.
For example, an `app` project's `jvmCompileClasspath` configuration
would get its `project('lib')` dependency resolved to the
`jvmLibRuntimeElements` instead of `jvmLibApiElements`.
Fix this by:
1) running the part of the disambiguation rule only with Gradle 4.1+, so
as to use the consumer value for proper disambiguation;
2) choosing the JAVA_API usage when the consumer is JAVA_API or
KOTLIN_API, and choosing one of the JAVA_RUNTIME usages if the
consumer is either KOTLIN_RUNTIME, one of the JAVA_RUNTIME usages, or
does not specify its usage.
Issue #KT-27849 Fixed
This commit is contained in:
+24
@@ -241,6 +241,30 @@ class VariantAwareDependenciesIT : BaseGradleIT() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testCompileAndRuntimeResolutionOfElementsConfigurations() =
|
||||||
|
with(Project("sample-app", gradleVersion, "new-mpp-lib-and-app")) {
|
||||||
|
val libProject = Project("sample-lib", gradleVersion, "new-mpp-lib-and-app")
|
||||||
|
embedProject(libProject)
|
||||||
|
gradleBuildScript().modify {
|
||||||
|
it.replace("'com.example:sample-lib:1.0'", "project('${libProject.projectName}')")
|
||||||
|
}
|
||||||
|
|
||||||
|
listOf("jvm6" to "Classpath", "nodeJs" to "Classpath", "wasm32" to "Klibraries").forEach { (target, suffix) ->
|
||||||
|
build("dependencyInsight", "--configuration", "${target}Compile$suffix", "--dependency", "sample-lib") {
|
||||||
|
assertSuccessful()
|
||||||
|
assertContains("variant \"${target}ApiElements\" [")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (suffix == "Classpath") {
|
||||||
|
build("dependencyInsight", "--configuration", "${target}Runtime$suffix", "--dependency", "sample-lib") {
|
||||||
|
assertSuccessful()
|
||||||
|
assertContains("variant \"${target}RuntimeElements\" [")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun Project.embedProject(other: Project) {
|
private fun Project.embedProject(other: Project) {
|
||||||
setupWorkingDir()
|
setupWorkingDir()
|
||||||
other.setupWorkingDir()
|
other.setupWorkingDir()
|
||||||
|
|||||||
+21
-7
@@ -65,19 +65,33 @@ object KotlinUsages {
|
|||||||
override fun execute(details: MultipleCandidatesDetails<Usage?>) = with(details) {
|
override fun execute(details: MultipleCandidatesDetails<Usage?>) = with(details) {
|
||||||
val candidateNames = candidateValues.map { it?.name }.toSet()
|
val candidateNames = candidateValues.map { it?.name }.toSet()
|
||||||
|
|
||||||
|
fun chooseCandidateByName(name: String?): Unit = closestMatch(candidateValues.single { it?.name == name }!!)
|
||||||
|
|
||||||
// if both API and runtime artifacts are chosen according to the compatibility rules, then
|
// if both API and runtime artifacts are chosen according to the compatibility rules, then
|
||||||
// the consumer requested nothing specific, so provide them with the runtime variant, which is more complete:
|
// the consumer requested nothing specific, so provide them with the runtime variant, which is more complete:
|
||||||
if (candidateNames.filterNotNull().toSet() == setOf(KOTLIN_RUNTIME, KOTLIN_API)) {
|
if (candidateNames.filterNotNull().toSet() == setOf(KOTLIN_RUNTIME, KOTLIN_API)) {
|
||||||
details.closestMatch(candidateValues.single { it?.name == KOTLIN_RUNTIME }!!)
|
chooseCandidateByName(KOTLIN_RUNTIME)
|
||||||
}
|
}
|
||||||
if (JAVA_API in candidateNames && JAVA_RUNTIME_JARS in candidateNames && values.none { it in candidateNames }) {
|
|
||||||
details.closestMatch(candidateValues.single { it?.name == JAVA_RUNTIME_JARS }!!)
|
// The consumer value is available and can be used for disambiguation in Gradle 4.1+
|
||||||
}
|
if (isGradleVersionAtLeast(4, 1)) {
|
||||||
if (JAVA_API in candidateNames && JAVA_RUNTIME in candidateNames && values.none { it in candidateNames }) {
|
val javaRuntimeUsages = setOf(JAVA_RUNTIME_JARS, JAVA_RUNTIME)
|
||||||
details.closestMatch(candidateValues.single { it?.name == JAVA_RUNTIME }!!)
|
|
||||||
|
if (JAVA_API in candidateNames &&
|
||||||
|
javaRuntimeUsages.any { it in candidateNames } &&
|
||||||
|
values.none { it in candidateNames }
|
||||||
|
) {
|
||||||
|
when (consumerValue?.name) {
|
||||||
|
KOTLIN_API, JAVA_API ->
|
||||||
|
chooseCandidateByName(JAVA_API)
|
||||||
|
null, KOTLIN_RUNTIME, in javaRuntimeUsages ->
|
||||||
|
chooseCandidateByName(javaRuntimeUsages.first { it in candidateNames })
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JAVA_RUNTIME_CLASSES in candidateNames && JAVA_RUNTIME_RESOURCES in candidateNames && KOTLIN_RUNTIME in candidateNames) {
|
if (JAVA_RUNTIME_CLASSES in candidateNames && JAVA_RUNTIME_RESOURCES in candidateNames && KOTLIN_RUNTIME in candidateNames) {
|
||||||
closestMatch(candidateValues.single { it?.name == KOTLIN_RUNTIME }!!)
|
chooseCandidateByName(KOTLIN_RUNTIME)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user