Reputation: 27485
I have a directory with several sub-directories in it. Inside there are files. Out of those file1.ext
is a duplicate present in more than 1 directory. The sub-directories and filenames are obviously unknown at the time of execution.
-> bigdir --------> subdir1 ----------------> file1.ext --------> subdir2 ----------------> file1.ext --------> subdir3 ----------------> file2.ext
I am trying to copy contents of bigdir
into smalldir
using flatten="true"
so that my resultant file structure looks like
-> smalldir ----------> file1.ext ----------> file2.ext
So far, I have the following
<copy todir="${smalldir}" flatten="true" verbose="true">
<fileset dir="${bigdir}">
<include name="**/*.ext"/>
</fileset>
</copy>
This works fine and achieves the result that I want, HOWEVER, it is an error to have duplicate files in bigdir
. I want the build to fail if it detects that bigdir
has duplicate filenames inside
I was trying to find a way to make the <copy>
task fail in such case. It doesn't have to be through this approach. I can happily run some kind of validation
on the directory before copying too, if I could figure out how.
Maybe make each copied file read-only, so that subsequent overwrites as a result of copy flatten=true
fail to overwrite and produce an error?
No ant-contrib please
Upvotes: 1
Views: 464
Reputation: 10377
You may use a scriptcondition (see ant manual conditions) with builtin javascript engine
(included since Java 1.6.06, so no extra libraries or ant addons needed), like that :
<project>
<fileset dir="C:\tmp\bigdir" id="whatever"/>
<echo>${toString:whatever}</echo>
<fail message="Duplicate Filenames detected !!">
<condition>
<scriptcondition language="javascript">
<![CDATA[
importPackage(java.util);
var input = project.getProperty('toString:whatever').split(';');
// get basenames
for (var i = 0; i < input.length; i++) {
input[i]=input[i].substring(input[i].lastIndexOf("\\")+1);
}
var inputList = Arrays.asList(input);
// no duplicates in Hashset
var inputSet = new HashSet(inputList);
self.setValue(inputSet.size() < inputList.size());
]]>
</scriptcondition>
</condition>
</fail>
</project>
output :
[echo] subdir1\foo.txt;subdir2\foo.txt;subdir3\foobar.txt
BUILD FAILED
C:\area51\AntTest\tryme.xml:7: Duplicate Filenames detected !!
-- EDIT after comment --
To display the duplicates use something like :
<project>
<fileset dir="C:\bigdir" id="whatever"/>
<echo>${toString:whatever}</echo>
<fail message="Duplicate Filenames detected !!">
<condition>
<scriptcondition language="javascript">
<![CDATA[
importPackage(java.util);
// get DirectoryScanner
ds = whatever.getDirectoryScanner(project);
// get the included files => array
checkFiles = ds.getIncludedFiles();
var checkSet = new HashSet();
var s = "";
for (j=0; j < checkFiles.length; j++) {
f = new java.io.File(whatever.getDir(project), checkFiles[j]);
if(!checkSet.add(f.getName()))
s += f + '\n';
}
println(s.substring(0, s.length - 1));
self.setValue(checkSet.size() < checkFiles.length);
]]>
</scriptcondition>
</condition>
</fail>
</project>
output :
[echo] subdir1\foo.txt;subdir2\foo.txt;subdir3\foobar.txt;subdir3\subsubdir1\foo.txt;subdir3\subsubdir2\foobar.txt;subdir4\foobaz.txt
[fail] C:\bigdir\subdir2\foo.txt
[fail] C:\bigdir\subdir3\subsubdir1\foo.txt
[fail] C:\bigdir\subdir3\subsubdir2\foobar.txt
BUILD FAILED
Btw, often it's much simpler to use the ant api :
// get DirectoryScanner
ds = whatever.getDirectoryScanner(project);
// get the included files => array
checkFiles = ds.getIncludedFiles();
instead of :
var input = project.getProperty('toString:whatever').split(';');
// get basenames
for (var i = 0; i < input.length; i++) {
input[i]=input[i].substring(input[i].lastIndexOf("\\")+1);
}
as i used in first snippet.
Upvotes: 1