Mikhail Sidorov
Mikhail Sidorov

Reputation: 799

How to sequential execute gradle task with sh scripts inside

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

Upvotes: 1

Views: 251

Answers (1)

Stanislav
Stanislav

Reputation: 28126

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.

Upvotes: 2

Related Questions