it's not just you. Ant tends to be a pain in the butt if you have to do a lot of scripting (ok, almost any scripting) work in your build system. If your build system consists of essentially a batch execution of a linear path of steps, Ant works great. As soon as you have to have some indeterminate information that is discovered during the build (like having to repeat tasks or loop over lists, etc.) Ant becomes difficult to fit in.

I often end up writing shell scripts that do work and calling them from Ant or using the ant-contrib libs which make a HUGE ease-of-use improvment (looping !!). I also wrote a recursive property handler as that is a definate ease-of-use improvment... though I hear that may be built into a future version of Ant?

Anyway, no build tool is the be-all-and-end-all, if your builds requires a lot of scripting, another tool may benefit you more than Ant.

Richard Russell wrote:
Hi all,

Firstly, please excuse the crufty formatting of this email -- my employer
makes me use Notes. If people would prefer, I can paste this into a public
Twiki somewhere... Just let me know the general preference.

Secondly, I'm hoping that this email does not come across overly critical
or negative -- I'm not having a go at ant, I honestly just want to get my
head around these problems better.

Finally, thanks for your patience if you manage to read the whole email. I
wanted to keep it short, but decided that the length was necessary to
illustrate the problem that I've been having. Those interested, but
pressed for time could just read the first part, up to the example...


OK, now to the actual content:

I'm having ongoing problems getting along with Ant. I keep wanting to do
things that it appears that Ant can't do, despite trying to use what I
would consider fairly basic constructs. I run into these issues so
regularly that I cannot help but assume that I am simply not 'thinking in
Ant', and am therefore fighting against its design rather than working
with it. I occasionally come across snippets of documentation that seem to
confirm this. Specific examples of things I keep butting my head against
include:

properties being "immutable" (except in some cases -- see propertycopy)
not being able to double-dereference properties (eg ${${propertyname}}),
or use arrays (not comma-separated lists -- indexable arrays)
lack of 'if', 'for' and similar logic constructs (yes, I am aware of
ant-contrib, but much documentation seems to indicate that this is a
concession rather than an ideal)
inflexibility of certain tasks/containers etc -- eg below, I want to set
up a bunch of filters, and would like to use a construct like this within
a loop:

                <filterchain id="${filtername}">
                        <replacetokens>
                                <for param="propertyname"
list="parameterlist">
                                        <propertycopy name="propertyvalue"
from="[EMAIL PROTECTED]"/>
                                        <token key="@{propertyname}"
value="${propertyvalue}"/>
                                </for>
                        </replacetokens>
                </filterchain>

