Run shell command in gradle but NOT inside a task - shell

What I currently have is:
task myTask (type : Exec) {
executable "something.sh"
... (a lot of other things)
args "-t"
args ext.target
}
task doIt {
myTask.ext.target = "/tmp/foo"
myTask.execute();
myTask.ext.target = "/tmp/gee"
myTask.execute();
}
With this I thought I could run "myTask" with different parameters when I start "doIt". But only the first time the script is executed because gradle takes care that a task only runs once.
How can I rewrite the "myTask" so that I can call it more than once? It is not necessary to have it as a separate task.

You can do something like the following:
def doMyThing(String target) {
exec {
executable "something.sh"
args "-t", target
}
}
task doIt {
doLast {
doMyThing("/tmp/foo")
doMyThing("/tmp/gee")
}
}
The exec here is not a task, it's the Project.exec() method.

Related

Gradle set ext property in one task and use it in another

I have several tasks which executes different SQL scripts via psql.
task runScript1(type: Exec) {
commandLine 'cmd', '/c', "psql -f script1.sql"
}
task runScript2(type: Exec) {
commandLine 'cmd', '/c', "psql -f script2.sql"
}
Now I want to write one generic exec task and pass only the script name to it.
ext {
scriptName = ''
}
task runScriptGeneric(type: Exec) {
commandLine 'cmd', '/c', "psql -f ${scriptName}"
}
task runScript1() {
scriptName = 'script1.sql'
}
runScript1.finalizedBy runScriptGeneric
task runScript2() {
scriptName = 'script2.sql'
}
runScript2.finalizedBy runScriptGeneric
Unfortunately this approach is not working. The scriptName stays empty in the runScriptGeneric task.
I suspect this has to do with the Exec type because the following simple task working well.
ext {
scriptName = ''
}
task runScriptGeneric() {
doLast {
println "${scriptName}"
}
}
task runScript1() {
doLast {
scriptName = 'script1.sql'
}
}
runScript1.finalizedBy runScriptGeneric
task runScript2() {
doLast {
scriptName = 'script2.sql'
}
}
runScript2.finalizedBy runScriptGeneric
I do not want do pass it over as a command line parameter (-PscriptName), because I want to keep the individual tasks for each script. Is there any other way to pass the scriptName from each individual task to the generic task?
Actually, it's not an answer to my question, but it's a solution I can live with.
I've created a dynamic task instead of passing the variable to the executing script:
['Script1', 'Script2'].each {taskName ->
task "run${taskName}"(type: Exec) {
commandLine 'cmd', '/c', "psql -f ${taskName}"
}
}

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).

Gradle, task type: Exec - commandLine not work in onLast

I want execute some command from command line in gradle task(e.g. print all files in dir):
task dir(type: Exec) {
def adbCommand = ["dir", "*.*"]
commandLine adbCommand
standardOutput = new ByteArrayOutputStream()
doLast {
println ("result = " + standardOutput)
}
}
It's work. OK. But when I put it on onLast section it's not work:
task dir(type: Exec) {
doLast {
def adbCommand = ["dir", "*.*"]
commandLine adbCommand
standardOutput = new ByteArrayOutputStream()
println ("result = " + standardOutput)
}
}
I get error:
FAILURE: Build failed with an exception.
What went wrong:
Execution failed for task ':app:dir'.
execCommand == null!
The reason is in the fact, that task of Exec should be configured during configuration phase of the build, otherwise your task will be not configured and fail.
In you first example everything works due to configuration happens at the configuratyion phase. Your second example tries to configure the task within doLast closure - right after the task is executed yet.
If you really need to execute something in doLast, you can use something like this, without creating special task:
task someTaskName {
doLast {
exec {
commandLine adbCommand
}
}
}
Here is exec-specification used to execute some command and it's configured and executed at the same time.

Gradle - How to set dependency tasks for Exec-type tasks?

Say, you have following task:
task commandA() {
doLast {
project.ext.ping = 'PING'
}
}
This will work:
task commandB() {
dependsOn commandA
doLast {
println ping
}
}
This will fail:
task commandC(type: Exec) {
dependsOn commandA
commandLine "echo", ping
}
With Could not find property 'ping' on task 'commandC'. error message.
So, how one can declare dependency for an exec-type task and set some variable in that dependency?
Just don't initialize the variable within the doLast block, since it's getting initialized at the execution phase, but commandLine "echo", ping is trying to get it at the configuration phase of the build.
So, you need something like that:
task commandA() {
project.ext.ping = 'PING'
}
Or even without task, as follows:
project.ext.ping = 'PING'
Because configuration of any task is always executed, even if the task's action won't be executed.
Another solution is to use exec-action, not exec-task, something like this:
task commandA() {
doLast {
project.ext.ping = 'PING'
}
}
task commandC {
dependsOn commandA
doLast {
exec {
commandLine ping, "192.168.100.1"
}
}
}
In this case, exec-closure will be done during execution phase wuth the ping variable already available.
You can read about build lifecycle in the official Gradle user guide

Build a module with a task

I wanted to build a particular module from my project via a task, which will in turn run its tests. Basically I want to execute, "gradle :module:build" from a task.
task thatBuildsTheModule() << {
.....
}
task A() << {
......
tasks.thatBuidsTheModule.execute()
......
}
How can I do this ?
You're close. It's not recommended to call execute on a task. Instead use the task graph and make your builder task a dependant of your A task, labeled anotherTask in this example
// create builder task
task thatBuildsTheModule << {
println "Hello $it.name"
}
// create our other task
task anotherTask << {
println "Hello $it.name"
}
// make `anotherTask`'s execution depend on the execution of our builder task
anotherTask.dependsOn thatBuildsTheModule
Now we can see that executing just the anotherTask task we also execute the thatBuildsTheModule task
$ ./gradlew -q anotherTask
Hello thatBuildsTheModule
Hello anotherTask

Resources