ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Carpenter, James" <>
Subject Completed new custom task to dynamically determine classpaths
Date Tue, 30 Dec 2003 21:07:23 GMT
I have a need to change our current ant based build system from a single monolithic build in
which all utilities are part of the source tree of the webapp currently under development
into several component builds.  This way other web applications can share the same exact utilities,
or more specifically version X of each desired internal utility.  To my knowledge there is
no combination of existing ant tasks (other than my custom task) that solve all of the problems
involved in a nice clean manner.  Furthermore, I suspect most every large company using ant
with multiple teams will eventually encounter the same problem set.

Componentizing the build solves the problem of sharing common libraries between development
teams.  Unfortunately doing so also often causes the following problems:
1) Some teams will inevitable end up using rather outdated versions of a shared internal library.
2) Without an overall build system extending a utility can be rather cumbersome.

The general solution to potential problem 1 is to somehow increase the visibility of a particular
team's use of an outdated version.  If upgrading to a new version is easy enough (i.e. just
edit a property file) and a team is constantly reminded they are using an older version, they
will likely tend to stay up to date.  Ideally the fact the team's code is using an old version
will be reported by any continuous integration environment (i.e. cruise-control).

Potential problem 2 is referring to the typical scenario in which one is developing client
code (a web application) to the internal utility when one discovers the utility isn't adequate.
 In practice one is then often forced to make changes to the utility, release a new version
of the utility, configure the client application to use the new version of the utility, see
if the client application's need has been satisfied and if not repeat the above steps.  To
alleviate such tediousness one obviously tries to construct an overall build environment that
can compile/test/distribute the utility and then do the same for the client application. 
In the event one is using such an overall build the utility distribution that is created is
simply a temporary one and probably shouldn't represent an internal release.  (When one completes
extending the utility one will most likely want to create an internal release.)

I found it very difficult to use the existing ant tasks to write an ant build system that
componentized the build system yet still addressed potential problems 1 and 2.  To that end
I wrote a custom ant task that searches for each desired utility and sets a class path reference
with the results.  The task first searches an area intended for active build artifacts and
failing that looks for the desired release version in a specified directory.  If a release
version is being used, the task reports at warning level if a newer version exists.  If an
active build artifact is being used for a particular utility then the task reports the fact
at an info level.  As well as the above information, boundary cases indicating something is
misconfigured result in BuildExceptions being thrown.

The custom task only implements the missing functionality.  It is still expected the user
will use the existing ant tasks to complete his/her overall build environment.

Although only lightly documented the task is very thoroughly unit tested using the Ant extensions
to junit.

The task is currently adequate for my needs and I do not have the time to submit it as a formal
ant task.  That said it would be in my employer's best interest to have the ant team integrate
it in as an official ant task (or just a related project).  To that end I believe I can get
a formal legal release of the code under an open-source license if there is any interest.
 The task is useful in its current form (after someone writes a bit more documentation) but
could be made even more general than it is.

In case your wondering, I am intending to store our internal utility releases in CVS in the
same directory structure as expected by the custom ant task.  This will work fine for now,
but at some future point may need to be done differently.

The class level javadoc is copied below:
 * This ant task is intended to be used in determining
 * where to acquire jar files for a given internal
 * subproject.
 * The search algorithm is as follows:
 * Foreach subproject look in
 * activebuildlibdir for a subproject.category
 * directory.  If found look for any jars there
 * and add them to the path list.
 * If unsuccessful then look in
 * releasedir/subproject.category/subproject.desiredversion
 * If nothing is found, get mad and throw a BuildException.
 * If something is found see if the desired version
 * is the most current version available
 * in the releasedir/subproject.category directory.
 * If you have trouble parsing the name
 * of any subdirectory found
 * in releasedir/subproject.category throw a BuildException.
 * If the desired version is out of date
 * log it at warning level.
 * An example usage is shown below:
 *      <property name="subproject.lib.dir" value="../subprojectactivebuildlib"/>
 *      <property name="release.dir" value="../internaltools"/>
 *      <property name="internal.core.category" value="core"/>
 *      <property name="internal.core.desiredversion" value="1_0_1"/>
 *      <property name="internal.db.category" value="db"/>
 *      <property name="internal.db.desiredversion" value="2_4_1"/>
 *      <!--After the below target's execution the subproject.classpath
 *      can be used as a refid for the classpath argument of the javac
 *      ant task -->
 *      <target name="determine.subproject.classpaths">
 *      <findsubprojects
 *          classpathid="subproject.classpath"
 *          activebuildlibdir="${subproject.lib.dir}"
 *          releaselibdir="${release.dir}">
 *           <subproject
 *               category="${internal.core.category}"
 *               desiredversion="${internal.core.desiredversion}"/>
 *           <subproject
 *               category="${internal.db.category}"
 *               desiredversion="${internal.db.desiredversion}"/>
 *      </findsubprojects>
 *      </target>

Please let me know if you, the reader, are interested in more.  (If you post back to the mailing
list, please send me an email as anything from the ant-dev mailing list is automatically shuttled
to its own directory and only occasionally read.)

James Carpenter

To unsubscribe, e-mail:
For additional commands, e-mail:

View raw message