Gradle – Copy to Multiple Destinations
Learn all about how to use Gradle, specifically copying to a slew of destinations in this neat tutorial.
Join the DZone community and get the full member experience.
Join For Freedef deployTargets = ["my/dest/ination/path/1","my/other/desti/nation"]
def zipFile = file("${buildDir}/distributions/dist.zip")
task deploy (dependsOn: distZip) {
inputs.file zipFile
deployTargets.each { outputDir ->
outputs.dir outputDir
}
doLast {
deployTargets.each { outputDir ->
copy {
from zipTree(zipFile).files
into outputDir
}
}
}
}
My specific use case is to copy the jars from a Java library distribution to Tomcat web contexts, so you can see the distZip dependency in there, along with zip file manipulation.
The multiple destination copy seems to be a bit of FAQ for Gradle newcomers like myself. Gradle has a cool copy task, and lots of options to specify how to copy multiple sources into one destination. What about copying one source into multiple destinations? There’s a fair bit of confusion around the fact that the copy task supports multiple “from” properties, but only one “into” property.
The answers I’ve found seem to fall into one of two classes. The first is to just do the copy imperatively, like so:
task justDoit << {
destinations.each { dest ->
copy {
from 'src'
to dest
}
}
}
which gives up up-to-date checking. The solution I’ve settled on fixes that by using the inputs and outputs properties. Unlike the copy task type’s “into” property, a generic task can have multiple outputs.
The other advice given is to create multiple copy tasks, one for each destination. The latter seems to be a little unsatisfactory, and un-dynamic. What if I have 100 destinations? Must I really clutter up my build script with 100 copy tasks? The following is my attempt to handle it dynamically.
def deployTargets = ["my/dest/ination/path/1","my/other/desti/nation"]
def zipFile = file("${buildDir}/distributions/dist.zip")
task deploy
// Set up a copy task for each deployment target
deployTargets.eachWithIndex { outputDir, index ->
task "deploy${index}" (type: Copy, dependsOn: distZip) {
from zipTree(zipFile).files
into outputDir
}
deploy.dependsOn tasks["deploy${index}"]
}
This one suffers from the problem that it will not execute on the same build when the zip file changes, but it will execute on the next build. So in sequence:
- Change a source file
- Run “Gradle deploy”
- Sources compile, distZip executes, zip file is produced, but deploy tasks do not execute
- Run “Gradle deploy” again
- Deploy tasks execute
Why is this so? I don’t know. This thread seems to imply that there could be some race condition in Gradle, but beyond that – *shrug*. The multiple copy task approach is recommended by a lot of smart people, so I assume there’s a better way to do it, but for now the single custom task is working for me.
Published at DZone with permission of Jaime Metcher, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments