This message was deleted.
# community-support
s
This message was deleted.
v
The message does not tell you it didn't find a configuration. It says it couldn't choose between these two and didn't consider the third one. If you look at output of
: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.
b
I see. This really should be better explained. I will check if that solves it.
I don't really know where I would set that attribute
I figured it out, but also - this requires that this is done on the whole configuration, couldn't that lead to issues if there is any dependency that isn't a jar?
Another thing I don't understand there is that clearly, gradle can choose the variant if there is no transformed attribute being required. Then why can't it choose the same one it would have used otherwise?
v
As I tried to explain, without the transformed all three match attribute-wise. One is primary, the others are secondary to it, so the primary runs over the secondaries. With 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. You can set attributes on the whole configuration, but you can also set them on a specific dependency individually. So if you would have a differently typed necessary, you can overwrite the attribute for that specify dependency.
But yes, those details are relatively complex and I also needed some time to wrap my head around it to some extent. Still not always sure what happens.
b
I tried to set it in the dependency directly and getting
Mutation of attributes is not allowed
tried this
Copy code
dependencies {
    newTestConf(project(":sub")) {
        attributes.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements, LibraryElements.JAR))
    }
}
With 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?
I... no longer understand how that syntax works. attributes≄attribute() doesn't work but attributes{attribute()} does
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?
v
I tried to set it in the dependency directly and getting
Mutation of attributes is not allowed
Not fully sure right now why, but if you instead write it like
Copy code
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
Copy code
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
Copy code
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_matching
b
Now I think I finally understand it properly. Thanks for the explanation!
v
You're welcome
b
One last thing, hopefully: I wanted to do some more tests to confirm I understand it properly, and it seems like it's impossible for me to actually set the transformed attribute on the classes and resources variants
This is more for the sake of me copmpletely understanding how this all works. I can see and it agrees with the expanation that I'm setting the transformed attribute only for artifact type jar. But seems like it's not even possible to set it on the other variants
v
Why not? What did you try and what happened?
b
Copy code
artifactTypes.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 null
v
I tried the compatibility rule before I wrote it would work, so you probably made a mistake šŸ™‚
b
In the meantime I also ported the test script to kotlin (because I want help from the IDE) and this is what I'm trying with the compatibility rule https://gist.github.com/Barteks2x/08aa7d750591c898118c9a86d75fe603
There is also the really strange thing in that the entire situation doesn't happenm in the first place if I just specify the dependency on for example implementation and let gradle build the project - so gradle can resolve and run the transform just fine... but on a custom configuration it can't?
I can clearly work around the issue in multiple ways but what I'm seeing just still makes no sense to me
Somehow specifying the usage attribute to java-api in the configuration I'm creating also fixes it... but why?
oh because the others have java-runtime usage and that filters them out. But that still doexn't explain any of the other things. But I feel like specifying the standard java attributes for the new configuration is the "correct" fix
v
No idea about the artifact types of secondary variants, maybe that does not work or has to be done differently. Never dived into that part yet.
In 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 rule
Ah, 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" fix
Exactly