As you can see, this illustrates a couple of my problems -- I'm using
propertycopy to get around the lack of double-dereferencing, and also
taking advantage of the way propertycopy can mutate values of "immutable"
properties. Then, I'm using a for loop (which requires mutable properties)
to set up multiple tokens in the replacetokens filter (actually, I can't
do this, as replacetokens doesn't support the nested 'for' element).
Another example of this is the (to my mind) strange duplication between
filterchains and filtersets. They seem to do basically the same thing, but
in different places and with different limitations.

My frustration here is because Ant isn't procedural. Or perhaps it's
because I think of my build process in a procedural manner (hence why I
call it a build *process* and not a build *declaration*). Perhaps this is
because I've always used make, but I'm not sure how else to think about
it, at least at the low level. Eventually, I have battled through, and
have created new tasks, macros, or used other people's libraries to make
it all happen, but no matter what, it all takes so long, and I don't see
life getting much better as I grow in familiarity with it.

------------------------------------------------

Here's a longer example of something that I would normally consider
simple. I want to append each of the files in one directory to the
same-named file in another directory, filtering some tokens as I go. It's
possibly expressed simplest as a shell script:

----
for file in `ls ${dir1}/*.DAT`; do
  cat ${dir1}/${file} | sed -e 's/@parameter@/value/' >> ${dir2}/${file}
done
----

As an aside, I wrote that particular line in about two minutes, including
fixing the one error I made in the sed script (I missed the trailing /).
Obviously, there would be more sed parts for the different tokens, and
it's not exactly an elegant solution. But the point is that it took me two
minutes, didn't require me consulting any API documentation, and doesn't
require compilation. I'm sure there's more elegant, perhaps easier ways of
doing it, in Perl, or even still in shell, but this is just a trivial
example.

Now, to do the same in Ant, I first tried to combine the for and concat
tasks, with a filter, in the obvious (to me) manner. For various reasons
this wouldn't work -- mostly to do with immutable properties, and not
being able to separate the filename from the directoryname in a fileset
and so on. If anyone knows of a way to replicate this functionality
without writing a new Task, let me know.  As it was, I had to create the
following Task:

----
package mypackage;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.FileList;
import org.apache.tools.ant.taskdefs.Concat;

import java.io.File;


public class AppendCopy extends Concat { private String destDir=null; private File srcFile=null;

        public void execute() throws BuildException
        {
                if (destDir==null)
                        throw new BuildException("AppendCopy: destdir
attribute not set");
                if (srcFile==null)
                        throw new BuildException("AppendCopy: srcfile
attribute not set");
                try
                {
                        File destinationFile=new
File(destDir+System.getProperty("file.separator")+srcFile.getName());
                        super.setDestfile(destinationFile);
                        FileSet sourceFileSet=new FileSet();
                        sourceFileSet.setFile(srcFile);
                        super.addFileset(sourceFileSet);
                        super.setAppend(true);
                        super.execute();
                }
                catch (Exception exception)
                {
                        throw new BuildException("AppendCopy: something
went wrong\n" + exception);
                }
        }

        public String toString() {
                return
super.toString()+"\ntoDir="+destDir+"\nfromFile="+srcFile+"\n";
        }

        public void setDestdir(String string)
        {
                destDir=string;
        }

        public void setSrcfile(File file)
        {
                srcFile=file;
        }

        public void setDestfile(File destinationFile) throws
BuildException {
                throw new BuildException("AppendCopy: destFile attribute
disallowed");
        }

        public void setAppend(boolean append) throws BuildException {
                throw new BuildException("AppendCopy: Append attribute
disallowed");
        }

        public void addFileset(FileSet set) throws BuildException {
                throw new BuildException("AppendCopy: Nested FileSet
element disallowed");
        }

        public void addFilelist(FileList list) throws BuildException {
                throw new BuildException("AppendCopy: Nested FileList
element disallowed");
        }
}
----

And then, I use it in my build.xml like this:

----
<taskdef name="appendcopy" classname="mypackage.AppendCopy"/>
...
<for param="filename">
        <fileset dir="${dir1}/" includes="*.DAT"/>
        <sequential>
                <appendcopy srcfile="@{filename}" destdir="${dir2}"
fixlastline="true">
                        <filterchain refid="myfilter"/>
                </appendcopy>
        </sequential>
</for>
----

Plus, of course, the setting up of the filterchain "myfilter".

Now, when I look at the result, it's far from elegant, and without knowing
what appendcopy really did, I would be hard pressed to understand what the
ant snippet did. I could remove the for loop, and create a task that did
the whole operation, and was called like this:

----
<appendcopydirectory todir="${dir2}">
        <fileset dir="${dir1}/" includes="*.DAT"/>
        <filterchain refid="myfilter"/>
</appendcopydirectory>
----

But I suspect that would be even more work. It's also (to my mind) less
clear and less re-usable (though I could name it
appendcopyeachfileinfilesettosamenamedfileintodir, but that's got its own
problems). I could subclass copy, adding an "append" attribute, but,
having read the source to Copy
(http://cvs.apache.org/viewcvs.cgi/ant/src/main/org/apache/tools/ant/taskdefs/Copy.java?rev=1.66.2.6&view=markup <http://cvs.apache.org/viewcvs.cgi/ant/src/main/org/apache/tools/ant/taskdefs/Copy.java?rev=1.66.2.6&view=markup>),


I decided that discretion was the better part of valour, and there had to
be an easier way. Note that while I can code Java, I'm not a developer,
and have no desire to become one. Certainly, I challenge even a top
developer to come up with some sort of append attribute for Copy in the
time it took me to write the equivalent shell script above.

-------------------------------------------

So, what is it that I'm doing wrong here? Why am I always battling against
Ant, and finding that the things I wish to do, things which I find simple
to express in english, in psuedocode, or in shell, are so darned complex
to do in Ant? Am I just not getting it? Am I driving in nails with a
screwdriver?


Cheers,

Richard Russell
Deutsche Bank AG London
Global Markets Customer Solutions
Office: +44 (0)20 7545 8060
Mobile: +44 (0)79 0661 2237

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


-- -- Jeffrey Bacon [EMAIL PROTECTED] Creative Developer http://www.magmic.com

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



Reply via email to