Philip W
12/11/2024, 11:41 AMPhilip W
12/11/2024, 11:53 AMPhilip W
12/11/2024, 11:59 AMval sourceSetName = objects.property(String::class).convention(sourceSets.main.name)
sourceSets.named {
it == sourceSetName.get()
}.configureEach {
println("Configuring $name")
}
val s = sourceSets.register("foo")
sourceSetName.set(s.name)
prints: "Configuring main" what makes sense because the named/configureEach will be called immediately.
So the only workaround I got to work is using afterEvaluateVampire
12/11/2024, 12:30 PMProvider
makes sense here, neither built-in nor like you showed there.
Whenever you use get()
on a provider at configuration time, you basically introduce the same problems you have when using afterEvaluate { ... }
, getting ordering problems, timing problems, and race conditions.
And the content of your named { ... }
is of course evaluated at configuration time, because you use it with configureEach
. This means it is checked immediately for any already existing and realized source sets and for later added ones as soon they are (if they are) realized. For the first case the property will not yet set, for the second it could be either way.Vampire
12/11/2024, 12:32 PMVampire
12/11/2024, 12:33 PMsourceSets.named { it == theParameterOfTheFunction }.configureEach { ... }
or something like that.Vampire
12/11/2024, 12:34 PMconfigureEach
part is coming from your plugin and the foo
from your consumerPhilip W
12/11/2024, 12:37 PMwhen should the provider of named be called?
This is my very basic MCVE:
val task: Provider<Task> = provider { }
val sourceSetName = objects.property(String::class).convention(sourceSets.main.name)
sourceSets.named(sourceSetName.get()) {
java.srcDir(task)
}
// user
val s = sourceSets.register("foo")
// the user should somehow connect the new sourceSet with the task
sourceSetName.set(s.name)
Philip W
12/11/2024, 12:38 PMVampire
12/11/2024, 12:38 PMnamed(...)
is immediately checked and only for source sets already registered at that part 😄Philip W
12/11/2024, 12:38 PMVampire
12/11/2024, 12:39 PMVampire
12/11/2024, 12:40 PMPhilip W
12/11/2024, 12:59 PMafterEvaluate
.
For DomainObjectSet, you can use whenObjectAdded
as a workaround that basically disables laziness, but for providers there is no onChange/set callback, because the value could be computed (instead of passed as literal).
Maybe Gradle could add an interface like AutoClosable
that will evaluate the providers of an extension, at a time handled by Gradle instead using afterEvaluate
.Martin
12/11/2024, 1:02 PMBut I use the function to configure the sourceSet immediately, I still want to support to use the main sourceSet as default/conventionProbably not the answer you're looking for but I moved the problem of connecting source sets to the caller:
myExtension {
// By default, generated sources are wired to the main source set
// but the user can override that
outputDirConnection {
connectToKotlinSourceSet("test")
}
}
It's more "imperative" than "declarative" but it's served us well so far.Martin
12/11/2024, 1:03 PMPhilip W
12/11/2024, 1:03 PMPhilip W
12/11/2024, 1:09 PMconnectToKotlinSourceSet
. Sounds like it works, but personally, I don't like it :DMartin
12/11/2024, 1:11 PMmyExtension {
service("foo") { // creates generateFooSources
outputDirConnection {
// overrides the default wiring of generateFooSources
connectToKotlinSourceSet("test")
}
}
}
Martin
12/11/2024, 1:12 PMMartin
12/11/2024, 1:13 PM