Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call a task for each file in a fileset with plain ant with the filename as a parameter (no contrib tasks, no own tasks)

Tags:

ant

Problem:

If you have files that follow a certain naming convention(e.g. include locale) and need to be processed on a per file basis by an ant script, what are the possibilities in ant?

Example:

Files to be processed:

  • file_en-US.txt
  • file_en-GB.txt
  • ...

A task should be called for all files with their filename as a parameter. The locale that is contained in the filename needs to be extracted by a regex and passed to an external tool as a parameter. The extracting would be straight forward as soon as you have the filename.

Restrictions:

  • Plain Ant(1.7), no extensions allowed no custom/contrib tasks like foreach. Needs to run a every vanilla ant(1.7) installation.
like image 390
andy droid Avatar asked Oct 08 '22 20:10

andy droid


1 Answers

I pretty sure there isn't a way to generically call a task for each file without either creating your own custom task or using ant-contrib. However there are ways to get ant to automatically retrieve ant-contrib (or a custom jar) so you can achieve the desired result. This is the approach used by TIBant, which has a similar requirement (so that it's easy for anyone to contribute to the development),

Step 1: Download Apache Ivy

Apache Ivy can be used to retrieve dependencies such as ant-contrib. I use the following ant properties and target to download and load Ivy

<property name="ivy.install.version" value="2.2.0" />
<property name="ivy.jar.dir" location="${user.home}/.ivy2/jars" />
<property name="ivy.jar.file" location="${ivy.jar.dir}/ivy-${ivy.install.version}.jar" />

<target name="-download-ivy" unless="ivy.downloaded">
    <mkdir dir="${ivy.jar.dir}" />
    <!-- download Ivy from web site so that it can be used even without any special installation -->
    <echo message="installing ivy..." />
    <get src="http://repo1.maven.org/maven2/org/apache/ivy/ivy/${ivy.install.version}/ivy-${ivy.install.version}.jar"
         dest="${ivy.jar.file}"
         usetimestamp="true"
         verbose="true" />
</target>

<target name="-check-ivy-downloaded">
    <condition property="ivy.downloaded">
        <and>
            <available file="${ivy.jar.file}" />
            <available file="${ivy.jar.dir}/jsch-0.1.44-1.jar" />
        </and>
    </condition>
</target>

<target name="-load-ivy" depends="-check-ivy-downloaded,-download-ivy" unless="ivy.loaded">
    <path id="ivy.lib.path">
        <fileset dir="${ivy.jar.dir}" includes="*.jar" />
    </path>
    <taskdef resource="org/apache/ivy/ant/antlib.xml" uri="antlib:org.apache.ivy.ant" classpathref="ivy.lib.path" />
    <property name="ivy.loaded" value="true" />
</target>

Step 2: Add ant-contrib dependency

Ivy uses an "ivy file" for specifying dependencies. You can add ant-contrib as follows

    <dependency org="ant-contrib" name="ant-contrib" rev="1.0b3" transitive="false"/>

a full ivy file might look like

<?xml version="1.0" encoding="ISO-8859-1"?>
<ivy-module version="2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd">
    <info
    organisation="org.my"
    module="mymodule"
    status="release"/>

    <dependencies>
        <dependency org="ant-contrib" name="ant-contrib" rev="1.0b3" transitive="false"/>
    </dependencies>
</ivy-module>

You could also output this file dynamically from your ant script using echoxml

Step 3: Retrieve the dependencies

Use Ivy to download ant-contrib (or whatever dependencies you have specified)

<target name="retrieve" description="retrieve dependancies with ivy" depends="-load-ivy">
    <ivy:retrieve />
    <ivy:artifactproperty name="[module].[artifact]" value="lib/[artifact]-[revision].[ext]" />
</target>

Step 4: Load ant-contrib

<target name="-load-ant-contrib" depends="retrieve" unless="ant.contrib.loaded">
    <taskdef resource="net/sf/antcontrib/antlib.xml">
        <classpath>
            <pathelement location="${ant-contrib.ant-contrib}" />
        </classpath>
    </taskdef>
    <property name="ant.contrib.loaded" value="true" />
</target>

Step 5: Create your target that iterates over the files using for

<target name="mytarget" depends="-load-ant-contrib">
    <for param="file">
        <fileset dir="somedir" includes="..." />
        <sequential>
            <!-- do stuff with @{file} -->
        </sequential>
    </for>
</target>

If you only need to download ant-contrib and don't want to use Ivy to manage other dependencies, then you can skip most of the above and just use a get to download ant-contrib in the same way the above downloads Ivy.

like image 91
Tom Howard Avatar answered Oct 12 '22 11:10

Tom Howard