Reading stdin and The Kotlin DSL for Gradle - The Code Whisperer

Funny how the Gradle Kotlin DSL makes some things more consistent, but at the same time others less so.

Another alternative that I use and that is equivalent (as far as I know) is this:

tasks.run<JavaExec> {
    standardInput = System.`in`
}

This works because run comes pre-defined as an extension property on TaskContainer in the kotlin-dsl. If you jump to to the implementation you will find this:

val TaskContainer.`run`: TaskProvider<org.gradle.api.tasks.JavaExec>
    get() = named<org.gradle.api.tasks.JavaExec>("run")

We need the explicit <JavaExec> to get the invoke extension from Gradle to take precedence over the kotlin run scope-function. However since invoke operators are just syntactic sugar for just typing out invoke as a method call, we can also do this:

tasks.run.invoke {
    standardInput = System.`in`
}

And now it becomes interesting again, because how is invoke implemented? Let’s have a look:

operator fun <T> NamedDomainObjectProvider<T>.invoke(action: T.() -> Unit) =
    configure(action)

So the invoke method simply forwards to configure, which means we can also do this:

tasks.run.configure {
    standardInput = System.`in`
}

I am sticking with the first option I mentioned, but having many ways to do the same thing sure is confusing.

1 Like