Executing registered task in kotlin build file - gradle

I need to convert a gradle build script, which is written in Groovy, into Kotlin. The problem is, that in the Groovy build file in one task another task, which was defined before, is executed. However, it appears that in Kotlin there is no support for that, at least I could not find any in the API.
I have studied the API and searched for similar problems, but I could not find anything useful.
The Groovy code looks like this:
task doSomething () {
...
}
task anotherTask () {
...
doSomething.execute()
...
}
How would this call be translated into Kotlin?
doSomething.execute()

You should never call execute() on a task. Instead set the inputs, outputs and dependencies correctly, and Gradle will call the task for you if it needs to.
something like:
tasks {
val doSomething by registering {
doLast {
println("running doSomething")
}
}
val anotherTask by registering {
dependsOn(doSomething)
doLast {
println("Running anotherTask")
}
}
}
Then:
$ gradle anotherTask
> Task :doSomething
running doSomething
> Task :anotherTask
Running anotherTask
BUILD SUCCESSFUL in 746ms

Kotlin is statically typed. So you must know the type of the task of doSomething and anotherTask if Kotlin not able to infer it for you. execute leads me to believe it some sort of execute task. So for your example:
val doSomething = tasks.register("doSomething", JavaExec::class.java) {
main = "com.example.Example"
}
val anotherTask = tasks.register("anotherTask") {
doSomething.get().exec()
}
However, it looks you just want to execute doSomething before anotherTask, so you'd want:
val doSomething = tasks.register("doSomething", JavaExec::class.java) {
main = "com.example.Example"
}
val anotherTask = tasks.register("anotherTask") {
dependsOn(doSomething)
}
Without knowing the types of your task it's difficult to give you the right answer.

Related

Creating a task that runs before all other tasks in gradle

