Gradle copy task not copying files from temp folder first time around - gradle

I've a build file that runs tasks like this.
Task 1 (unpackWar): Unzips war file to Temp folder
Task 2 (copyWarFilesToWebContent): Copies the files to WebContent folder with some exclusions
Task 3 (copyRequiredJarFilesToWebContent): Unzips a couple of jar files from Temp/WEB-INF/lib to TempJarDir
Task 4 (explodeProductJars): Copies files we want from TempJarDir to WebContent folder
There is a single prepare task that runs each of these tasks using dependsOn and I've added mustRunAfter commands to each of the tasks so they execute in order. Also set upToDateWhen = false for each task.
What seems to happen is that Task 1 runs fine and unzips the war. Task 2 then uses the files from Temp and adds the required ones to WebContent correctly.
Task 3 and Task 4 are always coming back as Up To Date because seemingly there are no files to work with in the directory specified.
If I re-run prepare when the Temp folder exists, Task 3 and 4 run correctly.
I'm not sure if this is due to how fileTree works or if I'm doing something wrong. I've picked up gradle about a week ago and am still getting to grips with it.
Tasks look like this:
task prepare(dependsOn: ['unpackWar', 'copyWarFilesToWebContent', 'copyRequiredJarFilesToWebContent'])
prepare.outputs.upToDateWhen {false}
task unpackWar(type: Copy) {
description = 'unzips the war'
outputs.upToDateWhen { false }
def warFile = file(warFileLocation)
from zipTree(warFile)
into "Temp"
}
task copyWarFilesToWebContent(type: Copy) {
mustRunAfter unpackWar
description = 'Moves files from Temp to WebContent Folder'
outputs.upToDateWhen { false }
from ('Temp') {
exclude "**/*.class"
}
into 'WebContent'
}
task explodeProductJars(type: Copy) {
outputs.upToDateWhen { false }
FileTree tree = fileTree(dir: 'Temp/WEB-INF/lib', includes: ['application*-SNAPSHOT-resources.jar', 'services*-SNAPSHOT-resources.jar'])
tree.each {File file ->
from zipTree(file)
into "TempJarDir"
}
}
task copyRequiredJarFilesToWebContent(type: Copy, dependsOn: explodeProductJars) {
mustRunAfter copyWarFilesToWebContent
outputs.upToDateWhen { false }
from ("TempJarDir/META-INF/resources") {
include '**/*.xml'
}
into "WebContent/WEB-INF"
}
I've a feeling its something to do with fileTree but not sure whats happening exactly.

The Copy task is tricky. A Copy task will only be executed when it finds something to copy in the configuration phase. If it does not find anything during that phase it will be skipped.
You could use the copy method instead of the Copy task.
prepare( dependsOn: 'copyRequiredJarFilesToWebContent' ) {}
task unpackWar( type: Copy ) {
def warFile = file( warFileLocation )
from zipTree( warFile )
into 'Temp'
}
task copyWarFilesToWebContent( dependsOn: unpackWar ) << {
copy {
from ( 'Temp' ) {
exclude '**/*.class'
}
into 'WebContent'
}
}
task explodeProductJars( dependsOn: copyWarFilesToWebContent ) << {
copy {
FileTree tree = fileTree( dir: 'Temp/WEB-INF/lib', includes: [ 'application*-SNAPSHOT-resources.jar', 'services*-SNAPSHOT-resources.jar' ] )
tree.each { File file ->
from zipTree( file )
into 'TempJarDir'
}
}
}
task copyRequiredJarFilesToWebContent( dependsOn: explodeProductJars ) << {
copy {
from ( 'TempJarDir/META-INF/resources' ) {
include '**/*.xml'
}
into 'WebContent/WEB-INF'
}
}

Related

Gradle Copy Task Is UP-TO-DATE After Manually Deleting a File

I am forced to use Gradle 2.3 in this project.
I am trying to copy a set of dependencies from a custom configuration to a specific dir.
If I delete one of the files manually, Gradle still marks the task as UP-TO-DATE and I end up with an incomplete set of files.
task copyFiles(type: Copy) {
from configurations.zips
into 'zip-dir'
configurations.zips.allDependencies.each {
rename "-${it.version}", ''
}
}
This works as expected in v4.0.2 though.
To work around it I am counting files in that dir.
task copyFiles(type: Copy) {
outputs.upToDateWhen {
def count = new File('zip-dir').listFiles().count { it.name ==~ /.*zip/ }
count == configurations.zips.files.size()
}
from configurations.zips
into 'zip-dir'
configurations.zips.allDependencies.each {
rename "-${it.version}", ''
}
}
Which issue and version of gradle was this fixed in and is there a better workaround than what I have so far?
You can just run it always with
outputs.upToDateWhen { false }
or not use a type Copy for your task and
task copyFiles {
doLast {
copy {
from configurations.zips
into 'zip-dir'
configurations.zips.allDependencies.each {
rename "-${it.version}", ''
}
}
}
}
Note that this is a workaround not the solution

gradle - create jar iteratively under a certain directory

