In regards to a rant about ApacheAnt being sub-optimal, StevenNewton had the following to say:
See AntTheDefinitiveGuide for why it is the way it is.
This is all fine and good, and I understand the concept of depends and all, but what if subprojectN is only there under certain conditions? Our system had about 15 "modules" which may, or may not be checked out (in fact, it's highly likely that only 2 at a time would be in a developers environment). What is the Ant Way (tm)? Conditional execution based on the presence of the subproject?
The <available> task (or the <condition> task for more recent versions), combined with property checking in the target should do this for you.
<available file="./subprojectAdir" type="dir" property="subprojectA.present"/> <target name="all" depends="build-project-A"/> <target name="build-project-A" if="subprojectA.present"/>In a real world example:
<available file="/enCommerce/getAccess/bin/AccLic.dll" property="getaccess.available"/> <target name="test" depends="compile" description="run unit tests"> <mkdir dir="${junit.results}"/> <junit fork="true" dir="${basedir}" printsummary="true"> <classpath refid="test.path"/> <formatter type="xml"/> <batchtest todir="${junit.results}"> <fileset dir="${builddir}/classes"> <exclude name="**/security/jndi/tests/*.class" unless="getaccess.enabled"/> <exclude name="**/security/tests/*SOAP*.class" unless="getaccess.enabled"/> <exclude name="**/security/tests/GetAccess?*.class" unless="getaccess.enabled"/> </fileset> </batchtest> </junit> </target>
Thanks for the fine example! Unfortunately, I can't see how it fixes the nastiness of having to keep a list of modules hanging around, which you can't iterate over. Instead, one is required to write out an "available" property for each project. Am I missing something obvious here?
ex:
<available file="./subprojectBdir" type="dir" property="subprojectB.present"/> <available file="./subprojectCdir" type="dir" property="subprojectC.present"/> <available file="./subprojectDdir" type="dir" property="subprojectD.present"/> <available file="./subprojectEdir" type="dir" property="subprojectE.present"/>Each of which would require a corresponding target invoked conditionally later on as well. Is looping so evil in comparison?
If you need to do this, you can always write a custom task to do it. The NetBeans project has (had?) a task to do exactly that; given a list of modules, go away and build them. The custom task option is a damn sight cleaner than the JavaScript option. This is why the decision to put scripting into Ant was a very controversial one on the list (you could do anything you wanted to in a custom task, after all...).
So I guess that the Ant Way stipulates that we write special Java code to create custom tasks for each and every ant-based project that requires any sort of iterative or conditional build recipes that we don't want to be byzantinely (is that a word?) complex in our antfiles. And if, during the course of our project, packages are moved, deleted, or added, it could then be necessary to code, compile, install, and debug new versions of these Java-based custom tasks to accommodate these changes. And since many of these custom tasks are going to be extremely similar to other such tasks that people are writing for other projects, there is going to be a worldwide duplication of effort to write, compile, install, and debug these nearly (or totally) identical tasks. And we have all this extra time and duplicated effort simply for the purpose of maintaining the Ant Way.
The ant-contrib package is an example of some custom tasks that were written to be simple and generic, and which can be used to alleviate the need for spending valuable time "reinventing the wheel" by writing custom Java code every time a complex conditional or an iteration might be necessary to build some software. Sure, ant-contrib and others of its ilk indeed deviate from the Ant Way. But few companies want to spend time and money simply to adhere to an abstract ideal (such as the Ant Way or Pure Declarative Programming) that contributes nothing but added time and maintenance costs to their software development efforts.
I say that the following two things can and should happily exist side by side:
See also: AntUsageTask