I have a lazy property like Map/Boolean to control the plugin generating java code. And I want to make plugin not adding the task or folder to dependency when user disable the flag. I saw we can create empty provider like project.provider(() -> null), but looks like dependsOn or srcDir can’t use it?
The code is like below
// At extension
Property<Boolean> getFlag();
// At plugin code
public void apply(Project project) {
final TaskProvider<> customTask = ....;
project.getPlugins().withType(JavaPlugin.class).configureEach(javaPlugin -> {
project.getTasks().named(JavaPlugin.COMPILE_JAVA_TASK_NAME).configure(task -> {
task.dependsOn(extension.getFlag().flatMap(flag -> {
if (flag) {
return customTask;
} else {
// How to write this line? It will complain like Cannot query the value of this provider because it has no value available.
return project.provider(() -> null);
}
}));
});
}
}
Above code will not work when flag become false by showing the error like Cannot query the value of this provider because it has no value available.. Curious if we have anyway to achieve it or I should avoid using this behavior.
It might be better to not try it like that, but instead have an opt-in function in your extension, that then does the according changes as necessary.
And btw. if you look at project.getPlugins(), its usage is discouraged, you should instead use project.getPluginManager().withPlugin("java") { ... }.
And finally, wiring tasks manually using dependsOn is practically always a code-smell, except when there is a lifecycle task on the left-hand side. You should better wire outputs to inputs and by that get necessary task dependencies automatically. I guess customTask is your Java source generation task. If you only wire compileJava to it manually, all other actions needing sources do not get them like sourcesJar, static code analysis tools, and so on. If you would properly wire the codegeneration task like sourceSets.main { java.srcDir(customTask) } it would just work.
It might be better to not try it like that, but instead have an opt-in function in your extension, that then does the according changes as necessary.
What do you mean opt-in? Is flag not opt-in here? Or maybe can you provide an example
And btw. if you look at project.getPlugins() , its usage is discouraged, you should instead use project.getPluginManager().withPlugin("java") { ... } .
Thanks for your suggestion. will try this.
And finally, wiring tasks manually using dependsOn is practically always a code-smell, except when there is a lifecycle task on the left-hand side. You should better wire outputs to inputs and by that get necessary task dependencies automatically. I guess customTask is your Java source generation task. If you only wire compileJava to it manually, all other actions needing sources do not get them like sourcesJar , static code analysis tools, and so on. If you would properly wire the codegeneration task like sourceSets.main { java.srcDir(customTask) } it would just work.
This is due to my output may have nested folder which may cause the package weird, let me try if possible later.
What do you mean opt-in? Is flag not opt-in here? Or maybe can you provide an example
The important point was not “opt-in”, but “function”.
Not a flag you can flip and flip and flip and then have to react after it cannot be changed anymore,
but a function doGenerateMyCode() in your extension that the consumer can call.
In the implementation of the function you can then do the necessary configuration right away.
Thanks, let me think about it due to I may want to use lazy configuration with other properties. If we use method to trigger behavior eagerly, then code will become bit complex due to I need to have state reset when user call multiple times with different behavior.
when user call multiple times with different behavior
That’s the point.
My suggestion contains to not allow that.
Not a function to opt-in or opt-out, but only a function to opt-in.
Then there is no complex code and no state resetting or similar.
Just let the user say “I want it” and then do it.
Another option, especially when multiple properties on the extension are involved and you don’t want to make it a function call with multiple arguments instead would be to add one nesting level, so having for example like:
myExtension {
config {
flag = true
...
}
}
Then config is a function in your extension, taking an Action<MyConfigurationFlags>.
In the config function you then first check that the function is only called once,
then you invoke the supplied action, then you evaluate the flags and do according configuration.
I think you do not have much more options to avoid the cursed afterEvaluate.
I see, thanks for detail explanation.
One more question, if I do like
then you invoke the supplied action, then you evaluate the flags and do according configuration.
My configuration is adding task dependency to JavaPlugin’s task, how can i do that in Extension#config ? Because Plugin class apply method runs before config method call so it means I can’t do it at Plugins#apply?