Recent Posts

Archive

Ceilingfish

Making a better ant file

February 11th 2010

Ant files are commonly used to manage Java projects, not always I’ll grant you, but I’ve no personal experience of Maven, and as far as I can tell Ant does everything that I need. What I struggled with when I first started using them though was how to structure them, and furthermore how do you manage them between multiple developer workspaces.

Developer Specific Settings

Full Disclosure: This technique isn’t my own, it was shown to me by a very talented programmer called David Harrigan who I worked with a couple of years back. Sadly I can’t find a blog with his name on.

Let’s take an example where your project depends on a load of external graphical assets, the kind of stuff that would be absolute insanity to actually put into source control, and they get should be copied into the assets directory of any build, like so:

So each developer copies the relevant graphics onto their own hard disk, but of course they’re all in different folders. So we need to set the assets.dir property for each developer individually, there’s loads of ways to do this. Firstly we could do it as a command to the ant argument:

But this is going to get very cumbersome very quickly. We really don’t want to have to be retyping all these arguments every time we want to run a build. So on to phase two, put them in a properties file

build.properties

Then we include this at the top of the build file like this

build.xml

Now here’s the important bit make sure the build.properties file never gets committed. Add it to the ignore list for your version control (here’s how to do that in git and subversion). This means that individual developers can define their own version of the file and it will automatically be loaded when they run ant.

Of course it’s best not to leave developers guessing at what the correct structure of the build.properties file should be, so it’s generally useful to include an example file

build.properties-example

Dependency Management

Ivy is an absolutely awesome tool for handling dependent libraries, though there are a couple of tweaks you’ll need to make to get the behaviour you expect by default. First things first however, here’s a very good page on how to get ivy installed in seconds. So now all we have to do is define a task to actually invoke ivy.

The most important bit here is transitive="false". This stops ivy downloading any jars that are marked up as dependent by your resource. So for example if you use the dependency

It’ll also try and download all of these

which really starts to pump up the download times, because you’ll also need to download all the dependencies for each of these sub-dependencies, of which there are another 11. It’s enough to make a man cry.

The other useful bit of info in the ivy declaration is pattern="${libs.dir}/[artifact].[ext]" this tells ivy to download your dependencies into the libs.dir folder (which for the sake of outright insanity let’s assume is libs/), and structure them as such:

Because ivy names jars uniformly using this scheme we avoid any problems with two versions of a library being loaded (other schemes I’ve seen include a version number in the jar name, which can end up with both being in the classpath, which can get a little weird). One thing to remember though is do remember to add the libs/ directory to your source control ignore list. Running diffs on large binary files can really slow down SCM systems.