You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by Stefano Mazzocchi <st...@apache.org> on 1999/11/26 17:07:47 UTC

Still playing around with Ant

Hi guys,

other random comments on top of my head (sorry, but I don't have time to
implement them)

1) the Task interface should have methods that return basic information
on what the task does. Something like apache modules that expose their
behavior as well as their configurations.

Something like

public class Echo implements Task {
  String getHelp() {
    return "ouputs the given string to STDOUT";
  }
}

so that you can do 

  ant --help

and you get a list of supported tasks. Then

  ant --help echo

and you get the help for the echo task, right there.

You could do this also for attributes

  String getxxxHelp()

(if present) returns a help message for the "xxx" attribute, as well as

  String getxxxDefault() 

(if present) returns the default value for the "xxx" attribute.






2) Taks is an abstract class. Following the "polymorphic" design
pattern, we should have

 public interface Task

which includes the method definitions only, then

 public abstract class AbstractTask

which includes the methods shared between all tasks, then
 
 public abstract class FileTask

which includes all the common utility methods for file tasks (like are
today contained into Task.java), and you can have a bunch of abstract
classes for common tasks, that may be abstract or not, depending if they
are usable or not

 public class Exec extends AbstractTask

and

 public class Cvs extends Exec

while

 public class Copydir extends FileTask





3) Task.java should contain a method 

 setLog(PrintWriter log, boolean useXML)

to indicate where the class should place logs and if the XML syntax
should be used. The task should be guaranteed this method is _always_
called before any execution.



4) I don't like Jon's <keysubst> usage. I do consider it vital to have a
task that performs token substitutions, but I'd like to propose
something a little different. Consider something like this

<keysubst src="try.java" dest="try.new.java" 
   setKeys="version=$(version)*name=$(name)*debug=$(debug)"/>

it performs both a copy and a substitution, which is IMO no good.

I would like to be able to do

 <copydir src="src" dest="$(build.src)"/>
 <replace file="$(build.src)/Main.java" token="@version@"
value="$(version)"/>
 <replace file="$(build.src)/Main.java" token="@name@" value="$(name)"/>
 <replace file="$(build.src)/Main.java" token="@debug@"
value="$(debug)"/>
 <javac srcdir="${build.src}" destdir="${build.dest}" debug="${debug}"/>

and doing this with keysubst is much more verbose globally, even if it
encodes all the keys into one line.

The behavior is different, this is true, and much slower, granted, but
I'd like to have a task for copying the files and another for updating
them. keysubst is modeled out of the "sed" pattern, which is really
powerful, but IMO a pain in the ass to read (and to manage!) and works
well in pipes, that we don't have here.

Comments?

-- 
Stefano Mazzocchi      One must still have chaos in oneself to be
                          able to give birth to a dancing star.
<st...@apache.org>                             Friedrich Nietzsche



Re: Still playing around with Ant

Posted by Stefano Mazzocchi <st...@apache.org>.
jon * wrote:
> 
> on 11/26/99 8:07 AM, Stefano Mazzocchi <st...@apache.org> wrote:
> 
> > Hi guys,
> >
> > other random comments on top of my head (sorry, but I don't have time to
> > implement them)
> 
> oh great...make everyone else do your dirty work. ;-)

was it so evident? ;)

> > 1) the Task interface should have methods that return basic information
> > on what the task does. Something like apache modules that expose their
> > behavior as well as their configurations.
> 
> good idea. maybe next week i will look into doing this. although, just plain
> old documentation is a MUCH higher priority imho. ;-)

True.

Another idea is to have something like

  String getDTD()

where eash task returns a DTD fragment that Ant could use to generate a
validation schema for the build.xml file, but this is would have _way_
low priority.
 
> > 2) Taks is an abstract class. Following the "polymorphic" design
> > pattern, we should have
> 
> i agree fully. Ant definitely wasn't designed with OO in mind first. ;-) As
> I said earlier, it is a great 1.0. ;-) 2.0 needs to have some better OO
> design...not just with Tasks. I guess one could say this about Apache JServ
> 1.0 as well.

Actually it's not that bad. Add just a few interfaces/abstract-class
separations, a higher level XML parser abstraction and you're pretty
much done.
 
