Hello, How to configure lazily a task property (th...
# community-support
e
Hello, How to configure lazily a task property (that is not lazy) ? I would like to configure a Copy task
includeEmptyDirs
property using a custom project extension. The extension will have a
Property<Boolean>
. How to apply my extension property lazily ? As a workaround I was thinking to use
doFirst{}
during my task configuration :
Copy code
doFirst {
    includeEmptyDirs = extension.includeEmptyDirs.get()    
}
t
You don't have many options besides
afterEvaluate {}
(and do
finalizeValue()
there to make sure the extension cannot be reconfigured afterwards)
doFirst {}
should also work I think; but make sure you also declare your extension property as task input (
inputs.property("my-plugin-includeEmptyDirs", extension.includeEmptyDirs)
) for proper up-to-date checks
👍 1
If you're creating that task, maybe you could make a custom task using a
FileSystemOperations
, that way you can easily configure the
CopySpec
at execution time.
v
You should really not change a tasks configuration at execution time. Iirc if you ever hope to use configuration cache it should even result in a hard error. Besides that I'm this case I agree with Thomas that not using a
Copy
task, but a
copy { ... }
call at execution time is the better way, in similar situations I would recommend not to use a
Property
in the extension, but a function the body of which does the configuration change.
e
Thank you @Thomas Broyer and @Vampire. Why gradle
Property<T>
are not
Observable
? If it was the case I could use it to configure non lazy taks. I would end up using it like this :
Copy code
open class JavaOptionsExtension @Inject constructor(objectFactory: ObjectFactory) {
    val javaVersion: ObservableProperty<JavaVersion> = objectFactory.observableProperty()
}

the<JavaOptionsExtension>().apply {
    javaVersion.onChange {
        java{
            sourceCompatibility= javaVersion.get()
            targetCompatibility= javaVersion.get()
        }
    }
}
v
That you have to ask Gradle folks. Probably because you really should not do that but properly wire things together, only requesting them at execution phase. 🤷‍♂️
But sometimes it would be handy, yes, especially to do things that need to be done at configuration time
👍 1
Maybe you should open a feature request if there is none 🤷‍♂️
e
I opened a feature request but my explanations are not very clear 😅. https://github.com/gradle/gradle/issues/33062
👌 1
v
Thinking about it, I guess a problem will be that it is not really determinable when a property changes. Because often you wire a property to another property that is wired to another property that is wired to another property, and the value could even depend on some task being executed first. So you can maybe get notification about the direct value source being set, but probably not reliably about the actual value changing.
👆 1
Copy code
var observed = objects.property<String>()
var changed = objects.property<String>()
observed = changed
changed.set("foo")
Or
Copy code
var observed = objects.property<String>()
var changed = objects.property<String>()
observed = changed
changed.set(tasks.foo.map { it.outputs.files.singleFile.readText() })
t
Also, ValueSource.
👆 1
Gradle is moving to make everything a Property in v9 (even using bytecode rewriting at runtime IIUC) so this should not be needed in the long term. Your example above will just be:
Copy code
java {
  sourceCompatibility = the<JavaOptionsExtension>().javaVersion
  targetCompatibility = the<JavaOptionsExtension>().javaVersion
}
🙌 1
See also the discussion at https://github.com/tbroyer/gradle-errorprone-plugin/issues/97 which touches this topic.
e
The very begining of some sort of plugin: https://github.com/evantill/observable-property-gradle-plugin
v
Gradle is moving to make everything a Property in v9 (even using bytecode rewriting at runtime IIUC) so this should not be needed in the long term.
Unfortunately not 😞
It was shifted to v10 two weeks ago
😢 2