HelloWorld
HelloWorld

Reputation: 133

Ant Rename files maintaining directory structure

I want to rename files using Ant maintaining their directory structure.

e.g. Assume following directory structure:

- copy
    - new
        - testthis.a

Using code below, I could rename files containing "this" word to "that.a" using copy task, but they all are getting pasted into "paste" directory loosing their directory structure.

<copy todir="paste" overwrite="true">
    <fileset dir="copy"/>
    <regexpmapper from="^(.*)this(.*)\.a$$" to="that.a"/>
</copy>

Output:

- paste
    - that.a

If I change regexmapper to (notice \1 before that.a):

    <regexpmapper from="^(.*)this(.*)\.a$$" to="\1that.a"/>

It's generating correct directory structure but always prepends word before "this" to "that.a"

Output:

- paste
    - new
        - testthat.a

Is there any way to rename files maintaining their directory structure without pre-pending or appending any word?

Is there any other mapper which can be used for the same?

Any help would be appreciated.

Upvotes: 3

Views: 658

Answers (2)

Chad Nouis
Chad Nouis

Reputation: 7041

<copy todir="paste" verbose="true">
    <fileset dir="copy" includes="**/*this*.a"/>
    <regexpmapper from="((?:[^/]+/)*)[^/]+$$" to="\1that.a" handledirsep="true"/>
</copy>

First, setting handledirsep="true" allows us use forward slashes to match backslashes. This makes the regular expression a bit cleaner.

Next, I'll explain the gnarly regex by breaking it into parts.

I explode ((?:[^/]+/)*) into...

(
    (?:
        [^/]+
        /
    )
    *
)

What the parts mean:

(  -- capture group 1 starts
    (?:  -- non-capturing group starts
        [^/]+  -- greedily match as many non-directory separators as possible
        /  -- match a single directory-separator character
    )  -- non-capturing group ends
    * -- repeat the non-capturing group zero-or-more times
)  -- capture group 1 ends

The above parts repeatedly match as many subdirectories as possible. The ( and ) put all of the matches into capture group 1. Later, capture group 1 can be used in the to attribute of <regexpmapper> with a \1 backreference.

If there are no / directory separators in a path, then the above parts won't match anything and capture group 1 will be an empty string.

Moving to the end of the regex, the $$ anchors the regex to the end of each path selected by the <fileset>.

In the double dollar-sign expression, $$, the first $ escapes the second $. This is necessary because Ant would treat a single $ as the start of a property reference.

The [^/]+ matches just the filename because it matches all characters at the end of the path that aren't directory separators (/).

Example

Given the following directory structure...

- copy (dir)
    - new (dir)
        - notthis.b
        - testthis.a
    - anythis.a

...Ant outputs...

[copy] Copying 2 files to C:\ant\paste
[copy] Copying C:\ant\copy\anythis.a to C:\ant\paste\that.a
[copy] Copying C:\ant\copy\new\testthis.a to C:\ant\paste\new\that.a

Upvotes: 3

gaborsch
gaborsch

Reputation: 15758

Try this regexpmapper:

<regexpmapper from="^(.*)/([^/]*)this(.*)\.a$$" to="\1/that\3"/>

This cuts the path (\1) and filename prefix (\2), so you can preserve the directory structure.

Also, you can preserve the file extension if you use \3in the replacement string.

Upvotes: 0

Related Questions