> > 3) Task.java should contain a method
> >
> > setLog(PrintWriter log, boolean useXML)
> >
> > to indicate where the class should place logs and if the XML syntax
> > should be used. The task should be guaranteed this method is _always_
> > called before any execution.
> 
> Good idea. Also, we need to have logging be consistent throughout the
> application...rightnow, it is a bad combo of project.log and
> system.out.println(). ;-(

Yes, this is why Task.java should have a common logging system, I would
also like to add something like "debug level" so that you can request
log levels syslogd-style to reduce verbosity.
 
> > 4) I don't like Jon's <keysubst> usage.
> 
> biteme. ;-)

Sure, in the ass :)
 
> > I do consider it vital to have a
> > task that performs token substitutions, but I'd like to propose
> > something a little different. Consider something like this
> >
> > <keysubst src="try.java" dest="try.new.java"
> > setKeys="version=$(version)*name=$(name)*debug=$(debug)"/>
> >
> > it performs both a copy and a substitution, which is IMO no good.
> 
> It kinda has to. You can't do a replacement on an existing file (in place)
> without destroying it first. Since this could be a bad thing (what if there
> was an error during the destroy process?), the best way imho, is to copy/sub
> at the same time. Note that this is how autoconf works and that is how I
> modeled it. (ie: .in files).

Sure. <replace src="file.java" .../> has this pseudo code

 file.java -(filter)-> file.java.temp
 if (error) remove file.java.temp
 else remove file.java and rename file.java.temp as file.java

this is what I had in mind, which, true might follow the same pattern,
but allows you to forget about _how_ replacement is done (which is
something I don't care nor I should)

> > I would like to be able to do
> >
> > <copydir src="src" dest="$(build.src)"/>
> > <replace file="$(build.src)/Main.java" token="@version@"
> > value="$(version)"/>
> > <replace file="$(build.src)/Main.java" token="@name@" value="$(name)"/>
> > <replace file="$(build.src)/Main.java" token="@debug@"
> > value="$(debug)"/>
> > <javac srcdir="${build.src}" destdir="${build.dest}" debug="${debug}"/>
> >
> > and doing this with keysubst is much more verbose globally, even if it
> > encodes all the keys into one line.
> 
> Yes, but that isn't how Ant works at all. The above would cause <replace> to
> be called 3 times. 

No. If you do a bunch of <copyfile> for those who don't want to be
"filtered" you do the same thing.

> On top of it, it would do the replacements on the file
> Mail.java and you would be screwed (ie: loose data) if there was an error
> that prevented the new copy of Main.java to be written. Also, what if there
> is an error with the substitution?

See pseudocode above.
 
> Also, I don't like the idea of passing in the entire token. While it gives
> more flexibility towards what tokens get replaced, it encourages a pluthera
> of potentially bad tokens.

It's up to you to come up with the tokens you like. Why should you force
the tokens to be <token>variable<token>? what if I already have a build
system that uses "&^%$variable"? Do you really gain that much
readability by hiding/forcing the token encoding method?
 
> > The behavior is different, this is true, and much slower, granted, but
> > I'd like to have a task for copying the files and another for updating
> > them. keysubst is modeled out of the "sed" pattern, which is really
> > powerful, but IMO a pain in the ass to read (and to manage!) and works
> > well in pipes, that we don't have here.
> 
> No, it isn't based on sed, it is based on how autoconf does things. While
> autoconf isn't the best thing in the world, I do like some of the design
> ideas.

Ok.
 
> I guess my feeling is that I do like how keysubst works because it solved my
> problems. One thing I also really like about Ant is the fact that it is
> moduler. So, if you don't like it, come up with your own replacements. I'm
> not forcing you to use keysubst. ;-)

Totally true. But at least in the main distribution, I would like to
remove task functionality overlapping to remove the tons of "do I use
this or that? why do you have both?" type of questions. I'm sure you get
my point.

So, no, don't want to fight at all over this. It does the job and I love
it, but you know how picky I am... it's my "pain-in-the-ass" nature :)

Stefano.



Re: Still playing around with Ant

