ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Jason Rosenberg" <ja...@squaretrade.com>
Subject Re: Parameterized "task-function"
Date Fri, 12 Jan 2001 19:56:02 GMT

----- Original Message ----- 
From: "James Duncan Davidson" <duncan@x180.net>
To: <ant-user@jakarta.apache.org>
Sent: Friday, January 12, 2001 2:39 AM
Subject: Re: Parameterized "task-function"


> On 1/10/01 4:47 AM, "David Corbin" <david.corbin@machturtle.com> wrote:
> 
> > (That's just starters).  As was pointed out to me, ANT is a scripting
> > language.  I want function/procedures.   Is that so odd?
> 
> Whoever pointed that out to you was wrong. Ant is not a scripting language.
> It was never intended to be. If it were, I would have used JavaScript and a
> Rhino engine to do what I needed it to do. :)
> 

Ok, what is it?

To me, when first getting started, it's simplicity and elegance were absolutely clear.
It had a very nice, clean, way to specify all the procedures I wanted to do.

I could define the order that things should occur, and what should depend on
what else, etc.  I could  deal well with Java classpaths, and deal with file
copy/delete, etc., in a platform independent way.

Golden.

Then, I tried to actually build something.  The first pass was a success.
I created a build.xml to build a weblogic ejb, and copy it over to my
distribution root, etc.

But then I ran into problems.  I didn't want to have to manually copy this
build.xml file into each of my ejb module directories, and then locally
modify each one with the specific names to include for each module, etc.

I have 50 different ejb projects.  There is a complex dependency graph
for the order in which these can and should be built.

Sadly, Ant provided no way to make it such that I only even attempt
to build each ejb once.  The 'depends' attribute began breaking down,
because the only way to use lots of individual project build.xml files
was to use the <ant> and sometimes the <antcall> tasks.  These tasks
cause a whole new sub-project, which completely subvert the whole
'depends' DAG implementation.

It also became a nightmare maintaining all the individual scripts in each
module, especially when I wanted to modify the basic structure of
the build scripts, I would have to go in and do the same mod to a
large number of files.

I experimented quite a bit with using the <!ENTITY> xml tag, as a
way of loading in reusable code as a sort of "include" mechanism.
Still, I had the problem of having to go and modify the <!ENTITY>
tags in a large number of build.xml files each time I want to
change things around.

I toyed with the idea of trying to do a sort of buildscript generator,
the idea being that if these are all ejb projects, then I should be able
to just do a buildscript pre-compile to generate all the build.xml's
based on a set of rigid assumptions about naming and conventions
with regards to how each module is set up.  Alas, I ran into the problem
that these ejb's were written by a large team of developers, and the
rules about how different files are named is not consistent, etc., and
so the job of doing this became intractable.  I looked at doing XSLT
and also at just doing another Ant buildscript that would do this
generation.  The problem is that you have make lots of rigid assumptions
about the form of the code you are trying create a buildscript for,
otherwise you end up handling each module as a special case.  Which
is just doubling the work.  Why not break things down into just a few
configurable parameters that are sufficient for describing a module
type, and then have a single build that runs them.

If we were to go the pre-compile build script route, then you would
still end up with lots of individual, self-contained build scripts which
at run time don't have a way of communicating with other modules, etc.

So, finally, I went the scripting route using javascript, via the <script>
tag.  Now, I have only one build.xml file, which basically takes
care of global init tasks, and then performs builds based on
command line inputs, and loaded in property files which describe
the modules to work on.

The build.xml file includes lots of targets which have only stub tasks
in them.  That is, they contain tasks which have an 'id' attribute, but
with nothing else.  This allows them to be exposed for manipulation
via javascript code.  I can then do things like re-configure the
task multiple times for each usage, etc.  I can then call the target via
'target.execute()'.

By using the builtin and optional tasks included with Ant, it is very
easy to create these build tasks via javascript, and I can be confident
the whole thing will work equally under NT and Solaris.

In some cases, it was necessary via javascript to create new instances
of tasks, via the project.createTask() method, because, like properties,
many of the Ant tasks don't have resettable data attributes.  So, I had
to create local javac task variables, because each time you call the
setFileSet method on a javac task, it ends up being a cummulative
event, which I don't want, if I am trying to reuse the object.  So,
in many cases I ended up calling the execute method on the task
objects and not the target objects.

In some cases, these stub targets still take advantage of the depends
attribute, in order to have aggregated, canned tasks which always
occur as a sequence.

The scripting route also afforded me to have resettable properties,
which is something you can't do in Ant1.2, since I can call
directly the setUserProperty and getUserProperty methods. 

I then began keeping
track of my own '<moduleName>.alreadyProcessed' properties,
so that I could keep track of dependencies and whether a module
has already been completed, and for detecting circular dependencies.

Is this elegant?  Not really.  I am accessing all kinds of internal
Ant code, some of which may be changed in future releases.

But, I think this was the purpose of the <script> task.  If people
really want to do scripting, then they should feel free to do
so using the <script> task, and in the process have all sorts of
internal Ant java code readily accessible.  At least this is suggestion
that I heard repeatedly on these airwaves, which guided my
progress on this.

This is a very dangerous precedent, though, since by having the
<script> task, you are inviting lots of backwards compatibility
complaints in the future.

So, is this my perfect world?  No.

What I would want is that I be able to do everything I did without having
to resort to the <script> task.  The simple pieces that I would need:

1. resettable property values.

2. direct calling of targets, e.g. <call-target> (not antcall!),
    with parameterized arguments passed to the target.

3. tasks then, need to be dynamically reusable and reconfigurable,
    so that when they are traversed as part of call-target, they
    represent fresh instantiations of the task, so that new filesets,
    etc., can be attached to them.

4. more functional boolean logic conditions, with the ability to
    call a target directly based on the evaluation.  And I am
    in favor of the boolean logic being expressed in an xml
    like structure, instead of cryptic C like expressions.  Need
    else functionality too, and possibly case, etc.

5. ability to conditionally gate execution of a target before 
    evaluating dependencies, as well as after.  Currently,
    you can only do so after, using  the if/unless syntax.

6. simple iteration loops, i'd be happy only with a while loop,
    which could be implemented very easily (it is essentially
    a simple goto back to start on condition construct).

7. improved logging, don't need every target visited reported
    to the output, etc.  Perhaps just need a -antsilent flag,
    which suppresses all but explicitly defined task specific output, etc.

The bottom line.  Ant is and should be a scripting language.  When
you try to say it isn't, you force people down the <script> route,
as the only recourse, which is nothing but a can of worms.

You are trying to say that Ant is just a language for declaring
a bunch of build data.

But what happens when you do:

'java org.apache.tools.ant.Main' ?

Now you are executing a program, which interprets the build
data.  The build data serves as an input script which is interpreted
by 'java.org.apache.tools.ant.Main'.  This can't be denied.

The build.xml file, therefore, is a directive oriented language
that is absolutely nothing but interpreted.  It is a description
for performing a specific action.  

IT IS A SCRIPT.

Jason

p.s. forgive me for cross-posting this to ant-dev, but it clearly
has its primary audience over there....
    











Mime
View raw message