Now, this is working fine as expected. Both of my requirements are met, however I feel like there is a better way of doing this. I took out several copy blocks to make the code shorter in this post. Is there a way I could use a single statement for copying same file/directory into multiple location. According to following documentation, it seems “into()” method can only accept a single distination path.
Also, at first in this task, I started using just copy statement (i.e. without using copy {} block), but that way it seems only the very last statement gets excuted. Not all of them. So, I tried it this way, which seems to perform ALL of the copy statements.
There is a very distinct difference between with and without the ‘copy {…}’ blocks. Those blocks are actually calls to ‘Project.copy()’, which in turn performs the copy at the time that line is evaluated. In this case, that is configuration time. What this means, is by using ‘copy {…}’ you are actually performing the copy operation during the evaluation of the build script, not when the ‘copySpecFiles’ task actually executes.
I believe the problem you were seeing without using that method was due to some missing curly braces. Instead of creating child 'CopySpec’s, you were simply overriding the root spec by calling ‘into()’ over and over again.
The following seems to work fine, but it has the same effect that I ran into originally. Subsequent from methods causes only the last block/statement to be executed.
from('srcDir') {
rename...
} into (destDir + myScriptDir)
Hmm… Interesting… Didn’t realize I could do that!!
Thanks Mark. Although this is perfect in my case at the moment, I’m wondering how would I copy to multiple distinations that doesn’t have same root destination? Am I stuck with creating different task?
Also, I’m still required to have different “from() {}” block for each copy action. I guess I was looking for a map/list I could provide to the “into()” method that will perform the copy action to all of them. Something like this:
If you want to copy to multiple destinations you could simply call ‘into()’ with a common parent directory (perhaps ‘project.buildDir’) and use child copy specs to configure all the different copy actions.
You can’t copy a single source to multiple destinations with a single copy spec. You’ll have to duplicate that, or alternatively, place that configuration in some kind of loop.
I’m revisiting this task and trying to rewrite it using tasks inputs and outputs property.
Let’s say, I have a task with inputs and outputs configured and that tasks name is “createFile”
Now, I’m trying to rewrite this same task (let’s call it, copySpecFiles) in the same manner, but I’m not sure how to iterate over the output of the task named “createFile”. Here’s what I’m doing (or trying so far):
task copySpecFile {
inputs.dir(createFile) //output of createFile will be input for this task
ext.destDir = new File(specFileRepo, 'newSpecs')
outputs.dir(destDir) //output location of this task
//here's where I'm getting stuck
//how do I iterate over inputs.dir and copy them into different destinations but in the same root directory
// specified by the outputs directory?
//below is just my pseduo code that will iterate over each files in the input directory
//and copy it to certain destination based on filename
inputs.dir.files.each { specs->
copy {
from specs
rename "specs.txt"
if(specs.name contains "windows")
into "windows"
if(specs.name contains "linux")
into "linux"
}
into destDir
}
}
Am I approaching this incorrectly?
If you want to leverage inputs and outputs here the best way would be to use a ‘Copy’ task, which will handle all that for you. If you need to do several separate copy actions into different destination directors then I would suggest simply creating multiple tasks.
Thanks Mark. I just realized I had a typo in my code example. Actually I was already using Copy type task.
Right now I’m trying to perform conditional copy. Do I still need multiple task for that? Here’s what I’ve done so far:
task copyFile(type: Copy) {
inputs.dir(createFile) // outputs of createFile task
ext.destDir = new File(scriptSourceDir, '')
outputs.dir(destDir)
inputs.files.each{ propFile->
if(propFile.name.toLowerCase().startsWith("aix7")){
//println "copying $propFile.name into $scriptAix64"
from propFile
into "$scriptSourceDir/$scriptAix64"
}
else if(propFile.name.toLowerCase().startsWith("win12")) {
from propFile
into "$scriptSourceDir/$scriptWin12"
}
else if(propFile.name.toLowerCase().startsWith("xlinux64")) {
from propFile
into "$scriptSourceDir/$scriptLinux64"
}
}
}
The problem here is that the conditions are not working as expected. I’m getting inconsistent result. The source files get copied into a single directory and the destination seems to be different directory at different times instead of being copied to corresponding directories based on the conditions.
Shouldn’t this task treat each copy action separately since it’s being done by iterating over individual files?
No, a copy task can only have a single root destination. If you want to copy to multiple destinations you’ll have to either a) have multiple copy tasks or b) copy to directories under a common root directory. In this case, that directory could be ‘scriptSourceDir’.
Also you don’t need to specify inputs and outputs for a ‘Copy’ task, that is done when you configure the copy spec. You’ll eventually want to end up with something like this:
Interesting… I thought I tried it that way too. I might have had a typo/mistake (i.e. the common root was probably after all the conditions instead of after the closure of files.each.
Anyways, I just tried it following your example and it still didn’t work for me. I don’t get any error message. Only output I get is “:copyFile UP-TO-DATE”. Actual copy operation doesn’t take place.
In the meantime, I had started creating multiple tasks for each destinations. It works, but I’m wondering if you’d be able to tell me how to improve on it. Here’s what I have:
I understand I don’t need to define inputs and outputs. I’ll take them out of those copy tasks later. Hopefully I’ll still be able to take advantage of “up-to-date” mechanism. The only thing I’m seeing here is in each copy tasks, I’m iterating over “Every” output files generated by createFile task.
I can’t think of any other way around it, but since I’m still new at Gradle, thought I’d ask if I can make any improvements over what I have right now.
I’m having a little bit of issue with dependency declaration, but I create a separate thread for that. For now, it’s working as is.
My only other thought is that it isn’t working because the outputs of the ‘createFile’ task don’t exist yet? It may depend on how you are declaring the output on that task.