Gradle Copy Task up-to-date determination - gradle

I'm relatively new to gradle and trying to set up a backup task. I have a few examples, first I'll describe the goal:
I have a number of files in a directory (call it the "data directory"). When the contents of Any File in this data directory are modified, I want to create a new directory in a "backup location" and copy Every File in the data directory into the directory that was just created. The name of the directory created will contain the current date and time. For now, the data directory contains no subdirectories.
I had this working fine when the "data directory" contained one file and all I wanted to do was rename that file to include the date. Example:
task copyDocs(type: Copy) {
from 'src/main/doc/testfile.html'
into 'build/target/doc'
rename { String fileName ->
def date = new Date();
date.format("YYYY-MM-dd--HH-mm-ss") + " " + fileName
}
}
This worked great. I could run the task "copyDocs" as many times as I wanted, but it would only create a new file if I had actually modified the contents of testfile.html. Now, I wanted to expand this so that instead of creating a new file that got renamed, it would create a new directory and copy the source file into it.
task copyDocs(type: Copy) {
def dateStr = (new Date()).format("YYYY-MM-dd--HH-mm-ss");
from 'src/main/doc/testfile.html'
into 'build/target/doc/' + dateStr
}
This did not work so great. While the directory that gets created has the name I wanted, the problem is that Every Time I run the task, it creates a new directory and copies testfile.html into it, regardless of whether this file was modified.
I know this has something to do with the 'task inputs' and such, and I have read the parts of the documentation that describe the initialization phase vs. the configuration phase and so on. What I have not found is anything specific enough to help me understand why the copy task believes it needs to be re-run in the second case but not in the first case.
Simply put, in both cases, the potential output file(s) change every time the task is run as a function of the date/time. The input file(s) Do Not Change in the case of either task. So why does the second task need to be re-run every time, but not the first task? Is there a straightforward way to "debug" gradle so that it explicitly tells me why this is?
Your time and help are greatly appreciated, I am interested in learning more about gradle as it seems like an effective and modern build system!

When it comes to copy task whether it will be executed is determined by task's inputs and outputs which are set during configuration phase (see here). Since at configuration phase output is different every time:
into 'build/target/doc/' + dateStr
(it depends on seconds, but if you trim to hours, days, months the effect will be the same but rarer) the file is copied every time the task is executed even though it hasn't changed. To fix the problem you need to alter the destination at the execution time which can be done in the following way:
task copyDocs(type: Copy) {
def dest = 'build/target/doc/'
from 'src/main/doc/testfile.html'
into dest
eachFile { fcp ->
def dateStr = (new Date()).format("YYYY-MM-dd--HH-mm-ss");
fcp.path = dest + dateStr
}
}
This way task will be executed if and only if from input differs.

Related

How can I create a task in Gradle that depends on all files in a directory?

