Antlibs

Specifying custom tasks for Apache Ant 1.7

Kev Jackson

ViNetworks - Senior Software Developer

Contents

  • Who am I?
  • Introduction - Extending Ant
  • Antlibs - What?
  • Antlibs - How? (the BIG bit)
  • Ant 1.7 - New Features
Contents, no extra info.

Who am I?

Kev Jackson

Ant Committer, Ant 1.7 Release Manager

Extending Ant - Patch the code

  • Post a patch or feature request on Bugzilla
  • and wait...
  • ...wait...
  • ...wait for a committer to have the time to review your patch.
  • Even then, the patch may not be suitable :(

Ant is designed to be extensible. From its xml build files, to the API that encourages third party developers to write their own tasks. But what are the options for extending Ant as a developer? From the very beginning, it was always possible to contribute via patches...

Extending Ant - Hack your own

  • Download latest version from SVN repo...
  • ...download required third-party libraries (there are a lot)...
  • ...get the code to compile...
  • ...finally write your custom code.
  • Difficult to merge in beneficial changes from the trunk of the repo - are you paid as a full-time Ant customizer?
  • Highly Unlikely!

So instead you could get the source code and change it as needed...

Extending Ant - <macrodef>


<macrodef name="hello-world">
  <sequential>
    <echo message="hello, world"/>
  <sequential>
</macrodef>
  • Good for some problems, but...
  • ...only works by combining tasks that are already available

Wait, what about the XML? This macrodef looks handy...

Extending Ant - <exec>

<exec executable="...">
  • Like 'make', just shell out and call external program to do the work, but...
  • ...not cross platform
  • ...path problems
  • ...many caveats for each different OS!

So we'll go old skool then!

Extending Ant - <scriptdef>


<scriptdef name="scripttest" language="javascript">
  <![CDATA[
    project.log("Hello from script")
  ]]>
</scriptdef>
  • Supports many languages
  • Can write new functionality very quickly, but...
  • ...great for one off scripts, not great for reusable code
  • ...needs the correct script jars on the classpath

Extending Ant - Custom Tasks

  • Great!
  • ...Complete control over what we do
  • ...in Java so no problems* with different OS
  • ...problem solved! Or, not quite...
  • Classpath problems: example JUnit Task (how long has this been around?)
  • ...http://ant.apache.org/faq.html#delegating-classloader-1.6
  • ...and people still have problems getting it to work
  • Simple fix...place all third-party jars in $ANT_HOME/lib

Extending Ant - Antlibs

  • Advantages over a custom task
  • ...available automatically (if placed in $ANT_HOME/lib)
  • ...in Java so no problems* with different OS
  • ...can bundle a lot of functionality together in one 'library'
  • ...separate from Ant core (unlike optional taskdefs)
  • ...can be updated separately from Ant core (no longer have to wait for new Ant to take advantage of new features in an antlib)

Antlibs - What?

  • Just a custom task
  • ...placed in $ANT_HOME/lib
    • or in user.home/.ant/lib (for centrally managed installation)
    • or you can specify them manually
  • ...with an antlib.xml file
  • ...declared as part of an xml namespace in your build.xml file

Antlibs - Making a tla (GNU Arch) antlib

  • Remember: just a 'normal' custom task
  • 1: Install GNU Arch (tla)...

Antlibs - Making a tla (GNU Arch) antlib

Antlibs - Making a tla (GNU Arch) antlib

  • 1: Install GNU Arch (tla)...
  • 2: Write a command line wrapper similar to AbstractCVSTask...

Antlibs - Making a tla (GNU Arch) antlib


  Environment env = new Environment();
  Execute exe = 
    new Execute(getExecuteStreamHandler(), null);
  exe.setAntRun(getProject());
  exe.setCommandline(toExecute.getCommandline());
  exe.setEnvironment(env.getVariables());
  try {
    String actualCommandLine = 
        executeToString(exe);
    log(
        actualCommandLine, 
        Project.MSG_VERBOSE
    );
    int retCode = exe.execute();
    ...
  • See http://people.apache.org/~kevj/ant-tla/ant-tla.html for the full code

Antlibs - Making a tla (GNU Arch) antlib

  • 1: Install GNU Arch (tla)...
  • 2: Write a command line wrapper similar to AbstractCVSTask...
  • 3: Add custom classes for individual actions (get/update etc)

Antlibs - Making a tla (GNU Arch) antlib

Antlibs - Making a tla (GNU Arch) antlib

Antlibs - Making a tla (GNU Arch) antlib

  • 1: Install GNU Arch (tla)...
  • 2: Write a command line wrapper similar to AbstractCVSTask...
  • 3: Add custom classes for individual actions (get/update etc)
  • 4: Add an antlib.xml

Antlibs - Making a tla (GNU Arch) antlib


<?xml version="1.0" encoding="utf-8"?>
<antlib>
  <taskdef name="tla"
    classname="org.apache.ant.tla.Tla"
    />
  <taskdef name="registerarchive"
    classname="org.apache.ant.tla.RegisterArchive"
    />
  <taskdef name="get"
    classname="org.apache.ant.tla.Get"
    />
  <taskdef name="update"
    classname="org.apache.ant.tla.Update"
    />
</antlib>

Antlibs - Making a tla (GNU Arch) antlib

  • 1: Install GNU Arch (tla)...
  • 2: Write a command line wrapper similar to AbstractCVSTask...
  • 3: Add custom classes for individual actions (get/update etc)
  • 4: Add an antlib.xml
  • 5: Write a simple build file using the antlib...

Antlibs - Making a tla (GNU Arch) antlib


<?xml version="1.0" encoding="utf-8"?>
<project name="tla-test" basedir="../../../" default="get"
  xmlns:tla="antlib:org.apache.ant.tla">

  <property name="repo-dir" value="tla-test"/>
  <target name="get">
    <tla:registerarchive
      repoURL="http://www.atai.org/archarchives/atai@atai.org--public/"
    />
    <tla:get archive="atai@atai.org--public"
                revision="tla--atai-dists--1.3.4"
                dest="${repo-dir}" />
  </target>

  <target name="cleanup">
    <delete dir="${repo-dir}"/>
  </target>

</project>

Antlibs - Making a tla (GNU Arch) antlib

  • 1: Install GNU Arch (tla)...
  • 2: Write a command line wrapper similar to AbstractCVSTask...
  • 3: Add custom classes for individual actions (get/update etc)
  • 4: Add an antlib.xml
  • 5: Write a simple build file using the antlib...
  • 6: Test the code with the build file

Antlibs - Making a tla (GNU Arch) antlib

Antlibs - Making a tla (GNU Arch) antlib

  • 1: Install GNU Arch (tla)...
  • 2: Write a command line wrapper similar to AbstractCVSTask...
  • 3: Add custom classes for individual actions (get/update etc)
  • 4: Add an antlib.xml
  • 5: Write a simple build file using the antlib...
  • 6: Test the code with the build file
  • 7: Write a repeatable test

Antlibs - Making a tla (GNU Arch) antlib

Antlibs - Making a tla (GNU Arch) antlib

Antlibs - Things to notice

  • Not specified like a normal custom task
  • Use xml namespaces
  • Trivial to change a normal build file into an 'antunit' test
  • What's this tla:register-archive?
  • What about backwards compatibility with Ant 1.5 etc?

Antlibs - Build.xml -> Antunit test

  • Add the antunit namespace to your build file
  • Specify the driving target as the default in the build file
  • In the driving target read in the build file (yes the same file), and set up the <au:plainlistener/>
  • Write a target named 'testX'
  • Inside 'testX', perform actions as normal
  • After the actions have been performed use the appropriate <au:assertX/> to test the result
  • For setup, add a <target name="setUp">
  • For teardown, add a <target name="tearDown">

Antlibs - Antunit

  • Antunit is an antlib
  • Just like JUnit (setUp -> test1..testN -> tearDown)
  • Dependencies are *still* called
  • Antunit reads a buildfile (x.xml) to drive the tests
  • Antunit provides basic assertions, but more can be added
  • (My) preferred method of testing Ant task code (plain JUnit or even BuildFileTests are now obselete)
  • Antunit, currently in Apache Ant Antlib SVN repo, should be released 'Real Soon Now' :)
  • See http://ant.apache.org/antlibs/antunit/ for more information

Antlibs - tla:register-archive?

  • Sorry, a required task so that we can 'get'
  • Wanted to concentrate on one function for the examples
  • In the code for this antlib, there are other features which I didn't reveal today...
  • You can try the code out from http://people.apache.org/~kevj/ant-tla/ant-tla.html

Antlibs - A compatibility 'trick'

  • What if you want to distribute a custom task that can run as both an antlib or as a normal custom task?
  • DRY - Don't repeat yourself
  • Create an antlib, and in the base directory write a properties file
  • In the antlib.xml file, use <taskdef resource="tasks.properties"/>
  • Example - Ant-contrib

Antlibs - A compatibility 'trick'

  • Define tasks that are compatible with <Ant 1.6 in a properties file

Antlibs - A compatibility 'trick'

  • Define tasks which require >Ant 1.6 in the antlib.xml

Antlibs - A compatibility 'trick'

  • Benefits:
  • 1: DRY - Don't repeat yourself
  • 2: Easier maintenance as edits can be made to the properties file and they are instantly available in the antlib
  • 3: Good backwards compatibility for normal taskdefs, antlib tasks available for ant 1.6+

Antlibs - Inside antlib.xml

  • Allowed inside an antlib.xml file:
    • <taskdef>
    • <typedef>
    • <presetdef>
    • <macrodef>
    • <scriptdef>
    • anything that implements the AntLibDefinition interface
  • For Example, antunit:

Antlibs - Inside antlib.xml

Finally - Ant 1.7 new features

  • ResourceCollections (can contain files, archives and URLs)
  • Better Java5 support (eg <apt>)
  • JUnit4 support in the <junit> task
  • Full antlib support (hope to release svn antlib, antunit antlib, vss antlib at or around 1.7 release)
  • <scp> task now supports sftp
  • Better .Net support (including Mono)
  • New <schemevalidate> task supports XSD files
  • A lot of new conditions (issigned, scriptcondition, xor, parsersupports, typefound, isfailure, resourcesmatch, antversion)