How do I check if a task exists? I tried `tasks.na...
# community-support
m
How do I check if a task exists? I tried
tasks.named(...).isPresent
, but it seems tasks.named is throwing an UnknownTaskException instead?
m
Catch the exception?
m
Is there no simpler method of doing it? And in that case, what's the point of isPresent if it throws an exception regardless?
m
I don't think there's another "lazy" way
v
isPresent
is to check whether the provider is present or has no value. But you do not even come that far, as
named(...)
requires that the task is already registered
m
The
isPresent
is part of the
Provider
API
v
Catching the exception is not a good idea though of course 😄
You just use
tasks.names.contains(...)
to check whether the task is already registered without forcing it to be realized.
BUT, there is almost no valid use-case to do that
☝️ 1
So you might want to instead take a step back from the XY problem and tell us about the use-case you try to solve, then we can maybe provide a better suggestion than to check whether a specific task is already registered or not.
m
tasks.names.contains(...)
That's an aside to this discussion but that's technically 2 lookups. It's a pity Gradle doesn't provide an API that does both at the same time IMO (which
named()
does but at the price of using exceptions for flow control, which isn't great either)
m
The use-case here is to create a task to download a required tool as dependency, but only if that task doesn't already exist. Additionally, the binaries required for the exec are dependent on the output directory of that task for their convention
v
That's an aside to this discussion but that's technically 2 lookups
Not sure what you mean. You get a list and then look in that list. That's one lookup for me.
but only if that task doesn't already exist.
You really shouldn't do that. Instead for example have one separate plugin that adds this task, and from the other plugins that would register the task if it is absent, just apply that other plugin that always registers it.
m
and then in my task's init do I just use
dependsOn(project.tasks.named(...))
? Since this task is designed to be used by the developer in their build scripts rather than by a plugin registering the task, so if they register a task with this type it should automatically add the dependency ideally
v
They do apply a related plugin though, right?
m
Not sure what you mean.
With
tasks.names.contains()
, you first need to check for existence and get the value if it exists. Would be cool to be able to do both in a single call
m
It's currently designed to just be lifted from the repo as-is and put into a buildSrc
m
Just like there is
Map<T>.get(): T?
v
Just like there is
Map<T>.get(): T?
Ah, I see, you didn't mean the check, but the
registerIfAbsent
idiom. Well, it is usually bad practice, that might be the reason they don't provide it. 🤷‍♂️ But feel free to open a feature request to see what Gradle folks think if there is none yet. 🙂
It's currently designed to just be lifted from the repo as-is and put into a buildSrc
Where would you then apply the separate plugin I mentioned? Or where would you have wanted to do the "register task if it does not exist" logic if not in a plugin they apply?
If they apply some plugin, that plugin can do a
tasks.withType(...).configureEach { ... }
that configures all tasks of that type and set them up as required, including tasks the consumers register manually in their build scripts. And besides that, either way you should not use
dependsOn
. Practically any explicit
dependsOn
that does not have a lifecycle task on the lefthand side is a code smell and usually a sign that you do not properly wire task outputs to task inputs, which would automatically add the necessary task dependency. So if you for example have the download task that has an
@OutputFile
property to which you download the file and then an
@InputFile
property on the other task that needs it, you would wire those properties together and with that have the necessary task dependency automatically where needed.
m
But feel free to open a feature request to see what Gradle folks think if there is none yet
I'll skip that one, there are a bunch of more pressing issues at the moment, I can live with this
👌 1
v
m
It's not even that,
maybeCreate
is
Map.getOrPut{}
. In that case, it'd be more like
Map.getOrDefault{}
v
You can anytime use
named { ... }
and check if it is there. You just have to keep in mind that it is only working configuration-avoidance safe combined with
configureEach
not with iterating or checking even thought that was its original intention.
But, well, in most situations as I said, it is a bad idea. If you need the task, make sure it is registered. The use-case of OP would indeed be
getOrPut
just configuration-avoidance safe ... and it shouldn't be done 😄