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

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.

Related

Delete all files except those with a specific extension in VBS [duplicate]

I'm making a project out of creating a script to use at work to automate one of our processes.
I'd like the script to check an input for username to search the specified user profile path for any files of .doc,.docx,.pdf,.pst ect. and copy them as is to a created folder on a network drive location.
My main question is what is the command or chain of commands to check folders and sub folders starting at the specified userpath, for JUST files with those extensions and I guess copy them but without getting to a situation where it just copies the same file over and over and over again. Sorry if that's confusing.
This answer provides sample code for recursively traversing a folder tree. A list of extensions could be handled by creating a dictionary:
Set extensions = CreateObject("Scripting.Dictionary")
extensions.CompareMode = vbTextCompare 'case-insensitive
extensions.Add "doc", True
extensions.Add "docx", True
extensions.Add "pdf", True
extensions.Add "pst", True
...
and then checking the extension of the processed files like this:
For Each f In fldr.Files
If extensions.Exists(objFso.GetExtensionName(f.Name)) Then
f.Copy targetFolder & "\"
End If
Next
The trailing backslash is required when the destination is a folder, otherwise you'd have to specify the full target path including the target filename.
I think I have understood most of the requirements, and this can be more easily achieved by using a .BAT file approach within windows. This batch (.Bat) file can run commands such as copy / delete etc.
So create a file called test.bat, and inside the file add the below script:
::XCOPY source [destination]
XCOPY "C:\Temp\*.doc" "C:\Temp\another"
What does this do? Well it uses an XCOPY Command to copy any files within the C:\Temp direcory which have a .doc extension. The files will be copied over to a folder called C:\Temp\another.
The XCOPY takes two primary arguments: source and destination. Source is where the file currently lives, and destination is where you want to copy the files to. More info of all of the options available can be found on:
http://support.microsoft.com/kb/240268
In order to run the file, just double click it, or schedule it to run whenever required.
Let me know if this meets your requirement, I didn't fully understand the bit about an input for a username?

How to bootstrap generated files task output with msbuild

I have a .csproj file where I declare some generated files:
<ItemGroup>
<AutoGenerated Include="generated\*.cs;generated\Models\*.cs"/>
</ItemGroup>
This is used as Outputs on a task:
<Target Name="GenerateFilesFromTemplate" BeforeTargets="BeforeBuild;BeforeRebuild"
Inputs="sometemplatefile"
Outputs="#(AutoGenerated)">
<Exec
Command="somegenerator.exe ... "
Outputs="#(AutoGenerated)"/>
</Target>
The generated/ is added .gitignore, so the generated files are not part of the source control.
My problem is that this setup does not bootstrap itself. As initially the generated folder is empty, the build skips the generate files task because it has no outputs:
GenerateFilesFromTemplate:
Skipping target "GenerateFilesFromTemplate" because it has no outputs.
I feel I'm doing this the wrong way, or I'm missing the obvious. I know I can remove the Inputs and Outputs on the Task and then it will generate the files on every build. But the generation is lengthy, and I want to avoid it if no necessary (the template file did not change). How can I make the build self-bootstrap and generate the files on first build, or when necessary?
The output items are meant to indicate known output files of a target. MSBuild then checks if all modification dates of the outputs are greater than the highest modification date of the input items to see if it can skip the target. It will also run the target if one of the outputs are missing.
If you cannot know in advance which files are generated by a target, a workaround is to produce a temporary file with a known location.
e.g. write use the WriteLinesToFile task (configured to overwrite) to update a file ($(IntermediateOutputPath)autogen.marker) and use the file as output element. It will then run the target on the first build and then only run if the input template file is newer than the marker.

Gradle Copy Task up-to-date determination

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.

Bash get all specific files in specific directory

I have a script that takes as an argument a path to a file upon which it performs certain operations. These files are stored in directories with path storage///_id/files (so in 2016 July 22 it would be storage/2016/Jul/22_1/files for the first set of files, .../Jul/22_2/files for second one etc.). The problem is each directory stores files with two extensions (say file.doc, file.txt) and I want to perform operations only on .txt files. I've tested earlier something like
for file in "/home/gonczor/temp/"*/*".txt"; do
echo "$file"
done
And it worked perfectly given that names in directories don't change. When I move one step further and add this 22_1, 22_2, 23_1 directories something strange happens.
This is my script (simplified):
for file in "$FILE_PATH/""$YEAR/""$MONTH/""$DAY"*/*".txt"; do
my_program ${report}
done
And instead of finding .../2016/Jul/22_1/file.txt it finds /2016/Jul/22*/*.txt
How can I make it work? The solution I've tried to make up is from here

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);
}

Resources