Posted by Stefano Mazzocchi <st...@apache.org>.
James Duncan Davidson wrote:
> 
> jon * wrote:
> > > 1) the Task interface should have methods that return basic information
> > > on what the task does. Something like apache modules that expose their
> > > behavior as well as their configurations.
> >
> > good idea. maybe next week i will look into doing this. although, just plain
> > old documentation is a MUCH higher priority imho. ;-)
> 
> Yep. Documentation is a big item to address asap.
> 
> > > 2) Taks is an abstract class. Following the "polymorphic" design
> > > pattern, we should have
> >
> > i agree fully. Ant definitely wasn't designed with OO in mind first. ;-) As
> > I said earlier, it is a great 1.0. ;-) 2.0 needs to have some better OO
> > design...not just with Tasks. I guess one could say this about Apache JServ
> > 1.0 as well.
> 
> Actually I left it as an abstract class on purpose. The reason why is
> that I wasn't settled on exactly how the signatures should be and it's
> much easier to maintain compatibility with subtypes if you are modifying
> an Abstract Class rather than an Interface. Once you distribute an
> interface that people might rely upon outside of your code base, you
> really shouldn't ever tweak it again as to do so creates nasty
> versioning problems. Once it's happy, then the interface can be
> promoted.

Very nice point. Very wise practice. Don't you just love it when you
come across new design patterns :)
 
> > > 3) Task.java should contain a method
> > >
> > > setLog(PrintWriter log, boolean useXML)
> > >
> > > to indicate where the class should place logs and if the XML syntax
> > > should be used. The task should be guaranteed this method is _always_
> > > called before any execution.
> 
> I don't like the task knowing that the logging should be in XML terms.
> The task should be able to write without caring and the end result log
> is xml'ized.

Good point. But how do you do it?
 
> > Good idea. Also, we need to have logging be consistent throughout the
> > application...rightnow, it is a bad combo of project.log and
> > system.out.println(). ;-(
> 
> Also, I don't see a substantial difference between calling
> 
>         project.log("foo");
> 
>         and
> 
>         task.setLog(log);
>         log.write("foo");
> 
> I agree that all the System.out.printlns need to go though :)

This is the point. I don't care either how this is done.
 
> > > <keysubst src="try.java" dest="try.new.java"
> > > setKeys="version=$(version)*name=$(name)*debug=$(debug)"/>
> > >
> > > it performs both a copy and a substitution, which is IMO no good.
> >
> > It kinda has to. You can't do a replacement on an existing file (in place)
> > without destroying it first. Since this could be a bad thing (what if there
> > was an error during the destroy process?), the best way imho, is to copy/sub
> > at the same time. Note that this is how autoconf works and that is how I
> > modeled it. (ie: .in files).
> 
> I like jon's process as well as my preference is to leave files in the
> workspace "pristine" except for edits. And, given that you've got to
> copy the file over, it's a good time to do the substitutions.

Right. <replace> should not change the original files but a copy of it.

Anyway...

-- 
Stefano Mazzocchi      One must still have chaos in oneself to be
                          able to give birth to a dancing star.
<st...@apache.org>                             Friedrich Nietzsche



Re: Still playing around with Ant

Posted by Stefano Mazzocchi <st...@apache.org>.
James Duncan Davidson wrote:
> 
> jon * wrote:
> > > 1) the Task interface should have methods that return basic information
> > > on what the task does. Something like apache modules that expose their
> > > behavior as well as their configurations.
> >
> > good idea. maybe next week i will look into doing this. although, just plain
> > old documentation is a MUCH higher priority imho. ;-)
> 
> Yep. Documentation is a big item to address asap.
> 
> > > 2) Taks is an abstract class. Following the "polymorphic" design
> > > pattern, we should have
> >
> > i agree fully. Ant definitely wasn't designed with OO in mind first. ;-) As
> > I said earlier, it is a great 1.0. ;-) 2.0 needs to have some better OO
> > design...not just with Tasks. I guess one could say this about Apache JServ
> > 1.0 as well.
> 
> Actually I left it as an abstract class on purpose. The reason why is
> that I wasn't settled on exactly how the signatures should be and it's
> much easier to maintain compatibility with subtypes if you are modifying
> an Abstract Class rather than an Interface. Once you distribute an
> interface that people might rely upon outside of your code base, you
> really shouldn't ever tweak it again as to do so creates nasty
> versioning problems. Once it's happy, then the interface can be
> promoted.

Very nice point. Very wise practice. Don't you just love it when you
come across new design patterns :)
 
> > > 3) Task.java should contain a method
> > >
> > > setLog(PrintWriter log, boolean useXML)
> > >
> > > to indicate where the class should place logs and if the XML syntax
> > > should be used. The task should be guaranteed this method is _always_
> > > called before any execution.
> 
> I don't like the task knowing that the logging should be in XML terms.
> The task should be able to write without caring and the end result log
> is xml'ized.

Good point. But how do you do it?
 
