This message was deleted.
# community-support
s
This message was deleted.
v
Typically the argument provider has properties itself that are annotated with input annotations and are then used in the argument building method
👆 1
t
I'd say that, first, you probably shouldn't extend
JavaExec
and rather make your own task that executes your class with an `ExecOperations`'
javaExec
. That said, have you tried putting the
@OutputDirectory
on a property of the argument provider instead?
Copy code
abstract class GenerateLexerTask
  @Inject constructor(
    private val objects: ObjectFactory
  ) : JavaExec() {
    private val argumentProvider = ArgumentProvider(objects)
    abstract val targetOutputDir get() = argumentProvider.targetOutputDir

    // …

    init {
        // …
        argumentProviders.add(argumentProvider)
    }
}
internal class ArgumentProvider(
    objects: ObjectFactory
) : CommandLineArgumentProvider /* XXX: you should implement Named too */ {
    @get:OutputDirectory
    val targetOutputDir = objects.directoryProperty()

    override asArguments() = listOf(…)
}
v
I'm not sure argument provider can have output annotations (that have an effect)?
t
I must say I've indeed only ever used input properties in argument providers, and I'm assuming the issue here is specifically about the output property, so 🤷
v
Hm, because the argument provider accesses the property before the task was run of course and that makes it fail.
Awkward
Maybe it is a regression that it does not work anymore in 8.3 and it could be fixed in an 8.3.1. if reported as regression
Actually, no
I tried with this in my play project:
Copy code
abstract class GenerateLexerTask : JavaExec() {
    @get:OutputDirectory
    abstract val targetOutputDir: DirectoryProperty

    @get:InputFile
    @get:PathSensitive(PathSensitivity.RELATIVE)
    abstract val sourceFile: RegularFileProperty

    init {
        mainClass = "jflex.Main"
        argumentProviders.add {
            listOf(
                "-d",
                targetOutputDir.get().asFile.absolutePath,
                sourceFile.get().asFile.absolutePath,
            )
        }
    }
}

val bar by tasks.registering(GenerateLexerTask::class) {
    targetOutputDir = layout.buildDirectory.dir("bar")
    sourceFile = layout.projectDirectory.file("gradle.properties")
}
val foo by tasks.registering {
    inputs.files(bar)
}
and it works fine
Meaning I did
gw foo
with 8.3 used and it failed for not finding the
jflex.Main
class
m
it will work if you do call
get()
on the properties first rather than map the properties and call
get()
at the end, I had a similar issue and I've learned never to map lazy properties in task actions from that
😮 1
but what others said, don't extend the task, implement a custom
CommandLineArgumentProvider
I'm not sure argument provider can have output annotations (that have an effect)?
It can, @Vampire, there's
@Nested
on
org.gradle.process.JavaExecSpec#getArgumentProviders
t
They cannot have
@Option
though (options need to be on the task, cannot be on a
@Nested
object; unless that changed since I tried it long ago)
m
You might be right about
@Option
But I don't see anybody else mentioning
@Option
prior to you just now, Björn was raising output annotations not being effective.
v
Ah, right,
Copy code
argumentProviders.add {
    listOf(
        "-d",
        targetOutputDir.asFile.map { it.absolutePath }.get(),
        sourceFile.asFile.map { it.absolutePath }.get(),
    )
}
reproduces the error
☝️ 1
t
But I don't see anybody else mentioning
@Option
prior to you just now, Björn was raising output annotations not being effective.
Indeed. I was just widening the all property annotations. I mean
@Nested
works in some cases (input and output) but not others (option)
👌 1
m
To me
@Option
is a completely separate thing as it has nothing to do with inputs and outputs from the incremental build point of view. 🤷
👍 1
You do apply it to properties but I still think it's a different kettle of fish.
p
Wow, thanks for all the answers. So I will just change the get/map order, and the JavaExec inheritance. But interesting to see different get/map order fails the build...
Okay, I can't change the order, I register the task in a precompiled script, but set the value in the actual project, but the init block is called during registering resolving the provider directly, not lazy as in Gradle 8.2.1. Sounds like a regression to me 🤔
m
the problem will go away if you re-implement it as a
CommandLineArgumentProvider
You want your code dealing with properties to be as lazy as possible rather than doing things eagerly in an init block
v
He does have a
CommandLineArgumentProvider
even if it doesn't look like it. 🙂 The Kotlin lambda implements the
CommandLineArgumentProvider
.
p
Yup, it is just caused by the lambda/SAM interop.
v
@Philip W the part where you use the properties is lazily evaluated, so you can just
get()
the property and do not need to map anymore. This argument provider method you implement is only executed at runtime, so no need to use
map
That's one of the senses of the argument provider, that you can evaluate the properties late
p
I already tried this, but it still does not work.
Copy code
@CacheableTask
abstract class GenerateLexerTask : DefaultTask() {
    @get:OutputDirectory
    abstract val targetOutputDir: DirectoryProperty
    
    @get:InputFile
    @get:PathSensitive(PathSensitivity.RELATIVE)
    abstract val sourceFile: RegularFileProperty

    @get:Inject
    abstract val exec: ExecOperations

    init {
        exec.javaexec {
            mainClass.set("jflex.Main")

            argumentProviders.add(object: CommandLineArgumentProvider {
                override fun asArguments(): Iterable<String> {
                    return listOf(
                        "-d",
                        targetOutputDir.get().asFile.canonicalPath,
                        sourceFile.get().asFile.canonicalPath,
                    )
                }
            })
        }
    }
}
v
Can you show the actual code that is not working? The code you initially showed does not even compile.
p
Hm, why not?
v
Because
.path
is probably an extension function you define somewhere else in your code. 🙂
p
Ah, okay, yeah sorry, I inlined it now.
But it was:
map { it.asFile.canonicalPath }
BTW I don't understand why there is a
CommandLineArgumentProvider
at all and not just
ListProperty<String>
...
v
1. it is older than list properties 2. you can put input and output annotations to the argument provider properties so that the task becomes out of date if something you calculate the value from change but is not otherwise declared as task input anyway Btw. you should not use the
-all
distribution, but the
-bin
distribution. The
-all
distribution has only one use-case. During editing build scripts and only if they are written with Groovy DSL. When only executing the build or having Kotlin build scripts anyway, the
-all
distribution just wastes space, time, and bandwith of everyone and everything executing the build.
Can you maybe knit an MCVE where you use
targetOutputDir.get().asFile.canonicalPath
that does fail with the error you mentioned?
p
Yes: Gradle 8.2.1: https://github.com/hfhbd/gradle-jvmargprovider-bug/actions/runs/6156448601/job/16705142109 fails with Main class not found, I am to lazy to add a jar to the class path Gradle 8.3: https://github.com/hfhbd/gradle-jvmargprovider-bug/actions/runs/6156459152/job/16705173717 - fails with Querying the mapped value of task ':generateLexer' property 'targetOutputDir' before task ':generateLexer' has completed is not supported.
v
Yep, as we said. It might still be worth to report as regression as such a check should go through a deprecation cycle as it breaks existing working builds. So I guess it might have been accidentally introduce in 8.3 and you could get an 8.3.1 that reverts the change. Or you just not use
map
her as we advised above. 🙂
p
Oh, you are right. Using
get()
first without another provider does work with Gradle 8.3, thank you, I missed this combination after creating the reproducer. And it does work! Yes, I already created an issue: https://github.com/gradle/gradle/issues/26340
👌 1
m
I've added a comment to it with my experience, @Philip W.
👍 1