What is the "gradle" way to write this task? (unzipping a jar)


(Phil Swenson) #1

Here is my gradle task:

task installEventTypes(dependsOn: classes) << {
    File schemaJarFile = project.configurations.testCompile.find { File file -> file.absolutePath =~ /eda-eventtypes.*schemas/ }
    if (!schemaJarFile){
        throw new Exception("eda eventtypes schema not found!")
    }
    String outputPath = "${buildDir}/eda-eventtypes"
    ant.unzip(src: schemaJarFile.absolutePath, dest:outputPath, overwrite:"true")
    println "EDA event types extracted to ${outputPath}"
}
  installEventTypes.mustRunAfter classes

I tried using the copy task like this:

task installEventTypes(type: Copy) {
    def schemaJarFile = project.configurations.testCompile.find { File file -> file.absolutePath =~ /eda-eventtypes.*schemas/ }
    def outputDir = file("${buildDir}/eda-eventtypes")
    from zipTree(schemaJarFile)
    into outputDir
}

but this didn’t work because the configurations of the project (project.configurations.testCompile) don’t exist at configuration time, so I need to do this at run time.

The other question I have is how do I only run this if there is a new dependency (right now it unzips every time even if the event types have already been extracted from the jar)

Thanks for any thoughts?


(Peter Niederwieser) #2

The common solution is to defer the evaluation of the ‘from’ value (including ‘schemaJarFile’) by wrapping it with a closure. That’s a common pattern supported by many Gradle APIs. Whether an API supports this style can be determined by checking the Gradle Build Language Reference.

One reason why task types such as ‘Copy’ should be preferred over ad-hoc solutions is that you’ll get up-to-date checks for free.


(Phil Swenson) #3

is this what you meant by “wrapping it with a closure”?

task installEventTypes(type: Copy) << {
    def schemaJarFile = project.configurations.testCompile.find { File file -> file.absolutePath =~ /eda-eventtypes.*schemas/ }
    if (!schemaJarFile) {
        throw new Exception("eda eventtypes schema not found!")
    }
    def outputDir = file("${buildDir}/eda-eventtypes")
    from zipTree(schemaJarFile)
    into outputDir
    println "EDA event types extracted to $outputPath"
  }

It doesn’t execute when I do that…


(Peter Niederwieser) #4

I mean ‘from { def schemaJarFile = …; zipTree(schemaJarFile) }’. It doesn’t execute due to the ‘<<’, which is wrong and needs to be removed.


(Phil Swenson) #5

I still don’t follow, sorry…


(Michael Brand) #6

Is this what you meant?

task installEventTypes(type: Copy) << {
    from {
        def schemaJarFile = project.configurations.testCompile.find { File file -> file.absolutePath =~ /eda-eventtypes.*schemas/ }
        if (!schemaJarFile) {
            throw new Exception("eda eventtypes schema not found!")
        }
          zipTree(schemaJarFile)
    }
    def outputDir = file("${buildDir}/eda-eventtypes")
    into outputDir
    println "EDA event types extracted to $outputPath"
}

I think the “from {…}” is really “from(Closure cl)”. Instead of executing the closure immediately, “from” stores it and evaluates it later in config cycle.


(Peter Niederwieser) #7

The ‘<<’ needs to go.


(Michael Brand) #8

Right:

task installEventTypes(type: Copy) {
    from {
        def schemaJarFile = project.configurations.testCompile.find { File file -> file.absolutePath =~ /eda-eventtypes.*schemas/ }
        if (!schemaJarFile) {
            throw new Exception("eda eventtypes schema not found!")
        }
        zipTree(schemaJarFile)
    }
    def outputDir = file("${buildDir}/eda-eventtypes")
    into outputDir
    println "EDA event types extracted to $outputPath"
}

(Phil Swenson) #9

This does work, thanks!

One prob though - I have this in my build.gradle:

classes {
    doLast {
        installEventTypes.execute()
    }
}

And with the new method calling “classes” fails:

* Where:
Build file '/Users/philswenson/dev/sag/optimize_l/modules/ae/build.gradle' line: 148
  * What went wrong:
Execution failed for task ':modules:bam-ae:classes'.
> The task artifact state cache (/Users/philswenson/dev/sag/optimize_l/.gradle/1.5/taskArtifacts) has not been locked.
  * Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
  BUILD FAILED

(Peter Niederwieser) #10

Not clear what’s going on here. However, calling ‘execute()’ on a task is discouraged and unsupported.


(Michael Brand) #11

Looks like what you want is:

classes {
    doLast {
        copy {
           from {
              def schemaJarFile = project.configurations.testCompile.find {File file ->
                   file.absolutePath =~ /eda-eventtypes.*schemas/
               }
              if (!schemaJarFile) {
                   throw new Exception("eda eventtypes schema not found!")
              }
              zipTree(schemaJarFile)
            }
         }
         into file("$buildDir/eda-eventtypes")
         logger.warn "EDA event types extracted to $outputPath"
       }
               }
}

This will copy the zip file contents after the classes task is executed. Is that what you’re looking for?


(Peter Niederwieser) #12

Better use ‘classes.dependsOn(installEventTypes)’ then. PS: Something went wrong with your ‘into’ line.


(Michael Brand) #13

Yeah, you’re quick! I was just editing to correct it. I also changed “doFirst” to “doLast” from another late night mis-read. Can “mustRunAfter” and “dependsOn” can be used together to ensure that “installEventTypes” runs after classes?

Here’s the corrected code:

classes {
    doLast {
        copy {
           from {
              def schemaJarFile = project.configurations.testCompile.find {File file ->
                   file.absolutePath =~ /eda-eventtypes.*schemas/
               }
              if (!schemaJarFile) {
                   throw new Exception("eda eventtypes schema not found!")
              }
              zipTree(schemaJarFile)
            }
            into file("$buildDir/eda-eventtypes")
            logger.warn "EDA event types extracted to $outputPath"
        }
               }
}

(Peter Niederwieser) #14

I doubt that it’s necessary for ‘installEventTypes’ to run after ‘classes’. ‘classes.dependsOn(installEventTypes)’ should do just fine. Then again, I don’t understand why one would unpack what seem to be test-related classes (‘configurations.testCompile’) as part of ‘classes’…


(Michael Brand) #15

So I guess that’s a “no” on the dependsOn/mustRunAfter reversing the order. I assume that would error out as a cyclical dependency, but I was scratching my head about that earlier today.


(Phil Swenson) #16

You are correct, Peter… I don’t really need it to run after now that I think about it. So your suggestion works nicely. BTW, the reason I’m extracting the jar is it contains a bunch of XSDs that my tests need extracted.


(Michael Brand) #17

If your tests are dependent, why not test.dependsOn(installEventTypes)? That seems more intuitive.


(Phil Swenson) #18

i want it on compile as we might want to execute tests from IDE.