I need to create an initialize task that will run before all other task when I execute it.
task A {
println "Task A"
}
task initializer {
println "initialized"
}
If I execute gradle -q A, the output will be:
>initialized
>Task A
Now if i'll add:
task B {
println "Task B"
}
Execute gradle -q B, and I get:
>initialized
>Task B
So it doesn't matter which task I execute, it always get "initialized" first.
You can make every Task who's name is NOT 'initializer' depend on the 'initializer' task. Eg:
task initializer {
doLast { println "initializer" }
}
task task1() {
doLast { println "task1" }
}
// make every other task depend on 'initializer'
// matching() and all() are "live" so any tasks declared after this line will also depend on 'initializer'
tasks.matching { it.name != 'initializer' }.all { Task task ->
task.dependsOn initializer
}
task task2() {
doLast { println "task2" }
}
Or you could add a BuildListener (or use one of the convenience methods eg: Gradle.buildStarted(...))
Seems like you aim execution phase, and you want a task precursing each task or just run as a first task in the execution phase?
If you want a task to always execute in every project before each other task after its being evaluated you can add a closure to he main build.gradle:
allprojects {
afterEvaluate {
for(def task in it.tasks)
if(task != rootProject.tasks.YourTask)
task.dependsOn rootProject.tasks.YourTask
}
}
or
tasks.matching {it != YourTask}.all {it.dependsOn YourTask}
You can also use the Task Execution Graph to define the lifecycle. There are few ways of achieving your goal, depending on your needs and a project structure.
The previously suggested solution with dependsOn works fine, but I don't like about it that it changes and clutters the task dependencies. The first solution coming to my mind is using Gradle Initialization Scripts. They are really cool. But, the usage is a bit tedious: currently there is no way to have a default project-local Gradle init script. You have to either explicitly specify the script(s) on command line, or place them in USER_HOME/GRADLE_HOME.
So another solution (already briefliy mentioned by #lance-java) which can be used to run some initialization, like a init task/script, is "build listeners". Depending on how early/late the initialization code should run, I use one of these two:
gradle.afterProject {
println '=== initialized in afterProject'
}
or
gradle.taskGraph.whenReady {
println '=== initialized in taskGraph.whenReady'
}
Here the docs of the Gradle interface and of BuildListener.
Note that some of the events occur very early, and you probably can't use them because of that, like e.g. beforeProject and buildStarted (explanations here and there).

Automatically pass unparsed arguments to JavaExec-type task in Gradle?

I'm trying to pass a lot of arguments to a JavaExec task in Gradle. Right now I'm doing something like:
task foo(type: JavaExec) {
if (project.hasProperty('prop1')) {
args += ["--prop1"]
}
if (project.hasProperty('foo2')) {
args += ["--foo3"]
}
...
if (project.hasProperty('flagn')) {
args += ["--flagn"]
}
}
And then when I execute this I do something like ./gradlew :foo -Pprop1 -Pfoo2 ... -Pflagn. This works but is really tedious since I need to literally pass the same string arguments from Gradle to JVM. Is there an easier way - like automatically pass all the unparsed arguments or something simpler?
You can access the project properties from the command line via the StartParameter object.
So, for your example, you could use:
task foo(type: JavaExec) {
args gradle.startParameter.projectProperties.keySet().collect { "--$it" }
}
However, this will add any command line project property to the JavaExec args. Maybe you could think about filtering for properties with a specific prefix.

How do I alias gradle task as if it were called with -x parameter?

I want instead of gradle cleanIdea idea -x compileJava -x compileTestJava
call something like gradle ideaNoRecompile
You can use TaskExecutionGraph to do it. First of all, you need to provide a custom task, named ideaNoRecompile, when during the configuration phase, you need to check, whether this graph contains ideaNoRecompile task (that means, that this task will be executed. And if this task should be executed, then you can use a closгre to skip all the tasks, you don't want to be executed. Something like this:
task ideaNoRecompile(dependsOn:idea) {
gradle.taskGraph.whenReady { graph ->
if (graph.hasTask(ideaNoRecompile)) {
compileJava.enabled = false
compileTestJava.enabled = false
}
}
}
I've found another similar answer:
task ideaNoRecompile {
finalizedBy allprojects*.tasks*.idea
doFirst {
def skipTasks = ['compileJava', 'compileMirah', 'processResources', 'classes', 'compileTestJava', 'compileTestMirah', 'processTestResources', 'testClasses', 'jar', 'mergeProperties', 'generateModuleManifest' ] as Set
allprojects*.tasks*.each {
if (skipTasks.contains(it.name))
it.enabled = false
}
}
}

Null dependency in gradle? (workaround for lazy downloads?)

I would like to be able to write something like this:
dependencies {
myConfig computeMyDependency()
}
and I want to be able to say "there is no dependency". Returning null or an empty map doesn't work. I suppose I can return files('/dev/null'), but that is weird, hacky and not portable. Is there some sort of null dependency constructor I can use?
Some background:
What I'm really trying to do is to defer dependency download to actual execution time. It appears that if a write a task, for example a copy task like so:
task copyMyDependencyFile(type: Copy) {
from { configurations.myConfig
.grep { it.name.endsWith("zip") }
.collect() { zipTree it }
}
into targetDir
}
Then running ./gradlew tasks will actually execute the from closure, which makes me very sad. (Using Gradle 2.4)
A quick workaround might be also:
task copyMyDependencyFile << {
copy {
from {
configurations.
compile.
grep { it.name.endsWith("jar") }.
collect { zipTree it }
}
into targetDir
}
}
It should be portable.
Not sure but maybe from and into maybe configured in doLast closure of task with type Copy:
task copyMyDependencyFile(type: Copy) {
doLast {
from {
configurations.
compile.
grep { it.name.endsWith("jar") }.
collect { zipTree it }
}
into targetDir
}
}
Please try the latter yourself.

Gradle aggregation task

In my gradle scripts, I've built a task that runs a java process. This process depends on a target property. The task is defined by:
task('bulk', type: JavaExec, dependsOn: 'classes', description : 'Bulk data import on a target (defined by -Ptarget=[event|member|...]]') {
//available imports
ext{
event = relativePath('src/main/scripts/events.csv')
member = relativePath('src/main/scripts/member.csv')
membership = relativePath('src/main/scripts/membership.csv')
}
//check the target is set
doFirst {
if(!project.hasProperty('target')){
println "\nUsage:"
println "\tgradle bulk -Ptarget=[event|member|...]"
println "where target is : "
bulk.ext.each{ println it }
throw new GradleException('Target argument required')
} else {
println "\nBulk import of $target\n"
}
}
main = 'org.yajug.users.bulkimport.BulkImport'
classpath = sourceSets.main.runtimeClasspath
if(project.hasProperty('target')){
bulk{
args target
args bulk.ext[target]
debug false
}
}
}
And to run it:
gradle bulk -Ptarget=event
It's working fine, but know I have to run this process for different targets:
gradle bulk -Ptarget=event
gradle bulk -Ptarget=member
gradle bulk -Ptarget=membership
...
How can I group all these calls into an other single task with the gradle's dependency model ? (I know the list of targets)
SOLUTION
task bulk;
['event','member','membership'].each {target ->
task("bulk${target}", type: JavaExec, dependsOn: 'classes', description : "Bulk data import of ${target}s") {
//available imports
ext{
event = relativePath('src/main/scripts/events.csv')
member = relativePath('src/main/scripts/member.csv')
membership = relativePath('src/main/scripts/membership.csv')
}
//check the target is set
doFirst {
println "\nBulk import of $target\n"
}
main = 'org.yajug.users.bulkimport.BulkImport'
classpath = sourceSets.main.runtimeClasspath
args target
args ext[target]
debug false
}
bulk.dependsOn("bulk${target}")
}
How can I group all these calls into an other single task with the gradle's dependency model ?
You can't, because a task (instance) will be executed at most once per build. Instead, the way to go is to declare multiple task instances. You could do this by putting the task declaration in a loop, putting it in a method and calling it multiple times, or by writing a task class and instantiating it multiple times. Then you'll add one other task that depends on all bulk tasks. Assuming the execution order between bulk tasks is irrelevant, that's it.
By adding a helper method or two, you can create a nice little API around this, to improve readability and allow reuse in other places.
Another way to tackle this is with a task rule. You can read more on task rules in the Gradle User Guide.
What about creating a -Ptarget=all, and deal with that specific case in the build.gradle file. This could be done as:
['event','member','membership'].each { t ->
task("bulk${t}", ...) {
onlyIf project.hasProperty("target") && (project.getProperty("target").equals(t) || project.getProperty("target").equals("all"))
args target
args bulk.ext[target]
debug false
}
}

Resources