Slav
Slav

Reputation: 27485

Ant: How to stop copying on duplicates

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

Answers (1)

Rebse
Rebse

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

Related Questions