> > Good idea. Also, we need to have logging be consistent throughout the
> > application...rightnow, it is a bad combo of project.log and
> > system.out.println(). ;-(
> 
> Also, I don't see a substantial difference between calling
> 
>         project.log("foo");
> 
>         and
> 
>         task.setLog(log);
>         log.write("foo");
> 
> I agree that all the System.out.printlns need to go though :)

This is the point. I don't care either how this is done.
 
X-Mozilla-Status: 0009ry.java" dest="try.new.java"
> > > setKeys="version=$(version)*name=$(name)*debug=$(debug)"/>
> > >
> > > it performs both a copy and a substitution, which is IMO no good.
> >
> > It kinda has to. You can't do a replacement on an existing file (in place)
> > without destroying it first. Since this could be a bad thing (what if there
> > was an error during the destroy process?), the best way imho, is to copy/sub
> > at the same time. Note that this is how autoconf works and that is how I
> > modeled it. (ie: .in files).
> 
> I like jon's process as well as my preference is to leave files in the
> workspace "pristine" except for edits. And, given that you've got to
> copy the file over, it's a good time to do the substitutions.

Right. <replace> should not change the original files but a copy of it.

Anyway...

-- 
Stefano Mazzocchi      One must still have chaos in oneself to be
                          able to give birth to a dancing star.
<st...@apache.org>                             Friedrich Nietzsche



Re: Still playing around with Ant

Posted by Glenn Vanderburg <gv...@delphis.com>.
James Duncan Davidson <ja...@eng.sun.com> writes:
>
> I don't like the task knowing that the logging should be in XML terms.
> The task should be able to write without caring and the end result log
> is xml'ized.

Agreed.

> Also, I don't see a substantial difference between calling
> 
> 	project.log("foo");
> 	
> 	and
> 
> 	task.setLog(log);
> 	log.write("foo");

I do.  The first is better in every way.  :-)

When you have knowledge that a bunch of objects seem to need, it's
always better to wrap that up in a method that they all call (so that
only one object needs to know) than to try to go around telling
everyone.  The project.log solution hides several pieces of
information about logging in the project:

  - the log syntax
  - the destination of log messages
  - the fact that logging is done via a Writer

This is all good.  Those things are all attributes (using the plain
ol' English meaning of "attributes") of the project, not of each
individual task.  And hiding that knowledge in one place buys lots of
flexibility later (we could add a new log syntax, do replicated
logging, or log to a database (or some preexisting network logging
facility) rather than a file, for example).

I wouldn't mind seeing an optional logLevel parameter, although that
might be overkill for an application like Ant.

-- 
Glenn Vanderburg
Delphi Consultants, LLC
glv@delphis.com


Re: Still playing around with Ant

Posted by James Duncan Davidson <ja...@eng.sun.com>.
jon * wrote:
> > 1) the Task interface should have methods that return basic information
> > on what the task does. Something like apache modules that expose their
> > behavior as well as their configurations.
> 
> good idea. maybe next week i will look into doing this. although, just plain
> old documentation is a MUCH higher priority imho. ;-)

Yep. Documentation is a big item to address asap.

> > 2) Taks is an abstract class. Following the "polymorphic" design
> > pattern, we should have
> 
> i agree fully. Ant definitely wasn't designed with OO in mind first. ;-) As
> I said earlier, it is a great 1.0. ;-) 2.0 needs to have some better OO
> design...not just with Tasks. I guess one could say this about Apache JServ
> 1.0 as well.

Actually I left it as an abstract class on purpose. The reason why is
that I wasn't settled on exactly how the signatures should be and it's
much easier to maintain compatibility with subtypes if you are modifying
an Abstract Class rather than an Interface. Once you distribute an
interface that people might rely upon outside of your code base, you
really shouldn't ever tweak it again as to do so creates nasty
versioning problems. Once it's happy, then the interface can be
promoted.

> > 3) Task.java should contain a method
> >
> > setLog(PrintWriter log, boolean useXML)
> >
> > to indicate where the class should place logs and if the XML syntax
> > should be used. The task should be guaranteed this method is _always_
> > called before any execution.

I don't like the task knowing that the logging should be in XML terms.
The task should be able to write without caring and the end result log
is xml'ized.

> Good idea. Also, we need to have logging be consistent throughout the
> application...rightnow, it is a bad combo of project.log and
> system.out.println(). ;-(

Also, I don't see a substantial difference between calling

	project.log("foo");
	
	and

	task.setLog(log);
	log.write("foo");

I agree that all the System.out.printlns need to go though :)

