unless there are strange circumstances you didn’t mention, you should not have a getter where you return a new provider on each call, that greatly violates the concept of the wireable lazy providers instead you probably simply want @get:OutputDirectory val outputDir = outputBaseDir.dir("foo") for example. Also calling get() in there is most probably not what you should do
the BarExtension.sources should most probably not be a Property<FileCollection> as that is a lazy type wrapped in a lazy type, but instead a ConfigurableFileCollection
do not call get() on any provider unless you really really really have to, or you totally destroy the benefit of the lazy wireable providers. With that you immediately evaluate the value they have at that point in time and also loose the implicit task dependencies you want to have. get() should optimally never be called at configuration time but always only at execution time.
and then you would have in the last snippet sources.from(foo) if outputDir is the only outpuf of the task, or sources.from(foo.flatMap { it.outputDir }) if there are multiple outputs but there you only want that single one.
unless there are strange circumstances you didn’t mention, you should not have a getter where you return a new provider on each call, that greatly violates the concept of the wireable lazy providers instead you probably simply want @get:OutputDirectory val outputDir = outputBaseDir.dir("foo") for example. Also calling get() in there is most probably not what you should do
One “strange” circumstance not shown in my original the example: The output dir of the task depends on its boolean input properties, so the actual code looks more like:
@get:Input
abstract val option: Property<Boolean>
@OutputDirectory
fun getOutputDir(): Provider<Directory> {
return project.provider {
if (option.get()) {
outputBaseDir.dir("option_foo").get()
} else {
outputBaseDir.dir("default_foo").get()
}
}
}
If there is a better way to manage this, I am eager to learn about it.
the BarExtension.sources should most probably not be a Property<FileCollection> as that is a lazy type wrapped in a lazy type, but instead a ConfigurableFileCollection
I must be working with an older version of the api, as my ConfigurableFileCollection does not extend SupportsConvention, though the docs say it should.
do not call get() on any provider unless you really really really have to, or you totally destroy the benefit of the lazy wireable providers. With that you immediately evaluate the value they have at that point in time and also loose the implicit task dependencies you want to have. get() should optimally never be called at configuration time but always only at execution time.
This 100% make sense. I am trying to figure out how to avoid this.
and then you would have in the last snippet sources.from(foo) if outputDir is the only outpuf of the task, or sources.from(foo.flatMap { it.outputDir }) if there are multiple outputs but there you only want that single one.
This looks promising. I am getting some compile errors with it at the moment, but will report back if I can make this work.
One “strange” circumstance not shown in my original the example: The output dir of the task depends on its boolean input properties, so the actual code looks more like:
Doesn’t change much in what I said.
do not write getter-functions like that in Kotlin, that is very unidiomatic for Kotlin and ugly to use. if you would need to do it like that (Spoiler: you don’t), then at least make it a read-only property and implement its getter like
@get:OutputDirectory
val outputDir: Provider<Directory>
get() {
return project.provider {
if (option.get()) {
outputBaseDir.dir("option_foo").get()
} else {
outputBaseDir.dir("default_foo").get()
}
}
}
do not use ad-hoc providers like that, returning a new provider each time and calculating in it with get(), but properly wire properties together. Like you do it, you for example loose any existing task-dependency information. If for example the provider value that is set for option has a task dependency you would loose it that way, and you cannot know whether you have one. Instead properly wire the two properties together using Provider.zip like:
@get:OutputDirectory
val outputDir = option.zip(outputBaseDir) { option, outputBaseDir ->
if (option) {
outputBaseDir.dir("option_foo")
} else {
outputBaseDir.dir("default_foo")
}
}
or simply
@get:OutputDirectory
val outputDir = outputBaseDir.dir(option.map { if (it) "option_foo" else "default_foo" })
I must be working with an older version of the api, as my ConfigurableFileCollection does not extend SupportsConvention , though the docs say it should.
I don’t get that argument. SupportsConvention exists only since 8.7 and is incubating and there ConfigurableFileCollection also implements it.
If your plugin needs to be compatible with <8.7, fine, there of course it does not exist yet so it can also not implement it.
But that does not really explain why you think you need to double-lazify the property which is bad practice for various reasons. ConfigurableFileCollection also only supports convention(...) since Gradle 8.8, so before it just could have a concrete value, and to reset the concrete value to a completely differen value, you can just use setFrom(...).