Slackbot
08/20/2022, 5:23 PMVampire
08/21/2022, 12:14 AM:sub:outgoingVariants
, you see that there is a runtimeElements
primary variant with two sub-variants classes
and resources
for things that don't need a jar, but just the compiled classes and / or resource files.
First it tries to find a matching variant.
The primary runtimeElements
variant does not match because of the transformed
attribute being set to false
.
The secondary variants do not have that problem because their artifactType
is not jar
so you didn't set it.
But now it has two equally matching variants, classes
and resources
, where all requested attributes are not present (transformed
) and all present attributes are not requested (the standard JVM ecosystem properties as documented).
At this point in time the resolution fails as Gradle is unsure which variant to pick, as both would equally well fulfill the requirements without the need of doing any transforms and fails.
If you add the JVM ecosystem attributes - or at least attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements, LibraryElements.JAR))
to resolve the ambiguity between the three of them - the secondary variants are ruled out as the attribute does not match, but the primary variant can - with the help fo the artifact transform - made matching the requested attributes and thus this one will be picked.Barteks2x
08/21/2022, 1:33 PMBarteks2x
08/21/2022, 1:39 PMBarteks2x
08/21/2022, 1:43 PMBarteks2x
08/21/2022, 1:44 PMVampire
08/21/2022, 1:53 PMVampire
08/21/2022, 1:55 PMBarteks2x
08/21/2022, 1:59 PMMutation of attributes is not allowed
Barteks2x
08/21/2022, 2:00 PMdependencies {
newTestConf(project(":sub")) {
attributes.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements, LibraryElements.JAR))
}
}
Barteks2x
08/21/2022, 2:01 PMWith the transformed attribute, the primary would match with one transformation, the two secondaries would match without transformation. So shorter transformation chain (0) wins over longer chain (1), and now you are left with two variants that are equally eligible.So when there are unmatched attributes, gradle completely ignores the primary vs secondary variants and considers them all equally?
Barteks2x
08/21/2022, 2:05 PMBarteks2x
08/21/2022, 2:09 PMWith the transformed attribute, the primary would match with one transformation, the two secondaries would match without transformation.What why?
Barteks2x
08/21/2022, 2:10 PMVampire
08/21/2022, 4:12 PMI tried to set it in the dependency directly and gettingNot fully sure right now why, but if you instead write it likeMutation of attributes is not allowed
attributes {
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements, LibraryElements.JAR))
}
it works fine.
So when there are unmatched attributes, gradle completely ignores the primary vs secondary variants and considers them all equally?I'd tend to say "no", but I'm not sure what you try to say. It is not ignored, but simply ruled out before it is checked. Gradle tries to find a variant using attribute matching. During this attribute matching, shorter transformer chain wins over longer transformer chain. If in the result there is primary and secondary, primary wins.
> With the transformed attribute, the primary would match with one transformation, the two secondaries would match without transformation.
What why?
Wouldn't all of them require one transformation? Or am I missing something?No, with
dependencies {
artifactTypes.getByName("jar") {
attributes.attribute(transformedAttribute, false)
}
}
You set transformed
to false
for all variants with artifact type jar
.
Those secondary variants have other artifact types, you can see that when looking at :sub:outgoingVariants
.
So those secondary variants do not provide the transformed attribute.
If you would set the attribute to false
for those too, they would actually never be used, if transformed
`true`is requested,
because you would have no transformation that can transform the attribute.
You could also register an attribute compatibility rule that says absent attribute is not considered as compatible if true
is requested like
class Foo implements AttributeCompatibilityRule<Boolean> {
void execute(CompatibilityCheckDetails<Boolean> details) {
if ((details.consumerValue == true) && (details.producerValue == null)) {
details.incompatible()
}
}
}
dependencies {
attributesSchema {
attribute(transformedAttribute) {
compatibilityRules.add(Foo)
}
}
}
then it would also not use the secondary variants.
By default an attribute is considered compatible if it is absent and the more attributes matched, the better the match.
With a compatibility rule you can change that.
You can find deeper details about the selection algorithm in the manual at https://docs.gradle.org/current/userguide/variant_attributes.html#attribute_matchingBarteks2x
08/21/2022, 5:07 PMVampire
08/21/2022, 5:23 PMBarteks2x
08/21/2022, 5:29 PMBarteks2x
08/21/2022, 5:30 PMVampire
08/21/2022, 5:33 PMBarteks2x
08/21/2022, 5:37 PMartifactTypes.getByName("java-classes-directory")
shows that there is no such artifact type. Trying to create it doesn't have any effect.
I also tried to confirm all this by just creating the AttributeCompatibilityRule but that also doesn't seem to have an effect - the compatibility rule is never called with producer value nullVampire
08/21/2022, 5:39 PMBarteks2x
08/21/2022, 5:40 PMBarteks2x
08/21/2022, 5:48 PMBarteks2x
08/21/2022, 5:49 PMBarteks2x
08/21/2022, 6:13 PMBarteks2x
08/21/2022, 6:14 PMVampire
08/21/2022, 8:02 PMIn the meantime I also ported the test script to kotlin (because I want help from the IDE)Imho always a good idea, I use Kotlin DSL exclusively nowadays.
so gradle can resolve and run the transform just fine... but on a custom configuration it can't?I already explained that in the first post. On
implementation
all the JVM ecosystem attributes are set - in this case especially LIBRARY_ELEMENTS_ATTRIBUTE
, on your custom configuration they are not.
and this is what I'm trying with the compatibility ruleAh, sorry, it seems by test was bad. I added the compatibility rule but also had the
LIBRARY_ELEMENTS_ATTRIBUTE
on the dependency which made it work. š
Somehow specifying the usage attribute to java-api in the configuration I'm creating also fixes it... but why?Only one variant matches the attributes if you have
java-api
and that one can be transformed using the registered transform, so no ambiguity and it works.
But I feel like specifying the standard java attributes for the new configuration is the "correct" fixExactly