I have 2 gradle task, one depends on the other.
The first task get db dump from remote server using sh script. The second task parse dump from previous task.
The problem is that second task starts early than dump script from the first task finishes. So there is no file yet, when second task start to work.
Tasks:
task getDumpFromRemotePostgres(type: Exec) {
executable = "/bin/sh"
println 'started task getDumpFromRemotePostgres'
def dumpScript = './createSqliteDb/scripts/dump_db_script.sh'
def dbDumpFileName = 'dump.sql'
args += [dumpScript]
println 'finished task getDumpFromRemotePostgres'
}
task patchPostgresDumpFile(type: Exec) {
dependsOn getDumpFromRemotePostgres
executable = "/bin/sh"
println 'started task patchPostgresDumpFile'
def dbDumpFileName = 'dump.sql'
File dumpFile = file(dbDumpFileName)
def line
dumpFile.withReader { reader ->
while ((line = reader.readLine()) != null) {
//parse and modify
}
println 'finished task patchPostgresDumpFile'
}
Script dump_db_script.sh:
echo "dump script started"
pg_dump --data-only --inserts --dbname=postgresql://user:pas#server/base_name > dump.sql
echo "dump script finished"
Console log is the follow (if i delete access file lines):
started task getDumpFromRemotePostgres
finished task getDumpFromRemotePostgres
started task patchPostgresDumpFile
finished task patchPostgresDumpFile
> Task :getDumpFromRemotePostgres
dump script started
dump script finished
Is any idea how to solve the problem?
Tried with doLast{ ... } but came to nothing
It seems, it's all due to the different lifecycle phases. You can read more about it here.
First of all, when you createe a task of type Exec or any kind without <<, everything in it's body is a task configuration and is getting executed at the configuration pahse of the build. That's why you have messages like started task getDumpFromRemotePostgres first in your output.
The second thing is that an executable you are running, is executed at the execution phase, after all task's configuration is done already. And that is why dump script started appears after all the configurations are done.
In your case, you don't need to declare a patchPostgresDumpFile as an Exec task, because you don't actually call any executable, but need to run some logic. For that, you have to move this logic to the doLast closure, to run it in the execution phase. Something like this:
task patchPostgresDumpFile() {
dependsOn getDumpFromRemotePostgres
doLast {
println 'started task patchPostgresDumpFile'
def dbDumpFileName = 'dump.sql'
File dumpFile = file(dbDumpFileName)
def line
dumpFile.withReader { reader ->
while ((line = reader.readLine()) != null) {
//parse and modify
}
println 'finished task patchPostgresDumpFile'
}
}
And note, that your message started task getDumpFromRemotePostgres doesn't actually mean that this task is running, but that it's configuring. If you want to have a messages before and after the execution, move them into the doFirst and doLast closures within a task configuration closure.
Related
I have the following simple task in my build:
task generateFile << {
def file = new File("$buildDir/setclasspath.sh")
file.text = "sample"
outputs.file(file)
}
task createDistro(type: Zip, dependsOn: ['copyDependencies','packageEnvironments','jar', 'generateFile']) <<{
from generateClasspathScript {
fileMode = 0755
into 'bin'
}
}
When I run gradle clean build I see the following output:
Cannot call TaskOutputs.file(Object) on task ':generateFile' after task has started execution. Check the configuration of task ':generateFile' as you may have misused '<<' at task declaration
How do I declare the task file creation outputs as an input to the zip task while also ensuring they happen in the execution phase?
If I leave off the << then the clean task wipes the generated file before the ZIP can use it. If I keep them, I get the above error.
It's the opposite as what is being suggested in the comments. You are trying to set the outputs in execution phase. The correct way to do what you are probably trying to do is for example:
task generateFile {
def file = new File("$buildDir/setclasspath.sh")
outputs.file(file)
doLast {
file.text = "sample"
}
}
What is the difference between these two tasks. Only task with << in its definition is shown in the output of ./gradlew tasks.
task greet(type: GreetingToFileTask) {
destination = { project.greetingFile }
}
task sayGreeting(dependsOn: greet) << {
println file(greetingFile).text
}
The lines above are from gradle documentation Here
The << is a shortcut to the toLast configuration item of a task definition. I.e. the following two declarations are equivalent:
task hello << {
println 'Hello world!'
}
and:
task hello {
doLast {
println 'Hello world!'
}
}
(example taken from Gradle documentation here).
Now, in the first code snippet you just define a task and configuring its destination property. However, the task will only be executed if needed.
In the second code snippet, however, you are actually defining an action that will always be executed during the configuration phase, regardless of the tasks targeted for execution (cite from here):
A task has both configuration and actions. When using the <<, you are
simply using a shortcut to define an action. Code defined in the
configuration section of your task will get executed during the
configuration phase of the build regardless of what task was targeted.
Can a gradle task depend on the failure of another task?
For example, I have an auxillary task that opens the test report in a browser. I want the report to only appear when the task "test" fails, not when all tests pass as it does now.
task viewTestReport(dependsOn: 'test') << {
def testReport = project.testReportDir.toString() + "/index.html"
"powershell ii \"$testReport\"".execute()
}
You can try to set task's finilizedBy property, like:
task taskX << {
throw new GradleException('This task fails!');
}
task taskY << {
if (taskX.state.failure != null) {
//here is what shoud be executed if taskX fails
println 'taskX was failed!'
}
}
taskX.finalizedBy taskY
You can find the explanation gradle's user guide in chapter 14.11 "Finalizer tasks". Shortly, due to docs:
Finalizer tasks will be executed even if the finalized task fails.
So, you just have to check the state of the finilized task with TaskState and if it was failed, do what you wanted.
Update:
Unfortunately, because configuration is always executed for all tasks, seems not possible to create some custom task to set the flag to show report within script. On execution phase it is not possible too, because the task will not be called if previewsly runned task has failed. But you can do, what you wanted, providing the build script arguments, like:
task viewTestReport << {
if (project.hasProperty("showReport") && test.state.failure != null) {
//here is what shoud be executed on taskX fail
println 'test was failed!'
}
}
test.finalizedBy(viewTestReport)
In that case, you have to provide -PshowReport arguments, while you call any gradle task, if ou want to get the report in test task fail. For example, if you call:
gradle test -PshowReport
then report will be shown if test task fails, but if you call it:
gradle test
no report will be shown in any case.
I have a very simple build script like so
task hello{
println("hello World")
}
task bye {
println("bye")
}
On the command line I run
gradle hello and I get the following output:
hello World
bye
:hello UP-TO-DATE
Why is it executing the task "bye" (I'm assuming it gets executed since "bye" gets printed)? Thanks.
It's a common pitfall:
task hello {
println("Any code in here is about *configuring* the\
task. By default, all tasks always get configured.")
doLast {
println("Any code in here is about *executing* the task.\
This code only gets run if and when Gradle decides to execute the task.")
}
}
The distinction between configuration phase and execution phase is probably the single most important concept to understand in Gradle. It can be confusing at first, and may go away in the future. A kind of analogue in the Ant/Maven world is that these tools first parse XML build scripts and build an object model (perhaps resolving some properties along the way), and only then execute the build.
Adding to Peter answer, If you want to execute all task , you can specify the defaultTasks list.
defaultTasks 'clean', 'run'
task clean {
doLast {
println 'Default Cleaning!'
}
}
task run {
doLast {
println 'Default Running!'
}
}
task other {
doLast {
println "I'm not a default task!"
}
}
Output
Output of gradle -q
> gradle -q
Default Cleaning!
Default Running!
More details can be found here
https://docs.gradle.org/current/userguide/tutorial_using_tasks.html
I'm trying to write a task rule to create a series of tasks that checkout various svn repository locations. Here is my rule:
tasks.addRule("Pattern: svnCheckout<Classifier> - Checks out the indicated svn repo") { String taskName ->
if(taskName.startsWith('svnCheckout')) {
task(name: taskName, type: Exec) {
String classifier = taskName - 'svnCheckout'
String svnDir = svnRepoUrl //defined elsewhere
switch(classifier) {
case 'SourceTrunk':
svnDir += 'branches/CleanBuild/trunk'
break
case 'AutoInstaller':
svnDir += 'Tools/AutoInstaller'
break
case 'ContentAutomation':
svnDir += 'Tools/ContentAutomation'
break
case 'InternalTools':
svnDir += 'Tools/Internal'
break
default:
throw new GradleException("Invalid svnCheckout classifier '$classifier'")
}
String svnCommand = "svn co $svnDir --trust-server-cert"
//commandLine 'cmd', '/c', "$svnCommand"
commandLine 'cmd', '/c/', "echo 'Task created'"
workingDir = "$workspace"
}
}
}
I then try to run the task 'svnCheckoutSourceTrunk' with this command:
gradlew -Pworkspace="." svnCheckoutSourceTrunk
which fails with the error
FAILURE: Could not determine which tasks to execute.
* What went wrong:
Task 'svnCheckoutSourceTrunk' not found in root project 'GradleScripts'.
* Try:
Run gradlew tasks to get a list of available tasks.
BUILD FAILED
Anyone see what I'm doing wrong? I put some println statements around the first few lines, and the execution is getting past the if statement, but it's not getting inside the task declaration.
The syntax used for declaring the task(s) is incorrect. (Not sure why it's not giving an error.) The first positional argument always need to be the task name:
task(taskName, type: Exec) { ... }
In a build script, this will also work:
task "$taskName"(type: Exec) { ... }