I was wondering if anyone would bring it up...

+1 (is >1 allowed?) for including a scripting language implementation in the standard Ant distribution, so that we can rely on it being there. In fact I would suggest making Ant 2.0 assume a script as its input, and have a compatibility mode for old XML scripts.

-1 (or <-1 if allowed) on writing our own DSL.

-0 on rewriting existing tasks in the Ant distribution in another language. Would just confuse the code base. Focus on users of Ant, not developers of Ant. Of course users should be able to write tasks in a scripting language if they prefer. Ideally this would be the same thing as just writing a plain old library file.

-0.5 on Lisp or Scheme. Don't get me wrong, I probably would have been miserable as a teenager were it not for CLtLR2. But the last thing we want to do is make life harder for a random Java developer to build his or her program. Ant-in-Lisp would be far far better than the current XML mess, to be sure, but I think a relatively mainstream language like Rhino would be a lot more accessible. Lots of Java developers already know JavaScript from web development anyway. BeanShell is also an easy step for Java developers. JRuby and Jython are probably a bit more accessible than Lisp but less than JavaScript and BeanShell.

My personal experience with Ant has always been that the tasks are great, and the control flow is maddening. To write an interesting script, I generally spend most of the time wrestling with if and unless attributes, artificial targets set up to define properties at the right times, weird <pathconvert> hacks, refid->string conversions, selectors, and other gobbledygook. Generally all of this could be replaced with a few lines of elementary JavaScript or any other general-purpose language with sensible bindings and library functions.

The Ant scripts generated by NetBeans are also crippled by the lack of scripting. For example, seemingly trivial problem: given a ${classpath} which might be defined in some .properties files and which might include files from anywhere on disk, copy the JARs into a build dest dir. Now <copy> can take a fileset, but you have a path, not a fileset, and there is no root. If the number of classpath elements were fixed, you could write several <copy> tasks in sequence, but there can be any number of elements. Solution? Either (1) regenerate a build script using XSLT from some other definition file (eek!); (2) distribute a special task JAR to copy a list of files specified by path, and make sure that this JAR gets somehow referred to from every project's build script. An awful mess. And in JS? All this could be replaced with something like

for (jar in classpath.split(':;')) {copy({file: jar, todir: destdir})}

which anyone can read and understand at once. Furthermore it is trivial to see how to make a little modification to the above:

for (e in classpath.split(':;')) {
  if (e.endsWith('.jar')) copy({file: e, todir: destdir})
}

If we had scripting bindings, we could get rid of or deprecate a lot of weird task options, conditions, selectors, and so on. General rule of thumb: if your XML grammar includes elements named <and>, <or>, and <not>, you are doing something wrong. :-) Who needs to pore over the reference documentation for a date selector when you can just write e.g.

newfiles = scan(basedir, '**/*.java', function(f) {
  return f.lastModified() > ref.lastModified()
})

If targets were replaced by functions, and <import> by load(...), you could compose scripts as normal library files, without having to sweat over idiosyncratic inheritance and naming rules in the Ant manual, not to mention the confusing ways that properties and references are passed to subscripts, which does not match the semantics of any real language. Things that look like function calls would really be function calls (with parameters), lexically scoped and global identifiers would be what they appear, variables could vary.

You could just say that by default all (top-level) functions in a script are targets; if you wanted to use some library functions and expose only certain targets, just use e.g.

function build() {
  compile()
  jar()
}
function compile() {
  javac({srcdir: 'src', destdir: 'build/classes'})
}
function jar() {
  jar({basedir: 'build/classes', jarfile: 'myapp.jar'})
}
function clean() {
  delete({dir: 'build'})
}
TARGETS = [build, clean] /* build is first, so default */

If you really feel the need for infrastructure to run a given target only once (which I do not think should be the default behavior), this should be easy enough in JS:

function build() {
  once(compile)
  once(jar)
}
function compile() {...}
function jar() {
  once(compile)
  // ...
}

where once is defined to be something like this:

function once() {
  var targ = shift(arguments)
  if (!this.ran[targ]++) {
    apply(targ, arguments)
  }
}

Managing properties would also be far easier if you could be explicit about their lifecycle and precedence. E.g. if run with ant -Dx=y and build.properties containing "foo=value\nx=y2\nlocation.y=there":

print(x) // prints 'y'
var p = properties('build.properties') // load defs into map
print(p.foo) // prints 'value'
print(p.x) // prints 'y2'
add_defs(/* to */ this, /* from */ p, /* override? */ false)
print(foo) // now prints 'value'
print(x) // still prints 'y'
function sometarget(location) {...}
sometarget(this['location.' + x]) // called with 'there'
load('other.js') // defines function othertarget(defs) {...}
othertarget(p) // pass it what you loaded
othertarget(this) // pass it my own properties

I don't buy the argument that Ant is currently "declarative". It's nothing of the sort in my experience. When you think about what a build script does, it runs a sequence of actions, possibly with some control flow, and uses variables which are defined through a potentially complex series of interactions with the environment. That's a program, not a declaration. Make tried to impose a Prolog-y model onto the problem, with the result that only Prolog programmers could understand makefiles, and recursive make never really followed the model anyway. Ant is easier to understand because it works more like a sequential program, and file up-to-date handling is bundled into tasks. So why is it written in a cumbersome XML dialect which is incapable of expressing elementary computations?

-J.

--
[EMAIL PROTECTED]  x22801  netbeans.org  ant.apache.org
      http://google.com/search?q=e%5E%28pi*i%29%2B1


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

Reply via email to