Search code examples
regexantfileset

Ant regexpmapper file separator issues


I'm banging my head against a brick wall playing with ant filesets/ regexpmapper to try and simply rename a directory (in the middle of a path)...

The situation is really simple:

  • I have path component/DB/ that I'm copying to DB/api/src/main/distribution/component.
  • Path component/DB contains a set of install.sql scripts and a directory called api (or "API" or "Api"). This "api" directory contains additional sql and will be copied wholesale into the target DB/api/component (so creating DB/api/src/main/distribution/component/api).
  • As part of this copy, I simply want to lowercase the "api" directory name for consistency.

Sounds simple and I've been playing with filesets and regexpmapper (or mapper type=regexp) to achieve this. However, I've had mixed results... notably that it doesn't work as soon as I put a '/' in (or '\\' or '/' or ${file.separator}, even if using regexpmapper.handledirsep=yes).

Here is obfuscated source path structure (from find):

component/DB/
component/DB/API
component/DB/API/file1.sql
component/DB/API/file2.sql
component/DB/xyz.sql
component/DB/Install_API.sql
component/DB/excludes1/...

My basic copy is as below:

<copy todir="${my.db.api.dir}/src/main/distribution/component" verbose="true">
    <fileset dir="${component.src.dir}/DB">
        <exclude name="exclude1"/>
        <exclude name="exclude1/**/*"/>
    </fileset>
    <regexpmapper handledirsep="yes"
            from="(.*)/API(.*)" to="\1/api\2"/>
    <!--mapper type="regexp" from="(.*)/API(.*)" to="\1/api\2"/-->
</copy>

I've left plain '/' in for clarity. You can see the basic premise is to spot "API", grab the surrounding text and replay it with "api" instead. If I omit the '/' in the from then this does actually work but as soon as I put the '/' (or it's friends) in, the directory is not copied at all. Note that I want the preceding '/' as I only want to rename that dir, not the Install_API.sql file contained within it.

There are a lot of examples on-line but no-one seems to have had this issue as the supposedly working examples all seem to use plain '/', '\' or claim to be handled by the handledirset attribute.

ant 1.8.4 on RH6.3

Many thanks.


Solution

  • Your fileset's base directory is the DB dir which means that the paths your mapper will be mapping are of the form

    API/file1.sql
    Install_API.sql
    excludes1/...
    

    relative to that directory. Thus there is no slash in front of the API directory name and your from pattern never matches. But there's a deeper problem, which is that a regexpmapper completely ignores any file names that do not match the from pattern. This is not what you want, as you need to change API to api but leave non-API file names unchanged. So rather than a regexpmapper you need a filtermapper with a replaceregex filter:

    <copy todir="${my.db.api.dir}/src/main/distribution/component" verbose="true">
        <fileset dir="${component.src.dir}/DB">
            <exclude name="exclude1"/>
            <exclude name="exclude1/**/*"/>
        </fileset>
        <filtermapper>
            <!-- look for either just "API" with no trailer, or API followed by
                 a slash, in any combination of case -->
            <replaceregex pattern="^API(?=${file.separator}|$$)" replace="api"
                          flags="i"/><!-- case-insensitive search, finds API, Api, ... -->
        </filtermapper>
    </copy>