Search code examples
file-ioantant-contrib

Ant build to operate only on subdirectories


I'm trying to create an Ant build that will run a target in every subfolder in a folder. I need this one in particular to only run at the subfolder level, because if I run it from the top folder and tel it to include subfolders, it scrambles the results.

I put the following together from suggestions I've seen, and it seems close but it's not working. A couple of points about it:

  • When I run this, I get "C:\Developer\SVN\trunk\DITA\xxx_conversion\test\${subdir} does not exist." (A subdirectory does exist, I have ...\test\testsub\xxx_xxx.dita)

  • The target named "script" works perfectly by itself. If I point it to a folder, it transforms what's in it and gives me the result I need.

  • In the foreach task if I change to just <dirset dir="."> as a test then the build succeeds, but it basically just runs the "script" target as is.

  • In the target named "script", if I change "*.dita" to "**\*.dita" it then includes the top level folder in its operation so the result is not what I need, which is just to take each .dita file in each subfolder and wrap it in a folder of the same name as the dita file:

Starting state: testsub\xxx_xxx.dita

Desired result: testsub\xxx_xxx\xxx_xxx.dita

Scrambled result: testsub\xxx_xxx\testsub\xxx_xxx.dita

If anyone can tell me what's wrong with this (possibly many things) that would be great:

<project name="move_and_wrap_dita_topics" default="script" basedir="C:\Developer\SVN\trunk\DITA\xxx_conversion\test">

<taskdef resource="net/sf/antcontrib/antlib.xml">
</taskdef>

<foreach target="script" param="worksheet" inheritall="true">
  <path>
      <dirset dir="${subDir}">
           <include name="*"/>
      </dirset>
  </path>
</foreach>

<target name="script">
   <copy todir="C:\Developer\SVN\trunk\DITA\xxx_conversion\cleaned" verbose="true">
     <fileset dir="C:\Developer\SVN\trunk\DITA\xxx_conversion\test">
        <include name="*.dita"/> 
     </fileset>
        <scriptmapper language="javascript">
   self.addMappedName(source.replace(source.split('.')[0], source.split('.')[0] + "/" + source.split('.')[0]));
      </scriptmapper>
  </copy>
</target>

</project>

As an alternative, if there's some way to just write the "include name" in the "script" task so that it skips the top folder completely and only rewrites starting at the subfolders, that would be even simpler. I've tried <include name="/*.dita"/>and all sorts of other variations but no luck.


Solution

  • Starting state: testsub\xxx_xxx.dita

    Desired result: testsub\xxx_xxx\xxx_xxx.dita

    This should be doable with a single regex mapper, you don't need the foreach at all:

    <copy todir="C:\Developer\SVN\trunk\DITA\xxx_conversion\cleaned" verbose="true">
      <fileset dir="C:\Developer\SVN\trunk\DITA\xxx_conversion\test"
               includes="*/*.dita" />
      <!-- use handledirsep to treat \ as if it were / in the source file name -->
      <regexpmapper handledirsep="true" from="^(.*)/([^/]*)\.dita$"
                    to="\1/\2/\2.dita" />
    </copy>
    

    The includes="*/*.dita" will match .dita files that are one level below the base directory of the fileset, and the regex will convert testsub/xxx.dita in the source to testsub/xxx/xxx.dita in the destination. If you want to find files that are one-or-more levels deep then use */**/*.dita instead.