GreenGiant
GreenGiant

Reputation: 5236

Deleting files matching a placeholders in another directory tree

I have two directory trees:

source/aaa/bbb/ccc/file01.txt
source/aaa/bbb/file02.txt
source/aaa/bbb/file03.txt
source/aaa/ddd/file03.txt
source/file01.txt

and

template/aaa/bbb/ccc/file01.txt
template/aaa/bbb/DELETE-file03.txt
template/aaa/DELETE-ddd
template/DELETE-file01.txt

Using Ant, I want to do three things. First, I want to copy any files from "template" into "source", such that all files not starting with "DELETE-" are replaced. For example, "source/aaa/bbb/ccc/file01.txt" would be replaced. This is straightforward with:

<copy todir="source" verbose="true" overwrite="true">
    <fileset dir="template">
        <exclude name="**/DELETE-*"/>
    </fileset>
</copy>

Second, I want to delete all files in the "source" tree whose name matches a "DELETE-" file in the corresponding directory of the "template" tree. For example, both "source/aaa/bbb/file03.txt" and "source/file01.txt" will be deleted. I have been able to accomplish this with:

<delete verbose="true">
    <fileset dir="source">
        <present present="both" targetdir="template">
            <mapper type="regexp" from="(.*[/\\])?([^/\\]+)" to="\1DELETE-\2"/>
        </present>
    </fileset>
</delete>   

Third, I'd like to delete any directories (empty or not) whose names match in the same way. For example, "template/aaa/DELETE-ddd" and all file(s) under it would be deleted. I'm not sure how to construct a fileset that matches directories (and all the files under them) in the "source" tree where the directory has a DELETE-* file in the "template" tree.

Is this third task even possible with Ant (1.7.1)? I'd preferrably like to do this without writing any custom ant tasks/selectors.

Upvotes: 1

Views: 2081

Answers (2)

GreenGiant
GreenGiant

Reputation: 5236

It seems the root issue that makes this difficult is that ant drives selectors/filesets based on files found within the target directory of fileset. Normally, however, one would want to drive things from the list of DELETE-* marker files.

The best solution I've found so far does require some custom code. I chose the <groovy> task, but also could have used <script>.

The gist: create a fileset, use groovy to add a series of excludes that skip files and directories with a DELETE-* marker, then perform the copy. This accomplishes the second and third task from my question.

<fileset id="source_files" dir="source"/>

<!-- add exclude patterns to fileset that will skip any files with a DELETE-* marker -->
<groovy><![CDATA[
    def excludes = []
    new File( "template" ).eachFileRecurse(){ File templateFile ->
        if( templateFile.name =~ /DELETE-*/ ){
            // file path relative to template dir
            def relativeFile = templateFile.toString().substring( "template".length() )
            // filename with DELETE- prefix removed
            def withoutPrefix = relativeFile.replaceFirst( "DELETE-", "")
            // add wildcard to match all files under directories
            def exclude = withoutPrefix + "/**"
            excludes << exclude
        }
    }
    def fileSet = project.getReference("source_files")
    fileSet.appendExcludes(excludes as String[])
]]></groovy>

<!-- create a baseline copy, excluding files with DELETE-* markers in the template directories -->
<copy todir="target">
    <fileset refid="source_files"/>
</copy>

Upvotes: 1

Rebse
Rebse

Reputation: 10377

To delete a directory and its contents use delete with nested fileset, i.e. :

 <delete includeemptydirs="true">
  <fileset dir="your/root/directory" defaultexcludes="false">
   <include name="**/DELETE-*/**" />
  </fileset>
 </delete>

With attribute includeemptydirs="true" the directories will be deleted too.

Upvotes: 0

Related Questions