Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gradle task: how to wait for the file operation to complete

Here's what I'm trying to do:

  1. Copy archive (zip) from buildscript dependencies to the temp directory
  2. Unzip archive to another directory within build

Here's task to copy archive (works)

task copyTpcds(type: Copy) {  
    file('build/zip').mkdirs()
    from buildscript.configurations.classpath
    include 'tpcds*'
    into 'build/zip'
}

And the task to unzip and then delete archive

task extractTpcds(type: Copy) {  
    def names = new FileNameFinder().getFileNames('build/zip', 'tpcds*')
    def outDir = file('build/cmd/tpcds')
    outDir.mkdirs() // make sure the directory exists
    from zipTree(file(names[0])) // generates error when 
    into outDir
    // now remove copied zip file
    //zipFile.delete() // deletes file before the extractions completes?
}

Here are few scenarios:

  1. If I put both tasks into build.gradle and try to run anything, even just gradle tasks then I get this error: Neither path nor baseDir may be null or empty string. path='null' basedir='C:\dev\code\td\pdo\tpcds-tpg' from this code in the task #2: file(names[0])
  2. If I comment out code in the 2nd task, 1st task would run and copy zip file to build/zip
  3. Now I can uncomment code in the 2nd task (except deletion) and execute gradle extractTpcds it will run and extract the archive

So it seems to me that

  1. File operations are evaluated across all tasks regardless of which tasks is executed
  2. If I have a code that copies the file with some follow up code that tries to operate on the file being copied then that code will not wait for copy process to complete and will fail because file is not there yet

I'm at loss on how to deal with this and would greatly appreciate your suggestions

like image 508
Bostone Avatar asked Oct 13 '25 04:10

Bostone


1 Answers

The following works for me, using Gradle 2.12 (and assuming that the zip file resides in files):

buildscript {
    configurations {
        classpath
    }

    dependencies {
        classpath files("files/tpcds.zip")
    }
}

def copyFiles = { ->
    ant.mkdir(dir: "build/zip")
    buildscript.configurations.classpath.each { def thisFile ->
        if (thisFile.name ==~ /tpcds.*/) {
            ant.copy(file: thisFile.absolutePath, todir: "build/zip")
        }
    }
}

tasks.whenTaskAdded { task ->
    if (task.name == "extractTpcds") {
        copyFiles()
    }
}

task copyTpcds << {  
    copyFiles()
}

task extractTpcds(type: Copy) {  
    def names = new FileNameFinder().getFileNames('build/zip', 'tpcds*')
    def outDir = file('build/cmd/tpcds')
    outDir.mkdirs() // make sure the directory exists
    from zipTree(file(names[0])) // generates error when 
    into outDir
    // now remove copied zip file
    //zipFile.delete() // deletes file before the extractions completes?
}

An issue with the original involves an impedance mismatch vis-a-vis the ICE rule: Initialization phase, Configuration phase, and Execution phase. In particular, the specification of the Copy task is in Configuration phase; typically, task dependencies are enforced (e.g. dependsOn) during the Execution phase. The extractTpcds task has a dependency on other code during the Configuration phase.

In my example, there are are 2 cases:

  • gradle copyTpcds will call the copyFiles method during Execution phase. The << means "do this stuff last [during the Execution phase]".
  • gradle tasks will trigger the code in whenTaskAdded, during Configuration phase, and call copyFiles. Similarly for gradle extractTpcds

An alternative to this is simply to use the AntBuilder in both tasks, and avoid Type: Copy completely, as shown here:

buildscript {
    configurations {
        classpath
    }
    dependencies {
        classpath files("files/tpcds.zip")
    }
}

task copyTpcds << {  
    ant.mkdir(dir: "build/zip")
    buildscript.configurations.classpath.each { def thisFile ->
        if (thisFile.name ==~ /tpcds.*/) {
            ant.copy(file: thisFile.absolutePath, todir: "build/zip")
        }
    }
}

task extractTpcds(dependsOn: 'copyTpcds') << {  
    def outDir = "build/cmd/tpcds"
    ant.mkdir(dir: outDir)
    def names = new FileNameFinder().getFileNames('build/zip', 'tpcds*')
    names.eachWithIndex { zipFile, index ->
        if (index == 0) {
            ant.unzip(src: zipFile, dest: outDir)
        }
    }
}
like image 196
Michael Easter Avatar answered Oct 15 '25 11:10

Michael Easter