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]