Wednesday, April 3, 2013

Write your own Ant tasks

http://www.openlogic.com/wazi/bid/278127/write-your-own-ant-tasks

Apache Ant
is a Java-based build tool, and because it's based on Java, it is
entirely cross-platform. It comes with a huge list of available tasks
that you can run simply by including them in a build.xml file, but if
there's something you want it to do and no existing task
can do it, it's easy to extend Ant just by writing a new Java class.
Here's how to write your very own Ant tasks.
Before you get started, it's always best to check the list of existing Ant tasks, and the list of external (not included in default Ant) tasks
submitted by developers outside the Ant project and not directly
supported by the Ant developers. While writing a new task can be fun,
there's no need to reinvent the wheel if someone has already done the
work for you. If they haven't, because you've found something new it
would be handy to do or have unusual specifics you need to manage, you
can extend Ant for yourself.

A very basic new task

To write a new task, you need to extend the Ant Task class. (You can
theoretically manage without doing so, but extending Task gives you
access to a bunch of useful methods and setup, so it's sensible to use
it.) Let's see how with a simple HelloWorld example. Create a new
directory hellotask, and a file src/HelloTask.java that contains:

The only method you absolutely must have to extend Task is execute(). Here, we're calling the logger twice to output two lines. getProject(), getProperty(), and getLocation() are all inherited from the Task class, and do what you'd expect.
To run and compile this file, obviously we want to use Ant! Here's the build.xml file:

Most of this should be familiar if you read my tutorial on Ant buildfiles; it cleans things up, compiles, and creates a JAR from the source code. Run ant jar to build HelloTask into a JAR.
The final section is the bit that actually runs the task. The taskdef (task definition) line tells Ant what to do when it sees
later on. (With predefined tasks, you don't need this line because Ant
already knows how to handle them.) Note that in this setup, where we
might be deleting and recompiling the JAR, the taskdef line must be inside the target block. If you put the definition earlier in the file, and HelloTask.jar has been deleted (by running ant clean),
Ant won't find the JAR and you'll get an error. Later, if you were to
import the JAR elsewhere and just run the task, you could put this line
at the top of the file.
Finally, we set up the hello target to run . Type ant hello and you should see output a bit like this:

Note that the setter method (setOwner()) must match the
name of the variable you wish to set. Ant then generates a matching
getter method at compile time, and uses this when the task is run. (You
could of course also write your own getter method if you prefer.) Edit
build.xml to specify the parameter:

A more complicated task

Finally, let's take a look at a more complicated real-world example –
an Ant task I wrote to deal with LaTeX files. This is the first,
ultra-basic version, which just generates DVI output from a given LaTeX
input file. Save this as src/MakeLatex.java:

The setter method is familiar. In execute(), we send a log message, then create the command to run from the input provided. This command is then run externally with Runtime.getRuntime().exec(), and the output collected and printed to screen with a BufferedReader and the while loop.
To run this, edit the build.xml file to include this new target:

The existing jar target builds the new class into the
HelloTask.jar file. Obviously if you were using this for real you'd want
to build it into its own jarfile and save it somewhere else so you
could use it in future.
You also need a test .tex file. (Note: The test file is saved as test.tex, but you don't need the .tex extension when setting input in build.xml; LaTeX will assume it.):

Run ant latex to build your file, then look at test.dvi in your preferred DVI viewer to see the output.
While this approach generates a test.dvi file, it doesn't open it for
the user to look at, and it generates a lot of output noise. Also,
these days most people prefer PDF output to DVI output – I certainly do!
So here's an improved version, which takes an output and a verbosity
value:

And here's the accompanying buildfile, which specifies the output
format and verbosity. If your buildfile doesn't specify output or
verbosity values, the task defaults to PDF and to non-verbose:

Ant will now generate the sort of output you prefer, and fire up the specified viewer.
Finally, one last improvement: Let's pass in a filename from the
command line. Ant can do this if you add this code to build.xml:

Must specify input file

This sets a condition property, params.set, based on whether the "input" value is set. When we build the latex target, Ant first checks the status of params.set,
and fails the build (stopping there) unless it is true. If it is true,
the value is passed into the task, and off we go. You call this like so
(note the -D argument):

ant latex -Dinput='test'

As it stands, this task is very basic. You could add more options to
it; for example, you could add other output formats, or a bibtex option.
You could also do some error-checking on the input filename; currently
if you set input as test.tex rather than test, the task would fail.
Experiment a little with the code to see what else you can do with it,
and to get a better grasp of writing a task to do exactly what you want
it to.