--On Tuesday, September 13, 2005 1:30 PM +0200 Christoph Lofi <[EMAIL PROTECTED]>
wrote:
Well, I don't know. I think generating the build file is the easiest and least
dangerous way to go.
I also think that the debugugging problem isn't that severe as long as the
build file
generation is transparent (which is the case when using template languages like
velocity).
Hi Christoph,
I've just spent some time researching this issue. I've discovered one very
useful article:
<http://www.oracle.com/technology/pub/articles/bodewig_ant1.6.html>
In a nutshell, this article shows:
- how to use <macrodef> to simplify tasks that used to call <antcall>
- how to use <import> to simplify splitting up a large build.xml into smaller
ones.
- how to use <subant> to invoke a task that may be present in multiple
build.xml files.
There is an extremely intriguing reference at the very end of the article to an (as yet
unimplemented) task called <buildlist>, which would accept a set of build.xml files and
return a path that orders them according to their dependencies. They say this "might be
available" in a future release of Ant, but I did some searching and all I could find was
an implementation for a system called Ivy:
<http://www.jayasoft.org/node/223>
I'm pretty sure we don't want to import Ivy just to get this one task, but Ivy is open
source so its implementation is accessable and might be interesting to look at.
But Aarons Option 2 also sounds cool too me.
Determining the module build order should not be too hard (isn't that some kind
of
stupid standard graph theory problem? "serialization of a paralell tree" or
something
like that?). The implementation of that isn't not too different from the
generating
alternative (crawaling for the module definition files, checking if all
dependencies
are there and then generating eitther a build file or some kind of build order
description file.)
The first thing to note is that there is a misconception about the "generating
alternative": just like our current implementation is structured so that Ant takes care
of the dependency analysis, the generating alternative would similarly not require any
dependency analysis. It would simply use as data the various local.module.definition.xml
files, such as:
<hackystat-module>
<name>hackyFoo</name>
<available>on</available>
<dependent-modules>
<module>hackyKernel</module>
<module>hackyStdExt</module>
</dependent-modules>
</hackystat-module>
to produce (among other things) task definitions such as this doInternal_hackyFoo in the
generated build XML file:
<target name="doInternal_hackyFoo"
depends="doInternal_hackyKernel, doInternal_hackyStdExt"
if="hackyStdFoo.available">
<echo message="(${ant.project.name}) Invoking ${target} in hackyFoo." />
<fail message="hackyFoo requires module hackyKernel."
unless="hackyKernel.available" />
<fail message="hackyFoo requires module hackyStdExt."
unless="hackyStdExt.available" />
<ant dir="../hackyFoo" antfile="local.build.xml" target="${target}" />
</target>
The second thing to note is that Ant already implements a solution to the "stupid
standard graph theory problem" :-), so if we were to go down the route of implementing
our own <buildlist>, one would presumably be able to leverage the already implemented
dependency analysis code in Ant.
However, as I look more closely at the problem, I am less sanguine about the possibility
of <buildlist> solving all our problems, at least in a way that doesn't produce more
complexity rather than less.
To provide some insight into the complexity, what you need to see is that for each module
in Hackystat, there are over a dozen targets we want to implement, including: clean,
compile, checkstyle, javadoc, java2html, bcml, install, junit, cvsUpdate, cvsCommit,
cvsChangeLog, cvsDiff, and dependency. It turns out that some of these targets (like
compile) have to be written in a custom manner for each module, while other targets (such
as cvsUpdate) are written exactly the same way (modulo some property values) for each
module. Our current system solves this problem by providing "generic" implementations
for the tasks that are written the same way in the build.utils.xml file, and requiring
each module to provide its own implementation of the custom tasks in its own
local.build.xml file.
So, that's one issue that our current build system solves reasonably nicely, which is the
custom vs. generic task implementation. Overlaid on top of this is a second issue, the
module dependency issue, which involves doInternal_<module> and so forth to figure out
the order in which the generic (or custom) task for the set of modules should be invoked.
(By the way, I forgot that there's a whole other set of tasks in the build.utils.xml file
called doUtil_<module> that are there to facilitate the implementation of the generic
tasks.)
So, in summary, it seems to me that the direction that is simplest is the
following:
- remodularize our current build.xml and build.util.xml into a set of new build
files,
(1) new.build.xml
the master build.xml, which <import>'s the following build files.
(2) new.modules.build.xml
the auto-generated build file containing all tasks referring to specific modules,
including:
doUtil_<module>
doUtilAll
doInternal_<module>
doAll
checkModuleAvailability
modules
(3) new.cruisecontrol.build.xml
contains all of the cruise control related targets
(4) new.cm.build.xml
contains the CVS targets (and will be updated to SVN targets eventually)
The first goal is to successfully be able to invoke all of our current functionality
using:
ant -f new.build.xml <target>
Once we get to here, the next step is to autogenerate the contents of the
new.modules.build.xml file by reading in the individual local.module.definition.xml
files. For simplicity's sake, I would prefer to avoid introducing another huge and
complex package (i.e. velocity) if something simpler (such as Ant's built-in XSLT task)
would work epsilon-distance as well. On the other hand, a small improvement to the
built-in XSLT task like the <styler> task might be worth checking out, particularly
because it supports file merging:
<http://www.langdale.com.au/styler/>
By creating brand new files (i.e. with the "new." suffix), this allows us to work on the
revised build system in parallel with the current one, and only cut-over when we're
convinced it's working right.
So, Christoph, are you still up for fooling around with this?
Cheers,
Philip