I have a directory, let's call it inputs. I need to create a task that will:
read in all of the files in the inputs directory, ie: inputs/*.
produce a new file somewhere else that combines these files in some way. (For the sake of example, you can assume I just want to concatenate all of the files into a single output file.)
How do I set up the task correctly such that the following requirements are met?
requesting the task a second time when nothing has changed doesn't execute the task ("Already up to date").
adding, editing, or deleting files in the inputs directory causes the task to be "out of date", and so requesting it after any of those has happened will cause it to re-execute.

Create a directory structure from a path in gradle/groovy

I am implementing a diff package generation task in my project's gradle build from the git command line output. Currently I have a method which will give me a list of changed files from git diff --name-only. What I would like to do is create a directory structure in a new directory which matches the paths of each file. For example: inputting the string repo/dir/file.java would create in an output directory if not already created and inside it the directories head/repo/dir with the current file.java and prev/repo/dir with the previous file.java.
My current plan is to split the string repo/dir/file.java on the forward slash, and create directories until the last element of the split result, then write the file there. but nothing I have been able to come up with in gradle is nice or clean. I am wondering if there is a nicer way to create directories from a string like that.
My current plan is to split the string repo/dir/file.java on the forward slash, and create directories until the last element of the split result
Rather than splitting your string manually, you could try using File.mkdirs():
File newDirectoryStructureParent = new File('some/path/to/parent/dir')
def s = 'repo/dir/file.java'
def newContainer = new File(s, newDirectoryStructureParent).getParent()
newContainer.mkdirs()
everyone
In this part of my code you can just work around Path not File!
At the first you can define Path and second need check that path exist or not, if not mkdirs can make it ;)
Its help when you unknown about that path exist or not /
File fullPath = new File('/tmp/Test1')
if (!fullPath.exists())
fullPath.mkdirs()

Gradle copy task isn't overwriting file

I've got the following task:
preBuild.dependsOn "copyConfigFile"
task copyConfigFile(type: Copy) {
from 'ConfigSources/VersionInfo.java'
into 'src/main/java/com/company/gradleexperiments/'
expand([changeset: "12345",
changeset_time: "the time",
changeset_date : "the date"])
}
Its works as expected except after the file has been initially copied, if I change one of the values in the expand and build again, then the file is not being overwritten (the creation timestamp of the file in the target destination remains that last time it was built).
I did some googling and searching of past questions on this topic, however the answer I got was that the gradle copy task is by default always supposed to overwrite the file. If that is the case, then why is it not doing so for me?
This is a very old bug: the copy task doesn't consider the values passed to expand as inputs, and thus considers it's up-to-date even though these values have changed.
You can vote on this issue here.
This should be relatively easy to circumvent by adding the expanded values to the input explicitely. For example:
task copyConfigFile(type: Copy) {
from 'ConfigSources/VersionInfo.java'
into 'src/main/java/com/company/gradleexperiments/'
def values =
['changeset': '12345',
'changeset_time': 'the time',
'changeset_date': 'the date'];
inputs.properties(values);
expand(values);
}

How to remove an element from gradle task outputs?

is it possible to exclude an element from the output files of a Task in order to not consider it for the up-to-date check? In my case I have a copy task that automatically set the destination directory in outputs variable, but I'd like to remove it and set only some of the copied files.
Or, as alternative, is it possible to overwrite the entire outputs variable?
Thanks,
Michele.
Incremental tasks create snapshots from input and output files of a task. If these snapshots are the same for two task executions (based on the hash code of file content), then Gradle assumes that task is up-to-date.
You are not able to remove some files from output and expect Gradle to forget about them, simply because the hash codes will be different.
There is an option that allows you to manually define the logic of up-to-date checks.
You should use a method upToDateWhen(Closure upToDateClosure) in TaskOutputs class.
task myTask {
outputs.dir files('/home/user/test')
outputs.upToDateWhen {
// your logic here
return true; // always up-to-date
}
}
I've found the solution:
task reduceZip(type: Copy) {
outputs.files.setFrom(file("C:/temp/unzip/test.properties"))
outputs.file(file("C:/temp/unzip/test.txt"))
from zipTree("C:/temp/temp.zip")
into "C:/temp/unzip"
}
Outputs.files list could be modified only register new elements, not removing (for what I know). So I need to reset the list and then eventually add other files. The outputs.files.setFrom method reset the outputs.files list so it is possible add other file. In the example above I reduce the up-to-date check only to the test.properties and test.txt files.

How can we remove the current date from gradle generated .html and .xml file while running JMeter script from build.gradle file?

I am running my JMeter script from build.gradle file. After executing it is generating the html and xml report files with the script name. My problem is that current date is also present with the script name. Please tell me how to remove the current date from output files.
Gradle- gradle-2.4 version and HTML Report Publisher plugin in Jenkins
I'm assuming you're using com.github.kulya/jmeter-gradle-plugin ?
The date is tacked on to testplan name while generating results, which is then used while generating reports. The intention I believe is so that the results are not overwritten each time you run a test. The way it is currently implemented, it isn't configurable.
If you have only one set of result and report per jmx file, You should be able to define a new task though to strip out the date/timestamp from the results and report files.
task stripDateFromReport() {
new File("build/jmeter-report").eachFileMatch(~/.*.[xml|html]/){ file ->
def m = file.getName() =~ /^(.*?)-[0-9]{8}-[0-9]{4}(.*?)$/
file.renameTo(new File(file.getParentFile().getCanonicalPath()+ File.separator + m[0][1] + m[0][2]))
}
}
Note: If you have more than one report with just a different timestamp, this will obviously fail because once the dates are removed the filenames are not unique anymore.

Resources