This message was deleted.
# dependency-management
s
This message was deleted.
c
consumer/build.gradle.kts
Copy code
dependencies {
    attributesSchema {
        attribute(Features.FEATURES_ATTRIBUTE)
    }
}

val producerConfiguration by configurations.creating {
    isCanBeConsumed = false
    isCanBeResolved = true
    isVisible = false
    attributes {
        attribute(Features.FEATURES_ATTRIBUTE, "one,two")
    }
}

dependencies {
    producerConfiguration(project(":producer", configuration = "default"))
}

tasks.register<Copy>("copyLibs") {
    from(producerConfiguration)
    into(layout.buildDirectory.dir("features")
}
I would expect it to fail resolving it because :producer "default" configuration doesn't have FEATURES_ATTRIBUTE
if I do use
producerConfiguration(project(":producer", configuration = "myConfogiration"))
(where myConfiguration has set any value for FEATURES_ATTRIBUTE) It fails resolving the dependency as expected
v
https://docs.gradle.org/current/userguide/variant_attributes.html#sec:abm_algorithm
Each candidate’s attribute value is compared to the consumer’s requested attribute value. A candidate is considered compatible if its value matches the consumer’s value exactly, passes the attribute’s compatibility rule or is not provided.
So yes, works as designed I'd say.
c
Sorry, I saw you also replied in the other thread. I wrote it here to have a broader issue, but you got it fast I would say..that's terrible then, default will always match any attribute requirement.
v
I'm sure it has some sense. The attribute matching in Gradle is not trivial. Needs some time to wrap the head around.
c
maybe then it's my usage of the feature
I could use Usage="features"
or something like that to enforce the selection of my variant, but then it's like using
configuration="myConfiguration"
v
Or maybe feature variants / capabilities?
c
or maybe configurations.configuraEach and add my attribute
v
Yeah, that would be like the example in the docs, just that there it is added to the artifacts
Ah, no, confused that with artifact transform
c
capabilities are to make sure you only use one dependency with that capability, I don't think it's meant for my usecase
v
No, capabilities are not only for that. They are also the driver behind the feature variants functionality
c
another option is..
Copy code
configurations["default"].attributes {
    attributeProvider(Features.FEATURES_ATTRIBUTE, "...")
}
c
It feels to me like maybe the attribute compatibility rules are not configured correctly? It sounds like anyone fetching who requests your attribute should be incompatible with anything not declaring your attribute?
c
I removed the compatibilityRule (it's not called when the producer didn't set the attribute)
I had the same understanding @Chris, that's why I was going mad
v
See my quoted part of the docs above @Chris
Last case
c
hmm… yes - maybe @CristianGM you could make this more concrete? What does
Features
represent and what values can it take?
c
our libraries can have a list of features they implement (not like capabilities, not exclusive) We want to create "bundles" including just the libraries that have only "included features".
(think of bundles like ""fatJars"")
c
Ahh yes… I’m getting deja-vu. The right way to model this is with capabilities/feature variants as @Vampire suggests (I believe)… but I’ve hit issues with this stuff in the past. @Louis Jacomet care to help out here 😉?
c
note here I'm using
incoming.artifactView { lenient(true) }
to be able to run the task while excluding artifacts
l
Two things: • That rule on marking missing attribute as compatible with a request asking for it is actually a mandatory feature for any kind of backwards compatible evolution of variants. And since in the context of published metadata, backwards should be forever, there is just no way around it. I wished we had some public doc explaining that more in detail. Please trust me for now 😉 • I am not sure the current system can represent what you are trying to do because of the above. If your setup enhances existing variants, in a compatible way - that is they are selectable by a consumers just looking for a runtime classpath for example - then you will have to filter out the results outside of resolution itself.
c
I have made it, and it works fine, is just that I didn't expect that behaviour and thought it was a but. I would say 🙏 🙏 🙏 improve the docs to make it clear (and to understand the reasons).
👌 1
v
Then I would say open a doc improvement request ticket (or PR). :-)
👍 1