Stefano Zanella
08/23/2024, 8:39 PMresolvableConfiguration.incoming.resolutionResult.rootComponent.get().dependencies
Reading around it seems that maybe those dependencies don't match the variant attributes associated to the configuration, but I don't know how I can tweak this so that these self-resolving dependencies "declare" the correct variant.
Some code to make this more concrete:
// plugin `apply()`
val declarable = project.configurations.dependencyScope("pythonScope")
project.configurations.consumable("pythonConsumable") {
it.attributes {
it.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage::class.java, "python"))
}
}
val resolvable = project.configurations.resolvable("pythonResolvable") {
it.extendsFrom(declarable.get())
it.attributes {
it.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage::class.java, "python"))
}
}
// custom dependency class
interface PipDependency : Dependency {
fun asPipRequirement(): String
}
data class RemotePipDependency(
private val name: String,
private val versionSpec: VersionConstraint,
private val extras: List<String>,
private val objectFactory: ObjectFactory,
) : PipDependency, SelfResolvingDependencyInternal, FileCollectionDependency {
// ... etc etc, not much going on here
}
// plugin extension to encapsulate the custom dependency
internal class DefaultPipDependencyExtension @Inject constructor(
private val dependencies: DependencySet,
private val objectFactory: ObjectFactory,
) : PipDependencyExtension {
override fun invoke(name: String, versionSpec: String?, extras: List<String>): Dependency =
RemotePipDependency(
name,
versionSpec?.let { VersionConstraint(it) } ?: VersionConstraint.EMPTY,
extras,
objectFactory,
).also { dependencies.add(it) }
override fun invoke(project: ProjectDependency): Dependency = project.also { dependencies.add(it) }
}
If from a task I call
println(resolvable.get().incoming.resolutionResult.rootComponent.get().dependencies)
I get nothing.Vampire
08/23/2024, 9:34 PMVampire
08/23/2024, 9:34 PMStefano Zanella
08/23/2024, 9:34 PMVampire
08/23/2024, 9:34 PMStefano Zanella
08/23/2024, 9:34 PMVampire
08/23/2024, 9:35 PMStefano Zanella
08/23/2024, 9:35 PMVampire
08/23/2024, 9:35 PMStefano Zanella
08/23/2024, 9:36 PMStefano Zanella
08/23/2024, 9:37 PMVampire
08/23/2024, 9:37 PMAdam
08/23/2024, 9:39 PMStefano Zanella
08/23/2024, 9:39 PMVampire
08/23/2024, 9:40 PMStefano Zanella
08/23/2024, 9:42 PMAdam
08/23/2024, 9:44 PMI still need to put the dependency declarations in a pyproject.toml fileDo you mean that the dependencies will be declared in two places, the Python toml and Gradle
dependencies {}?Stefano Zanella
08/23/2024, 9:47 PMAdam
08/23/2024, 9:47 PMAdam
08/23/2024, 9:48 PMdependencies {} altogether and writing your own pythonDependencies {} extension?Adam
08/23/2024, 9:49 PMpyproject.toml and executes whatever the Python dependency downloading task is.Stefano Zanella
08/23/2024, 9:49 PMdependencies {
pip(project(grpc.stub.python))
}
and for this it's definitely easier to tap into the variant-aware resolution systemAdam
08/23/2024, 9:52 PMpythonDependencies {} block. It would be even easier because the standard dependencies {} block is quite old, and is very Groovy based.
I'd create a PythonDependencies class and add methods with overloads.
• fun pip(coord: String) would be put straight into the pyproject.toml
• fun pip(project: Project) would use the Gradle dependency resolution.Stefano Zanella
08/23/2024, 9:52 PMStefano Zanella
08/23/2024, 9:55 PMAdam
08/23/2024, 9:55 PMStefano Zanella
08/23/2024, 9:56 PMAdam
08/23/2024, 9:59 PMI need to use the resolvable configurationYeah, for sharing files between subprojects you need a 'declarable' configuration and a 'resolver' and a 'consumable'. It's a lot of boilerplate. Just to be clear, in case there's some confusion, the docs you linked are about getting the dependency graph. To get the actual files it's simpler:
val fooConfResolver by configurations.creating {
extendsFrom(fooConf)
isCanBeDeclared = false
isCanBeConsumed = false
isCanBeResolved = true
}
val fetchFiles by tasks.registering(Sync::class) {
from(fooConfResolver.incoming.files)
into("fetched-files")
}Adam
08/23/2024, 10:00 PMresolvableConfiguration.incoming.resolutionResult.rootComponent.get().dependencies has .get() it resolved the graph too early, so it didn't get the resolved dependencies? But I'm just guessing.Adam
08/23/2024, 10:01 PMStefano Zanella
08/23/2024, 10:01 PMdeclarable. I'm also not sure if it's resolved too early, it's inside the doLast of the task that otherwise reads from the declarable configurationStefano Zanella
08/23/2024, 10:01 PMAdam
08/23/2024, 10:02 PM--no-build-cache & --no-configuration-cache)?Stefano Zanella
08/23/2024, 10:03 PMAdam
08/23/2024, 10:04 PMAdam
08/23/2024, 10:04 PMincoming.resolutionResult isn't the best fitAdam
08/23/2024, 10:04 PMAdam
08/23/2024, 10:06 PMStefano Zanella
08/23/2024, 10:08 PMdeclared.get().dependencies as an input in a property. This works but breaks the build the moment I try to define an output for the task, I guess because something in the tree of classes making up the set of RemotePipDependency is not serializable and thus Gradle cannot cache it.
The sample you pointed at is precisely where I got the line about incoming.resolutionResult.rootComponent.Adam
08/23/2024, 10:11 PMAdam
08/23/2024, 10:12 PMAdam
08/23/2024, 10:17 PMStefano Zanella
08/23/2024, 10:19 PMStefano Zanella
08/23/2024, 10:21 PMStefano Zanella
08/23/2024, 10:22 PMStefano Zanella
08/23/2024, 10:24 PM