My first article on this subject - Aspirational Ants discussed the mythology that has been slowly turned on its head as Ant has progressed.
Sitting next to Joe of Exubero for the last six months has prompted me to rationalise and hone the company build processes even more tighly than usual. And I discovered in this process that above all you should create reusable components of your build process.
The problem is that Ant doesn't force you to engineer your builds in a reusable way, and all the commonly used build script examples avoid confusing the newbie by keeping it naive. This article is intended to be the first step for anyone just starting out on a new build process and wanting to leverage as much reuse as they can for later projects.
That is a quote from one of my favourite films, no prizes for guessing the film. I put it in as a reminder that in any large company there tends to be an ongoing battle between the business focused project developers and the standards focused company IT people. It is a fact of life that this split exists to a greater or lesser extent in almost every production environment.
Project developers tend to hack the build to make it work for them. Corporate IT developers tend to lack the understanding or power to fix those project specific builds and make them work in a reusable context. For your information, I am the former but with the knowledge and experience to avoid the pitfals.
So you have 2 camps of people who write ant scripts. How do you get the hackers to use well crafted build components? How do you work on components without touching the project builds?
It appeared in Ant 1.6, tucked away in the back of the manual. Very few people use it. But it provides a brilliant separation of concerns between the professional developer and the professional builder.
Antlib allows you to package up a set of macros, presets and typedefs and then drop them into a build environment as a jar or an xml file. Here is how it works:
Create a file called com/mycompany/ant/java/antlib.xml and make the contents as follows:
<antlib>
<presetdef name="javac">
<javac debug="on"/>
</presetdef>
</antlib>
Then create a mycompany_antlib.jar of the directory tree described above. And put that jar in your $ANT_HOME/lib folder. Then change your build.xml file to look something like this.
<project xmlns:my="antlib:com.mycompany.ant.java">
...
<my:javac src="${src}" />
...
</project>
Then when you run the script it will use the preset version and debug will be turned on.
Ant loads the namespace based operations from the jar you have created. This avoids the need for a complex hierarchy of build components and fragile task inheritance. And once the build is using the component, then you can upgrade and improve it without touching the main build.
Antlib can be used in other ways, please consult the Ant Manual for the full details.
The obvious thing to do is to create a build2 project in your development environment. As you can probably imagine you have a src folder and a build.xml file with the following target:
<target name="pack">
<jar destfile="${ant.home}/lib/my_antlib.jar">
<fileset dir="src" />
</jar>
</target>
As long as all the files you put in are using the naming convention of antlib.xml files at various points in the tree then they will be available to the project builds. Note that this snippet puts the created jar directly into your current ant environment, this could be considered risky.
Antlib definitions can be built upon other definitions, so you could have a whole hierarchy of build building projects. To make use of another antlib change the first line of the antlib to include the namespace reference(s) you require:
<antlib xmlns:my="antlib:com.mycompany.ant.j2ee"> ...
This basically puts the power of 'engineering the build' back into the hands of the ant script writers.
Having such a familiar build product, a jar file, means that you can also apply all the usual software engineering practices to the build project. I am chiefly talking about unit testing individual build targets and integration testing complex build relationships. This is much harder to do in a traditional ant build script because of the global nature of the tasks and targets, but the good separation of concerns, that antlib offers, permits the creation and maintenance of unit tests.
The mechanics of an ant unit test are basically a set of test project build.xml files arranged hierarchically, much like a set of JUnit TestSuite files. The high level 'test' task would use <ant dir="test1" /> to instigate the tests in an appropriate order. Then the resulting output can be checked and verified with the <available /> and <condition /> tasks. The use of XSLT and execution recordings provide adequate reporting and documentation tools for this process.
One of the other things about sitting next to Joe is that he keeps banging on about the benefits of
The migration path from project specific builds to a shared core of build resource is fraught with risk for an individual project.