I am trying to create multiple jars. I have a certain directory which contains multiple directory. Each directory has its own files(xml and sql). So I am trying to create a jar with a subdirectory name and all the files in it. Those jars will be used for junit test, so I want to create it during configuration phase in advance.
The target directory "../dist" exists outside this project.
ext.createTemplateJar = { sourceDirectory, jarFileName ->
jar {
archiveName = jarFileName
from sourceDirectory
includeEmptyDirs = false
manifest
{
attributes 'Implementation-Title' : VENDOR_NAME
}
}
println "creating a jar for ${jarFileName}"
}
tasks.withType(Jar) {
destinationDir = file("../dist")
}
task generateTemplates {
new File("${projectDir}/templates").eachFile() { file ->
if (file.isFile()) {
return
}
println "template dir is ${file.path}"
createTemplateJar(file.path, "${file.name}.jar")
}
}
When I execute this gradle generateTemplates, it runs fine, but I don't see any jar files created in the destination directory.
It seems something wrong, but I can't tell.
You should create multiple Jar tasks, one for each subdirectory inside ${projectDir}/templates, and have your generateTemplates task do nothing but depend on all of those tasks. For example (I renamed generateTemplates to allJars):
task allJars {
}
file("${projectDir}/templates").eachFile { f ->
def taskName = "jar${f.name.capitalize()}"
tasks.create(name: taskName, type: Jar) {
archiveName = "${f.name}.jar"
destinationDir = file('../dist')
// Configure each JAR however you want
}
allJars.dependsOn taskName
}
Example build:
$ ls templates/
bar baz foo test
$ ./gradlew clean allJars
:clean
:jarBar
:jarBaz
:jarFoo
:jarTest
:allJars
BUILD SUCCESSFUL
Total time: 0.615 secs
$ ls ../dist/
bar.jar baz.jar foo.jar test.jar

Execute one gradle task

I've this two tasks:
war {
webInf { from 'src/main/resources/WEB-INF' }
manifest {
attributes 'Implementation-Version': versioning.info.display
}
}
task createDemoWar(type: War, dependsOn: classes) {
archiveName "webapi-demo-${versioning.info.display}.war"
destinationDir = file("$buildDir/dist")
copy {
from 'scopes'
include 'configuration.demo.properties'
into 'src/main/resources/'
}
}
task createDevelopmentWar(type: War, dependsOn: classes) {
archiveName "webapi-dev-${versioning.info.display}.war"
destinationDir = file("$buildDir/dist")
copy {
from 'scopes/'
include 'configuration.development.properties'
into 'src/main/resources/'
}
}
Both tasks are trying to copy a property file fromscopes folder to src/main/resources/ folder.
I only run one task, however two files are copied in src/main/resources/ (configuration.demo.properties and configuration.development,properties.
Any ideas?
You use two copy specifications at the configuration phase (note, copy specification in that case doesn't configure your task, but add some extra action to it's configuration). That means, your files are getting copied during configuration. That's all because of this:
copy {
...
}
You have to run it during execution, to do that, try to move it into the doLast or doFirst closure, like so (for both tasks):
task createDemoWar(type: War, dependsOn: classes) {
archiveName "webapi-demo-${versioning.info.display}.war"
destinationDir = file("$buildDir/dist")
doFirst {
copy {
from 'scopes'
include 'configuration.demo.properties'
into 'src/main/resources/'
}
}
}
In that case, files will be copied only if task will be executed, right before the execution.

Gradle: Not able to run zipTree in doFirst block

I am trying to explode some jar files in a doFirst block as follows -
task copyBinaries(type: Copy){
def Jar1 = ""
def Jar2 = ""
def Jar3 = ""
doFirst {
Jar1 = configurations.Lib1.singleFile
Jar2 = configurations.Lib2.singleFile
Jar3 = configurations.Lib3.singleFile
}
inputs.files configurations.Lib1
inputs.files configurations.Lib2
inputs.files configurations.Lib3
from(zipTree(file(Jar1))) {
into('jar_folder1')
}
from(zipTree(file(Jar2))) {
into('jar_folder2')
}
from(zipTree(file(Jar3))) {
into('jar_folder3')
}
into('build/libs/')
}
}
In order the avoid resolution of dependencies in the configuration phase, I am extracting the file names from the configurations in the doFirst block. The problem is, since the Copy task needs the source and destination of copy during configuration phase, gradle sees Jar1, Jar2, Jar3 as empty strings and throws and error.
I am looking for a way to let the Copy task receive arguments (source file) during execution phase (after doFirst block is executed).
How can I address this situation? Thanks.
I've had a similar situation where I had to copy from a path that was created as output of another one.
I solved this with just declaring the copy logic in my task's doLast block:
task copyStuff {
doLast {
copy {
from zipTree('path/to/archive')
into 'destination/dir'
}
}
}
You just have to make sure, that your task runs after the task that creates the needed outputs with using dependsOn for example.

Change copy task destination

I would like to change the destination dir for file copy depending on the chosen build.
This does not work since the task graph is executed in execution phase but the copyTask is set in configuration phase.
How can I achieve this?
gradle.taskGraph.whenReady { taskGraph ->
println('taskGraph')
if (taskGraph.hasTask(buildRelease)){
File toDir=file('test/r')
println('Copy to: ' + toDir.getName())
}else if (taskGraph.hasTask(buildDevel)) {
File toDir=file('test/d')
println('Copy to: ' + toDir.getName())
}
}
task buildDevel (dependsOn: ['copyTask']){}
task buildRelease (dependsOn: ['copyTask']){}
task copyTask(type: Copy) {
from "test"
into toDir
include 'a.txt'
}
This may help You (You need to create a.txt file on the same level as build.gradle is located:
gradle.taskGraph.whenReady { taskGraph ->
def cp = project.copyTask
if (taskGraph.hasTask(buildRelease)){
cp.into 'lol1'
} else if (taskGraph.hasTask(buildDevel)) {
cp.into 'lol2'
}
}
task buildDevel (dependsOn: ['copyTask']){}
task buildRelease (dependsOn: ['copyTask']){}
task copyTask(type: Copy) {
from file('.')
include 'a.txt'
}
This will also work:
task buildDevel
task buildRelease
buildDevel.doFirst {
cp('lol1')
}
buildRelease.doFirst {
cp('lol2')
}
def cp(to) {
copy {
from file('.')
into to
include 'a.txt'
}
}

Resources