> > <keysubst src="try.java" dest="try.new.java"
> > setKeys="version=$(version)*name=$(name)*debug=$(debug)"/>
> >
> > it performs both a copy and a substitution, which is IMO no good.
> 
> It kinda has to. You can't do a replacement on an existing file (in place)
> without destroying it first. Since this could be a bad thing (what if there
> was an error during the destroy process?), the best way imho, is to copy/sub
> at the same time. Note that this is how autoconf works and that is how I
> modeled it. (ie: .in files).

I like jon's process as well as my preference is to leave files in the
workspace "pristine" except for edits. And, given that you've got to
copy the file over, it's a good time to do the substitutions.

.duncan

-- 
James Davidson                                     duncan@eng.sun.com 
Java + XML / Portable Code + Portable Data                 !try; do()



Re: Still playing around with Ant

Posted by jon * <jo...@clearink.com>.
on 11/26/99 8:07 AM, Stefano Mazzocchi <st...@apache.org> wrote:

> Hi guys,
> 
> other random comments on top of my head (sorry, but I don't have time to
> implement them)

oh great...make everyone else do your dirty work. ;-)

> 1) the Task interface should have methods that return basic information
> on what the task does. Something like apache modules that expose their
> behavior as well as their configurations.

good idea. maybe next week i will look into doing this. although, just plain
old documentation is a MUCH higher priority imho. ;-)

> 2) Taks is an abstract class. Following the "polymorphic" design
> pattern, we should have

i agree fully. Ant definitely wasn't designed with OO in mind first. ;-) As
I said earlier, it is a great 1.0. ;-) 2.0 needs to have some better OO
design...not just with Tasks. I guess one could say this about Apache JServ
1.0 as well.

> 3) Task.java should contain a method
> 
> setLog(PrintWriter log, boolean useXML)
> 
> to indicate where the class should place logs and if the XML syntax
> should be used. The task should be guaranteed this method is _always_
> called before any execution.

Good idea. Also, we need to have logging be consistent throughout the
application...rightnow, it is a bad combo of project.log and
system.out.println(). ;-(

> 4) I don't like Jon's <keysubst> usage.

biteme. ;-)

> I do consider it vital to have a
> task that performs token substitutions, but I'd like to propose
> something a little different. Consider something like this
> 
> <keysubst src="try.java" dest="try.new.java"
> setKeys="version=$(version)*name=$(name)*debug=$(debug)"/>
> 
> it performs both a copy and a substitution, which is IMO no good.

It kinda has to. You can't do a replacement on an existing file (in place)
without destroying it first. Since this could be a bad thing (what if there
was an error during the destroy process?), the best way imho, is to copy/sub
at the same time. Note that this is how autoconf works and that is how I
modeled it. (ie: .in files).

> I would like to be able to do
> 
> <copydir src="src" dest="$(build.src)"/>
> <replace file="$(build.src)/Main.java" token="@version@"
> value="$(version)"/>
> <replace file="$(build.src)/Main.java" token="@name@" value="$(name)"/>
> <replace file="$(build.src)/Main.java" token="@debug@"
> value="$(debug)"/>
> <javac srcdir="${build.src}" destdir="${build.dest}" debug="${debug}"/>
> 
> and doing this with keysubst is much more verbose globally, even if it
> encodes all the keys into one line.

Yes, but that isn't how Ant works at all. The above would cause <replace> to
be called 3 times. On top of it, it would do the replacements on the file
Mail.java and you would be screwed (ie: loose data) if there was an error
that prevented the new copy of Main.java to be written. Also, what if there
is an error with the substitution?

Also, I don't like the idea of passing in the entire token. While it gives
more flexibility towards what tokens get replaced, it encourages a pluthera
of potentially bad tokens.

> The behavior is different, this is true, and much slower, granted, but
> I'd like to have a task for copying the files and another for updating
> them. keysubst is modeled out of the "sed" pattern, which is really
> powerful, but IMO a pain in the ass to read (and to manage!) and works
> well in pipes, that we don't have here.

No, it isn't based on sed, it is based on how autoconf does things. While
autoconf isn't the best thing in the world, I do like some of the design
ideas.

I guess my feeling is that I do like how keysubst works because it solved my
problems. One thing I also really like about Ant is the fact that it is
moduler. So, if you don't like it, come up with your own replacements. I'm
not forcing you to use keysubst. ;-)

-jon