Ok, so if we are going to tighten up Ant to get to the point where it should
go, we should start off with a set of principles (or goals, or design
criteria, or whatever you want to call them) that we all agree on. It's
simple, it's basic, but maybe by starting off really basic, we can infuse
the rest of the process with a unified purpose.
Just for the curious, I'm not touching on specific tasks yet.. Most notably
I'm not going into conditional compilation, etc... That stuff comes after we
define how the framework within which conditional compilation can happen.
Design Goals (there should be no suprises here!)
Simplicity:
Ant must be simple to use and simple to extend. Of course, the
definition of simple can vary depending on which audience is chosen.
For Ant, since it is a build tool aimed at Java developers, the goal
is simplicity of use and extension for a competent Java programmer.
Understandability:
The way Ant works should be clearly understandable for a first
time as well as a veteran user. The mechanism to extend Utah must be
understandable. And the build file syntax must be eminently
understandable.
Extensibility:
Ant must provide an easy to use extensibility path. Extensions
must be easy to write for the programmer and easy to place where they
can best be used.
Conceptual Overview (here's a bit more detail, but still should be
relatively agreeable)
The base unit of work is a Project. A Project is defined by an
XML text file and as an object of type Project at runtime.
A Project is a collection of Property definitions and Targets.
Properties:
Properties are mutable name-value pairs that are scoped to the
Project and held in a List. The property list can be modified at
runtime allowing properties to be added, removed, or changed. The
property list is loaded from the XML based project file. It is useful
to be able to override the properties contained in a project file and
so optional parameters to the ant runtime can be defined to do so:
ant projectfile.xml -props foo=bar;baz=bop [target]
The current version of Ant allows the System property list to be
consulted for a return value of the Project if the property requested
doesn't exist in the Project property list. This can be considered to
be confusion, and should not be carried forward.
Yes, I'd like to see the props defined this way.. This does reserve
the ; and = chars, but I don't see a huge problem with this.
Targets:
Targets are orderded collections of Tasks, units of work to be
performed if a Target is executed. Targets can define dependancies on
other targets within the Project. If a Target is deemed to be executed,
either by direct definition on the command line, or via a dependancy
from a currently running target, then all of it's dependancies must
first be executed.
Circular dependancies are broken by examination of the dependancy
stack when a Target is evaluated. If a dependancy is already on the
stack, then the dependancy is considered to have been satisfied.
After all dependancies have been executed, the current target has
its task list examined and the tasks within that list are configured
and executed in sequential order. More accuratly, when a task is
executed, an instance of the class that defines the behavior of that
task is instantiated and then configured with the information from the
project XML file. It is then executed so that it may be able to perform
its function. It is important that this configuration happens just
before execution, and after execution of the previous task, so that any
configuration information that depends on properties can be properly
conveyed.
Tasks:
A Task is a unit of work in the project. When a task is executed,
it has access to the Project object allowing it to examine the property
list of the Project and to resolve filenames into actual File objects.
Build File Structure:
The top few levels of the build file are easy and shouldn't change much
from what we have now:
<project name="foo">
<property name="bar" value="bop"/>
<property name="far" value="out"/>
<taskdef name="joy" class="com.joy.Kill"/>
<target name="whoopie" depends="cushion">
<taskimpl ...>
...
</taskimpl>
</target>
</project>
Now, notice that I haven't talked about taskdefs above. I'm starting
to think that instead of taskdefs defined in the build.xml file, they
should be defined by something that looks an awful lot like a tag
library descriptor. See section on directory structure for more.
The other part that needs work is what happens inside the taskimpl
areas. Right now reflection is used to set attributes on bean methods
but it's heniously unclear how the best way to reflect the rest
of the elements within the taskimpl tag should be performed. For
example:
<script>
<language="somelang">
if (bar) { set-property("foo", "bar") };
</language>
</script>
Sam, you're the scripting guy, not me, but something along these
lines, along with a definition of the object model that is
exposed to the scripting environment (project/target/task +
properties) would be acceptable to me.
But, the tough part once again is reflecting this stuff in. We
need a simple, clearly defined way (just like attribs are set
using bean methods) that works the same way for every task. And
just passing in a DOM fragment doesn't cut it as far as I'm
concerned as I'd like to ensure that the XML impl doesn't
get too close to the runtime impl and vice versa. It's a data
format! :)
Installation:
Far far far too many people are inluding ant.jar with thier
software. Do people include make? No. Do people include diff?
No. So, we need to get Ant to the point where it's a first
class citizen on the user's machine. This means an install
and it means a directory structure.
I'm proposing this:
$install_dir/bin/ant.sh
/ant.bat
/lib/ant.jar
/ext
/opt/tasktype1
/tasktype2/tasktype2.xml
/src/...
The tasktype directories contain the source code for the
optional tasks, along with a project file to build them.
When they are built, they should be placed into the
/ext directory in a jar format...
$install_dir/ext/tasktype1.jar
/META-INF/taskdef.xml
The /META-INF/taskdef.xml file defines the task name and
the task class.
When ant starts, it scans the /ext dir, loads in all
tasks and makes them available to the runtime. It doesn't
do this by placing them on the classpath in the ant.sh
script, but by using JAR class loaders.
When ant is installed, a ant.xml file is placed into the
user's user.dir that defines where the ant installation
is. If this isn't present and ant is started, it should
ask the user.
File Naming Conventions (we gots to have some.. the Project object should
provide the hook to translate these into local File objects)
All tasks must be written to accept a common representation of
filenames that can be translated at runtime to a File object that is
valid for the runtime operating system. This common representation can
be translated into a File object by a convience method on the Project
object.
All directory seperators are the forward slash character ('/')
All path seperators are the colon (':')
In cases where the user must specify an absolute path on a
windows machine that starts with a drive letter, it should look like
'C:/foo/bar'
OK. That's enought for now.. It's a huge chunk to chew on. Let's hammer on
this and I'll keep a master document (and will check it into CVS) and get
wide agreement on it and then we can move into the finer details.
.duncan